diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -435,6 +435,15 @@ TypeSize TySize = DL.getTypeStoreSize(Ty); if (TySize.isScalable()) return false; + // When the load has nonnull and noundef metadata, we cannot easily conclude + // that it is safe. + if (auto *LI = dyn_cast(ScanFrom)) { + if (LI->getType()->isPointerTy() && + LI->getMetadata(LLVMContext::MD_nonnull) && + LI->getMetadata(LLVMContext::MD_noundef)) { + return false; + } + } APInt Size(DL.getIndexTypeSizeInBits(V->getType()), TySize.getFixedValue()); return isSafeToLoadUnconditionally(V, Alignment, Size, DL, ScanFrom, AC, DT, TLI); diff --git a/llvm/test/Transforms/SROA/select-load-with-nonnull.ll b/llvm/test/Transforms/SROA/select-load-with-nonnull.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SROA/select-load-with-nonnull.ll @@ -0,0 +1,56 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes='sroa' -S | FileCheck %s + +define void @load_of_select_with_noundef_nonnull(ptr %buffer, i1 %b) { +; CHECK-LABEL: @load_of_select_with_noundef_nonnull( +; CHECK-NEXT: br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTELSE:%.*]] +; CHECK: .then: +; CHECK-NEXT: [[LOAD_PTR_THEN_VAL:%.*]] = load ptr, ptr [[BUFFER:%.*]], align 8, !nonnull !0, !noundef !0 +; CHECK-NEXT: br label [[DOTCONT:%.*]] +; CHECK: .else: +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne ptr undef, null +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]]) +; CHECK-NEXT: br label [[DOTCONT]] +; CHECK: .cont: +; CHECK-NEXT: [[LOAD_PTR:%.*]] = phi ptr [ [[LOAD_PTR_THEN_VAL]], [[DOTTHEN]] ], [ undef, [[DOTELSE]] ] +; CHECK-NEXT: ret void +; + %ub_ptr = alloca ptr + %select_ptr = select i1 %b, ptr %buffer, ptr %ub_ptr + %load_ptr = load ptr, ptr %select_ptr, !nonnull !1, !noundef !1 + ret void +} + +define void @load_of_select_with_noundef(ptr %buffer, i1 %b) { +; CHECK-LABEL: @load_of_select_with_noundef( +; CHECK-NEXT: br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTCONT:%.*]] +; CHECK: .then: +; CHECK-NEXT: [[LOAD_PTR_THEN_VAL:%.*]] = load ptr, ptr [[BUFFER:%.*]], align 8, !noundef !0 +; CHECK-NEXT: br label [[DOTCONT]] +; CHECK: .cont: +; CHECK-NEXT: [[LOAD_PTR:%.*]] = phi ptr [ [[LOAD_PTR_THEN_VAL]], [[DOTTHEN]] ], [ undef, [[TMP0:%.*]] ] +; CHECK-NEXT: ret void +; + %ub_ptr = alloca ptr + %select_ptr = select i1 %b, ptr %buffer, ptr %ub_ptr + %load_ptr = load ptr, ptr %select_ptr, !noundef !1 + ret void +} + +define void @load_of_select(ptr %buffer, i1 %b) { +; CHECK-LABEL: @load_of_select( +; CHECK-NEXT: br i1 [[B:%.*]], label [[DOTTHEN:%.*]], label [[DOTCONT:%.*]] +; CHECK: .then: +; CHECK-NEXT: [[LOAD_PTR_THEN_VAL:%.*]] = load ptr, ptr [[BUFFER:%.*]], align 8 +; CHECK-NEXT: br label [[DOTCONT]] +; CHECK: .cont: +; CHECK-NEXT: [[LOAD_PTR:%.*]] = phi ptr [ [[LOAD_PTR_THEN_VAL]], [[DOTTHEN]] ], [ undef, [[TMP0:%.*]] ] +; CHECK-NEXT: ret void +; + %ub_ptr = alloca ptr + %select_ptr = select i1 %b, ptr %buffer, ptr %ub_ptr + %load_ptr = load ptr, ptr %select_ptr + ret void +} + +!1 = !{}