[llvm] 7893def - [Loads] Always pass down context in isSafeToLoadUnconditionally() (#201833)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 00:22:23 PDT 2026


Author: Nikita Popov
Date: 2026-06-08T09:22:17+02:00
New Revision: 7893defd8b56e70ebad4eaf79a1f14caf4a9d1d1

URL: https://github.com/llvm/llvm-project/commit/7893defd8b56e70ebad4eaf79a1f14caf4a9d1d1
DIFF: https://github.com/llvm/llvm-project/commit/7893defd8b56e70ebad4eaf79a1f14caf4a9d1d1.diff

LOG: [Loads] Always pass down context in isSafeToLoadUnconditionally() (#201833)

There is context-sensitive reasoning we can perform without a dominator
tree -- it doesn't make sense to drop the context instruction just
because there is no DT.

Also handle the case where the start instruction and the context
instruction are the same in willNotFreeBetween(). In that case we want
the function return true, not false.

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/Loads.h
    llvm/lib/Analysis/Loads.cpp
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Transforms/InstCombine/loadstore-metadata.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/Loads.h b/llvm/include/llvm/Analysis/Loads.h
index a9cbd5173973a..275dc2c5db847 100644
--- a/llvm/include/llvm/Analysis/Loads.h
+++ b/llvm/include/llvm/Analysis/Loads.h
@@ -65,8 +65,8 @@ LLVM_ABI bool isDereferenceableAndAlignedPointer(
 
 /// Return true if we know that executing a load from this value cannot trap.
 ///
-/// If DT and ScanFrom are specified this method performs context-sensitive
-/// analysis and returns true if it is safe to load immediately before ScanFrom.
+/// If ScanFrom is specified this method performs context-sensitive analysis
+/// and returns true if it is safe to load immediately before ScanFrom.
 ///
 /// If it is not obviously safe to load from the specified pointer, we do a
 /// quick local scan of the basic block containing ScanFrom, to determine if

diff  --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 434c86869d718..ab27da6317bd7 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -454,27 +454,14 @@ bool llvm::mustSuppressSpeculation(const LoadInst &LI) {
   return !LI.isUnordered() || suppressSpeculativeLoadForSanitizers(LI);
 }
 
-/// Check if executing a load of this pointer value cannot trap.
-///
-/// If DT and ScanFrom are specified this method performs context-sensitive
-/// analysis and returns true if it is safe to load immediately before ScanFrom.
-///
-/// If it is not obviously safe to load from the specified pointer, we do
-/// a quick local scan of the basic block containing \c ScanFrom, to determine
-/// if the address is already accessed.
-///
-/// This uses the pointee type to determine how many bytes need to be safe to
-/// load from the pointer.
 bool llvm::isSafeToLoadUnconditionally(Value *V, Align Alignment, const APInt &Size,
                                        const DataLayout &DL,
                                        Instruction *ScanFrom,
                                        AssumptionCache *AC,
                                        const DominatorTree *DT,
                                        const TargetLibraryInfo *TLI) {
-  // If DT is not specified we can't make context-sensitive query
-  const Instruction* CtxI = DT ? ScanFrom : nullptr;
-  if (isDereferenceableAndAlignedPointer(V, Alignment, Size, DL, CtxI, AC, DT,
-                                         TLI)) {
+  if (isDereferenceableAndAlignedPointer(V, Alignment, Size, DL, ScanFrom, AC,
+                                         DT, TLI)) {
     // With sanitizers `Dereferenceable` is not always enough for unconditional
     // load.
     if (!ScanFrom || !suppressSpeculativeLoadForSanitizers(*ScanFrom))

diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8ff5b750203cc..1261664c5b986 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -732,7 +732,7 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
     CtxIter = AssumeBB->end();
   } else {
     // Same block case: check that Assume comes before CtxI.
-    if (!Assume->comesBefore(CtxI))
+    if (Assume != CtxI && !Assume->comesBefore(CtxI))
       return false;
   }
 

diff  --git a/llvm/test/Transforms/InstCombine/loadstore-metadata.ll b/llvm/test/Transforms/InstCombine/loadstore-metadata.ll
index c21cc23565efb..02552df831196 100644
--- a/llvm/test/Transforms/InstCombine/loadstore-metadata.ll
+++ b/llvm/test/Transforms/InstCombine/loadstore-metadata.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -passes=instcombine -S < %s | FileCheck %s --check-prefixes=CHECK,GLOBAL
-; RUN: opt -passes=instcombine -use-dereferenceable-at-point-semantics -S < %s | FileCheck %s --check-prefixes=CHECK,AT-POINT
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+; RUN: opt -passes=instcombine -use-dereferenceable-at-point-semantics -S < %s | FileCheck %s
 
 target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
 
@@ -201,20 +201,13 @@ entry:
 
 ; Preserve none-UB metadata on loads.
 define ptr @preserve_load_metadata_after_select_transform1(i1 %c, ptr dereferenceable(8) %a, ptr dereferenceable(8) %b) {
-; GLOBAL-LABEL: define ptr @preserve_load_metadata_after_select_transform1(
-; GLOBAL-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
-; GLOBAL-NEXT:  [[ENTRY:.*:]]
-; GLOBAL-NEXT:    [[B_VAL:%.*]] = load ptr, ptr [[B]], align 1, !nonnull [[META6]], !align [[META8]]
-; GLOBAL-NEXT:    [[A_VAL:%.*]] = load ptr, ptr [[A]], align 1, !nonnull [[META6]], !align [[META8]]
-; GLOBAL-NEXT:    [[L_SEL:%.*]] = select i1 [[C]], ptr [[B_VAL]], ptr [[A_VAL]]
-; GLOBAL-NEXT:    ret ptr [[L_SEL]]
-;
-; AT-POINT-LABEL: define ptr @preserve_load_metadata_after_select_transform1(
-; AT-POINT-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
-; AT-POINT-NEXT:  [[ENTRY:.*:]]
-; AT-POINT-NEXT:    [[PTR_SEL:%.*]] = select i1 [[C]], ptr [[B]], ptr [[A]]
-; AT-POINT-NEXT:    [[L_SEL:%.*]] = load ptr, ptr [[PTR_SEL]], align 1, !tbaa [[SCALAR_TYPE_TBAA0]], !invariant.load [[META6]], !nonnull [[META6]], !dereferenceable [[META8]], !align [[META8]], !llvm.access.group [[META6]], !noundef [[META6]]
-; AT-POINT-NEXT:    ret ptr [[L_SEL]]
+; CHECK-LABEL: define ptr @preserve_load_metadata_after_select_transform1(
+; CHECK-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B_VAL:%.*]] = load ptr, ptr [[B]], align 1, !nonnull [[META6]], !align [[META8]]
+; CHECK-NEXT:    [[A_VAL:%.*]] = load ptr, ptr [[A]], align 1, !nonnull [[META6]], !align [[META8]]
+; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[C]], ptr [[B_VAL]], ptr [[A_VAL]]
+; CHECK-NEXT:    ret ptr [[L_SEL]]
 ;
 entry:
   %ptr.sel = select i1 %c, ptr %b, ptr %a
@@ -224,20 +217,13 @@ entry:
 
 ; Preserve none-UB metadata on loads.
 define i32 @preserve_load_metadata_after_select_transform_range(i1 %c, ptr dereferenceable(8) %a, ptr dereferenceable(8) %b) {
-; GLOBAL-LABEL: define i32 @preserve_load_metadata_after_select_transform_range(
-; GLOBAL-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
-; GLOBAL-NEXT:  [[ENTRY:.*:]]
-; GLOBAL-NEXT:    [[B_VAL:%.*]] = load i32, ptr [[B]], align 1, !range [[RNG11:![0-9]+]]
-; GLOBAL-NEXT:    [[A_VAL:%.*]] = load i32, ptr [[A]], align 1, !range [[RNG11]]
-; GLOBAL-NEXT:    [[L_SEL:%.*]] = select i1 [[C]], i32 [[B_VAL]], i32 [[A_VAL]]
-; GLOBAL-NEXT:    ret i32 [[L_SEL]]
-;
-; AT-POINT-LABEL: define i32 @preserve_load_metadata_after_select_transform_range(
-; AT-POINT-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
-; AT-POINT-NEXT:  [[ENTRY:.*:]]
-; AT-POINT-NEXT:    [[PTR_SEL:%.*]] = select i1 [[C]], ptr [[B]], ptr [[A]]
-; AT-POINT-NEXT:    [[L_SEL:%.*]] = load i32, ptr [[PTR_SEL]], align 1, !tbaa [[SCALAR_TYPE_TBAA0]], !range [[RNG11:![0-9]+]], !invariant.load [[META6]], !llvm.access.group [[META6]], !noundef [[META6]]
-; AT-POINT-NEXT:    ret i32 [[L_SEL]]
+; CHECK-LABEL: define i32 @preserve_load_metadata_after_select_transform_range(
+; CHECK-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B_VAL:%.*]] = load i32, ptr [[B]], align 1, !range [[RNG11:![0-9]+]]
+; CHECK-NEXT:    [[A_VAL:%.*]] = load i32, ptr [[A]], align 1, !range [[RNG11]]
+; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[C]], i32 [[B_VAL]], i32 [[A_VAL]]
+; CHECK-NEXT:    ret i32 [[L_SEL]]
 ;
 entry:
   %ptr.sel = select i1 %c, ptr %b, ptr %a
@@ -343,20 +329,13 @@ entry:
 }
 
 define float @preserve_load_metadata_after_select_transform_nofpclass(i1 %c, ptr dereferenceable(8) %a, ptr dereferenceable(8) %b) {
-; GLOBAL-LABEL: define float @preserve_load_metadata_after_select_transform_nofpclass(
-; GLOBAL-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
-; GLOBAL-NEXT:  [[ENTRY:.*:]]
-; GLOBAL-NEXT:    [[B_VAL:%.*]] = load float, ptr [[B]], align 1, !nofpclass [[META16:![0-9]+]]
-; GLOBAL-NEXT:    [[A_VAL:%.*]] = load float, ptr [[A]], align 1, !nofpclass [[META16]]
-; GLOBAL-NEXT:    [[L_SEL:%.*]] = select i1 [[C]], float [[B_VAL]], float [[A_VAL]]
-; GLOBAL-NEXT:    ret float [[L_SEL]]
-;
-; AT-POINT-LABEL: define float @preserve_load_metadata_after_select_transform_nofpclass(
-; AT-POINT-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
-; AT-POINT-NEXT:  [[ENTRY:.*:]]
-; AT-POINT-NEXT:    [[PTR_SEL:%.*]] = select i1 [[C]], ptr [[B]], ptr [[A]]
-; AT-POINT-NEXT:    [[L_SEL:%.*]] = load float, ptr [[PTR_SEL]], align 1, !nofpclass [[META16:![0-9]+]]
-; AT-POINT-NEXT:    ret float [[L_SEL]]
+; CHECK-LABEL: define float @preserve_load_metadata_after_select_transform_nofpclass(
+; CHECK-SAME: i1 [[C:%.*]], ptr dereferenceable(8) [[A:%.*]], ptr dereferenceable(8) [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B_VAL:%.*]] = load float, ptr [[B]], align 1, !nofpclass [[META16:![0-9]+]]
+; CHECK-NEXT:    [[A_VAL:%.*]] = load float, ptr [[A]], align 1, !nofpclass [[META16]]
+; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[C]], float [[B_VAL]], float [[A_VAL]]
+; CHECK-NEXT:    ret float [[L_SEL]]
 ;
 entry:
   %ptr.sel = select i1 %c, ptr %b, ptr %a
@@ -396,7 +375,7 @@ define float @test_load_cast_combine_nofpclass_1xvec_to_scalar(ptr %ptr) {
 ; CHECK-LABEL: define float @test_load_cast_combine_nofpclass_1xvec_to_scalar(
 ; CHECK-SAME: ptr [[PTR:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[L1:%.*]] = load float, ptr [[PTR]], align 4, !nofpclass [[META16:![0-9]+]]
+; CHECK-NEXT:    [[L1:%.*]] = load float, ptr [[PTR]], align 4, !nofpclass [[META16]]
 ; CHECK-NEXT:    ret float [[L1]]
 ;
 entry:
@@ -452,43 +431,23 @@ entry:
 !18 = !{ !"nvvm.l1_eviction", !"first" }
 
 ;.
-; GLOBAL: [[SCALAR_TYPE_TBAA0]] = !{[[LOOP1]], [[LOOP1]], i64 0}
-; GLOBAL: [[LOOP1]] = !{!"scalar type", [[META2:![0-9]+]]}
-; GLOBAL: [[META2]] = !{!"root"}
-; GLOBAL: [[META3]] = !{[[META4:![0-9]+]]}
-; GLOBAL: [[META4]] = distinct !{[[META4]], [[META5:![0-9]+]]}
-; GLOBAL: [[META5]] = distinct !{[[META5]]}
-; GLOBAL: [[META6]] = !{}
-; GLOBAL: [[META7]] = !{i32 1}
-; GLOBAL: [[META8]] = !{i64 8}
-; GLOBAL: [[ACC_GRP9]] = distinct !{}
-; GLOBAL: [[META10]] = !{i32 5, i32 6}
-; GLOBAL: [[RNG11]] = !{i32 0, i32 42}
-; GLOBAL: [[META12]] = !{[[META13:![0-9]+]]}
-; GLOBAL: [[META13]] = distinct !{[[META13]], [[META14:![0-9]+]]}
-; GLOBAL: [[META14]] = distinct !{[[META14]]}
-; GLOBAL: [[ACC_GRP15]] = distinct !{}
-; GLOBAL: [[META16]] = !{i32 3}
-; GLOBAL: [[META17]] = !{i32 0, [[META18:![0-9]+]]}
-; GLOBAL: [[META18]] = !{!"nvvm.l1_eviction", !"first"}
-;.
-; AT-POINT: [[SCALAR_TYPE_TBAA0]] = !{[[LOOP1]], [[LOOP1]], i64 0}
-; AT-POINT: [[LOOP1]] = !{!"scalar type", [[META2:![0-9]+]]}
-; AT-POINT: [[META2]] = !{!"root"}
-; AT-POINT: [[META3]] = !{[[META4:![0-9]+]]}
-; AT-POINT: [[META4]] = distinct !{[[META4]], [[META5:![0-9]+]]}
-; AT-POINT: [[META5]] = distinct !{[[META5]]}
-; AT-POINT: [[META6]] = !{}
-; AT-POINT: [[META7]] = !{i32 1}
-; AT-POINT: [[META8]] = !{i64 8}
-; AT-POINT: [[ACC_GRP9]] = distinct !{}
-; AT-POINT: [[META10]] = !{i32 5, i32 6}
-; AT-POINT: [[RNG11]] = !{i32 0, i32 42}
-; AT-POINT: [[META12]] = !{[[META13:![0-9]+]]}
-; AT-POINT: [[META13]] = distinct !{[[META13]], [[META14:![0-9]+]]}
-; AT-POINT: [[META14]] = distinct !{[[META14]]}
-; AT-POINT: [[ACC_GRP15]] = distinct !{}
-; AT-POINT: [[META16]] = !{i32 3}
-; AT-POINT: [[META17]] = !{i32 0, [[META18:![0-9]+]]}
-; AT-POINT: [[META18]] = !{!"nvvm.l1_eviction", !"first"}
+; CHECK: [[SCALAR_TYPE_TBAA0]] = !{[[LOOP1]], [[LOOP1]], i64 0}
+; CHECK: [[LOOP1]] = !{!"scalar type", [[META2:![0-9]+]]}
+; CHECK: [[META2]] = !{!"root"}
+; CHECK: [[META3]] = !{[[META4:![0-9]+]]}
+; CHECK: [[META4]] = distinct !{[[META4]], [[META5:![0-9]+]]}
+; CHECK: [[META5]] = distinct !{[[META5]]}
+; CHECK: [[META6]] = !{}
+; CHECK: [[META7]] = !{i32 1}
+; CHECK: [[META8]] = !{i64 8}
+; CHECK: [[ACC_GRP9]] = distinct !{}
+; CHECK: [[META10]] = !{i32 5, i32 6}
+; CHECK: [[RNG11]] = !{i32 0, i32 42}
+; CHECK: [[META12]] = !{[[META13:![0-9]+]]}
+; CHECK: [[META13]] = distinct !{[[META13]], [[META14:![0-9]+]]}
+; CHECK: [[META14]] = distinct !{[[META14]]}
+; CHECK: [[ACC_GRP15]] = distinct !{}
+; CHECK: [[META16]] = !{i32 3}
+; CHECK: [[META17]] = !{i32 0, [[META18:![0-9]+]]}
+; CHECK: [[META18]] = !{!"nvvm.l1_eviction", !"first"}
 ;.


        


More information about the llvm-commits mailing list