Index: lib/Transforms/Scalar/SROA.cpp =================================================================== --- lib/Transforms/Scalar/SROA.cpp +++ lib/Transforms/Scalar/SROA.cpp @@ -2387,6 +2387,21 @@ LI.isVolatile(), LI.getName()); if (LI.isVolatile()) NewLI->setAtomic(LI.getOrdering(), LI.getSynchScope()); + + SmallVector, 8> MD; + LI.getAllMetadata(MD); + // Try to preserve as much metadata as possible + for (const auto &MDPair : MD) { + unsigned ID = MDPair.first; + MDNode *N = MDPair.second; + switch (ID) { + case LLVMContext::MD_nonnull: + if (TargetTy->isPointerTy()) { + NewLI->setMetadata(ID, N); + break; + } + } + } V = NewLI; // If this is an integer load past the end of the slice (which means the Index: lib/Transforms/Utils/PromoteMemoryToRegister.cpp =================================================================== --- lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -387,6 +387,25 @@ // code. if (ReplVal == LI) ReplVal = UndefValue::get(LI->getType()); + + // We're replacing this Load with another Load, so let's preserve metadata + if (isa(ReplVal)) { + SmallVector, 8> MD; + LI->getAllMetadata(MD); + // Try to preserve as much metadata as possible + for (const auto &MDPair : MD) { + unsigned ID = MDPair.first; + MDNode *N = MDPair.second; + switch (ID) { + case LLVMContext::MD_nonnull: + if (LI->getType()->isPointerTy()) { + ((LoadInst *) ReplVal)->setMetadata(ID, N); + break; + } + } + } + } + LI->replaceAllUsesWith(ReplVal); if (AST && LI->getType()->isPointerTy()) AST->deleteValue(LI); @@ -939,6 +958,22 @@ continue; Value *V = IncomingVals[AI->second]; + if (isa(V)) { + SmallVector, 8> MD; + LI->getAllMetadata(MD); + // Try to preserve as much metadata as possible + for (const auto &MDPair : MD) { + unsigned ID = MDPair.first; + MDNode *N = MDPair.second; + switch (ID) { + case LLVMContext::MD_nonnull: + if (LI->getType()->isPointerTy()) { + ((LoadInst *) V)->setMetadata(ID, N); + break; + } + } + } + } // Anything using the load now uses the current value. LI->replaceAllUsesWith(V); Index: test/Transforms/SROA/preserve-nonnull.ll =================================================================== --- /dev/null +++ test/Transforms/SROA/preserve-nonnull.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -sroa -S | FileCheck %s +; +; Make sure that SROA doesn't lose nonnull metadata +; on loads from allocas that optimized out. + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK-LABEL: yummy_nonnull +; CHECK: %{{.*}} = load float*, float** %0, align 8, !nonnull !0 + +define float* @yummy_nonnull(float**) { +entry-block: + %buf = alloca float* + + %_0_i8 = bitcast float** %0 to i8* + %_buf_i8 = bitcast float** %buf to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %_buf_i8, i8* %_0_i8, i64 8, i32 8, i1 false) + + %ret = load float*, float** %buf, align 8, !nonnull !0 + ret float* %ret +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) + +!0 = !{}