diff --git a/lib/Transforms/Scalar/SROA.cpp b/lib/Transforms/Scalar/SROA.cpp index 80fbbeb6829b..e63ee2195a8a 100644 --- a/lib/Transforms/Scalar/SROA.cpp +++ b/lib/Transforms/Scalar/SROA.cpp @@ -2402,9 +2402,20 @@ class llvm::sroa::AllocaSliceRewriter if (LI.isVolatile()) NewLI->setAtomic(LI.getOrdering(), LI.getSynchScope()); + // Any !nonnull metadata or !range metadata on the old load is also valid + // on the new load. This is even true in some cases even when the loads + // are different types, for example by mapping !nonnull metadata to + // !range metadata by modeling the null pointer constant converted to the + // integer type. + // FIXME: Add support for range metadata here. Currently the utilities + // for this don't propagate range metadata in trivial cases from one + // integer load to another, don't handle non-addrspace-0 null pointers + // correctly, and don't have any support for mapping ranges as the + // integer type becomes winder or narrower. + if (MDNode *N = LI.getMetadata(LLVMContext::MD_nonnull)) + copyNonnullMetadata(LI, N, *NewLI); + // Try to preserve nonnull metadata - if (TargetTy->isPointerTy()) - NewLI->copyMetadata(LI, LLVMContext::MD_nonnull); V = NewLI; // If this is an integer load past the end of the slice (which means the diff --git a/test/Transforms/SROA/preserve-nonnull.ll b/test/Transforms/SROA/preserve-nonnull.ll index 1ff8bec3af91..a29da6dc2c37 100644 --- a/test/Transforms/SROA/preserve-nonnull.ll +++ b/test/Transforms/SROA/preserve-nonnull.ll @@ -42,4 +42,51 @@ entry: ret float* %ret } +; Make sure we properly handle the !nonnull attribute when we convert +; a pointer load to an integer load. +; FIXME: While this doesn't do anythnig actively harmful today, it really +; should propagate the !nonnull metadata to range metadata. The irony is, it +; *does* initially, but then we lose that !range metadata before we finish +; SROA. +define i8* @propagate_nonnull_to_int() { +; CHECK-LABEL: define i8* @propagate_nonnull_to_int( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[A:.*]] = alloca i64 +; CHECK-NEXT: store i64 42, i64* %[[A]] +; CHECK-NEXT: %[[LOAD:.*]] = load volatile i64, i64* %[[A]] +; CHECK-NEXT: %[[CAST:.*]] = inttoptr i64 %[[LOAD]] to i8* +; CHECK-NEXT: ret i8* %[[CAST]] +entry: + %a = alloca [2 x i8*] + %a.gep0 = getelementptr [2 x i8*], [2 x i8*]* %a, i32 0, i32 0 + %a.gep1 = getelementptr [2 x i8*], [2 x i8*]* %a, i32 0, i32 1 + %a.gep0.cast = bitcast i8** %a.gep0 to i64* + %a.gep1.cast = bitcast i8** %a.gep1 to i64* + store i64 42, i64* %a.gep1.cast + store i64 0, i64* %a.gep0.cast + %load = load volatile i8*, i8** %a.gep1, !nonnull !0 + ret i8* %load +} + +; Make sure we properly handle the !nonnull attribute when we convert +; a pointer load to an integer load and immediately promote it to an SSA +; register. This can fail in interesting ways due to the rewrite iteration of +; SROA, resulting in PR32902. +define i8* @propagate_nonnull_to_int_and_promote() { +; CHECK-LABEL: define i8* @propagate_nonnull_to_int_and_promote( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[PROMOTED_VALUE:.*]] = inttoptr i64 42 to i8* +; CHECK-NEXT: ret i8* %[[PROMOTED_VALUE]] +entry: + %a = alloca [2 x i8*], align 8 + %a.gep0 = getelementptr [2 x i8*], [2 x i8*]* %a, i32 0, i32 0 + %a.gep1 = getelementptr [2 x i8*], [2 x i8*]* %a, i32 0, i32 1 + %a.gep0.cast = bitcast i8** %a.gep0 to i64* + %a.gep1.cast = bitcast i8** %a.gep1 to i64* + store i64 42, i64* %a.gep1.cast + store i64 0, i64* %a.gep0.cast + %load = load i8*, i8** %a.gep1, align 8, !nonnull !0 + ret i8* %load +} + !0 = !{}