[llvm] [Loads] Check deref assumption early. (PR #127414)

via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 16 11:59:02 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

<details>
<summary>Changes</summary>

Move up the check of dereferenceable assumptions in isDereferenceableAndAlignedPointer so we also make use of assumptions of chained GEPs.

This also needs extending the cannot-be-freed check to look at the underlying objects.

---
Full diff: https://github.com/llvm/llvm-project/pull/127414.diff


2 Files Affected:

- (modified) llvm/lib/Analysis/Loads.cpp (+33-30) 
- (modified) llvm/test/Transforms/LICM/hoist-speculatable-load.ll (+1-1) 


``````````diff
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index b461c41d29e84..5c562fc3c0fd7 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -48,6 +48,39 @@ static bool isDereferenceableAndAlignedPointer(
   if (!Visited.insert(V).second)
     return false;
 
+  // Dereferenceable information from assumptions is only valid if the value
+  // cannot be freed between the assumption and use. For now just use the
+  // information for values that cannot be freed in the function.
+  // TODO: More precisely check if the pointer can be freed between assumption
+  // and use.
+  if (CtxI) {
+     const Value *UO = getUnderlyingObjectAggressive(V);
+     if(!V->canBeFreed() || (UO && !UO->canBeFreed())) {
+      /// Look through assumes to see if both dereferencability and alignment can
+      /// be proven by an assume if needed.
+      RetainedKnowledge AlignRK;
+      RetainedKnowledge DerefRK;
+      bool IsAligned = V->getPointerAlignment(DL) >= Alignment;
+      if (getKnowledgeForValue(
+              V, {Attribute::Dereferenceable, Attribute::Alignment}, AC,
+              [&](RetainedKnowledge RK, Instruction *Assume, auto) {
+                if (!isValidAssumeForContext(Assume, CtxI, DT))
+                  return false;
+                if (RK.AttrKind == Attribute::Alignment)
+                  AlignRK = std::max(AlignRK, RK);
+                if (RK.AttrKind == Attribute::Dereferenceable)
+                  DerefRK = std::max(DerefRK, RK);
+                IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
+                if (IsAligned && DerefRK &&
+                    DerefRK.ArgValue >= Size.getZExtValue())
+                  return true; // We have found what we needed so we stop looking
+                return false;  // Other assumes may have better information. so
+                               // keep looking
+              }))
+        return true;
+       }
+  }
+
   // Note that it is not safe to speculate into a malloc'd region because
   // malloc may return null.
 
@@ -169,36 +202,6 @@ static bool isDereferenceableAndAlignedPointer(
                                               Size, DL, CtxI, AC, DT, TLI,
                                               Visited, MaxDepth);
 
-  // Dereferenceable information from assumptions is only valid if the value
-  // cannot be freed between the assumption and use. For now just use the
-  // information for values that cannot be freed in the function.
-  // TODO: More precisely check if the pointer can be freed between assumption
-  // and use.
-  if (CtxI && !V->canBeFreed()) {
-    /// Look through assumes to see if both dereferencability and alignment can
-    /// be proven by an assume if needed.
-    RetainedKnowledge AlignRK;
-    RetainedKnowledge DerefRK;
-    bool IsAligned = V->getPointerAlignment(DL) >= Alignment;
-    if (getKnowledgeForValue(
-            V, {Attribute::Dereferenceable, Attribute::Alignment}, AC,
-            [&](RetainedKnowledge RK, Instruction *Assume, auto) {
-              if (!isValidAssumeForContext(Assume, CtxI, DT))
-                return false;
-              if (RK.AttrKind == Attribute::Alignment)
-                AlignRK = std::max(AlignRK, RK);
-              if (RK.AttrKind == Attribute::Dereferenceable)
-                DerefRK = std::max(DerefRK, RK);
-              IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
-              if (IsAligned && DerefRK &&
-                  DerefRK.ArgValue >= Size.getZExtValue())
-                return true; // We have found what we needed so we stop looking
-              return false;  // Other assumes may have better information. so
-                             // keep looking
-            }))
-      return true;
-  }
-
   // If we don't know, assume the worst.
   return false;
 }
diff --git a/llvm/test/Transforms/LICM/hoist-speculatable-load.ll b/llvm/test/Transforms/LICM/hoist-speculatable-load.ll
index a4a38c2eaadc3..331a6b973c395 100644
--- a/llvm/test/Transforms/LICM/hoist-speculatable-load.ll
+++ b/llvm/test/Transforms/LICM/hoist-speculatable-load.ll
@@ -174,12 +174,12 @@ define void @f_chained_gep_with_nofree_nosync(ptr %ptr, ptr %ptr2, i1 %cond) nof
 ; CHECK-NEXT:    store i32 0, ptr [[PTR2:%.*]], align 4
 ; CHECK-NEXT:    br label [[FOR_BODY_LR_PH]]
 ; CHECK:       for.body.lr.ph:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[GEP]], align 4
 ; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[I_08:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH]] ], [ [[INC:%.*]], [[IF_END:%.*]] ]
 ; CHECK-NEXT:    br i1 [[COND]], label [[IF_END]], label [[IF:%.*]]
 ; CHECK:       if:
-; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[GEP]], align 4, !invariant.load [[META0]]
 ; CHECK-NEXT:    store i32 [[TMP0]], ptr [[PTR2]], align 4
 ; CHECK-NEXT:    br label [[IF_END]]
 ; CHECK:       if.end:

``````````

</details>


https://github.com/llvm/llvm-project/pull/127414


More information about the llvm-commits mailing list