[llvm] fb632ed - [GVN] Handle provenance when propagating assume equality (#151953)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 5 00:18:46 PDT 2025


Author: Nikita Popov
Date: 2025-08-05T09:18:43+02:00
New Revision: fb632ed2377d280b581b8d4653b855e60d611f77

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

LOG: [GVN] Handle provenance when propagating assume equality (#151953)

If we have a known `p == p2` equality, we cannot replace `p2` with `p`
unless they are known to have the same provenance. GVN handles this when
propagating equalities from conditions, but not for assumes, as these go
through a different code path for uses in the same block.

Call canReplacePointersInUseIfEqual() before performing the replacement.
This is subject to the usual approximations (e.g. that we always allow
replacement with a dereferenceable constant and null).

This restriction does not appear to have any impact in practice.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/GVN.cpp
    llvm/test/Transforms/GVN/assume-equal.ll
    llvm/test/Transforms/GVN/lifetime-simple.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 3a73b42455b0d..7704e49c499da 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -2499,11 +2499,11 @@ void GVNPass::assignBlockRPONumber(Function &F) {
 bool GVNPass::replaceOperandsForInBlockEquality(Instruction *Instr) const {
   bool Changed = false;
   for (unsigned OpNum = 0; OpNum < Instr->getNumOperands(); ++OpNum) {
-    Value *Operand = Instr->getOperand(OpNum);
-    auto It = ReplaceOperandsWithMap.find(Operand);
+    Use &Operand = Instr->getOperandUse(OpNum);
+    auto It = ReplaceOperandsWithMap.find(Operand.get());
     if (It != ReplaceOperandsWithMap.end()) {
-      // Do not replace lifetime alloca argument with something else.
-      if (Instr->isLifetimeStartOrEnd())
+      const DataLayout &DL = Instr->getDataLayout();
+      if (!canReplacePointersInUseIfEqual(Operand, It->second, DL))
         continue;
 
       LLVM_DEBUG(dbgs() << "GVN replacing: " << *Operand << " with "

diff  --git a/llvm/test/Transforms/GVN/assume-equal.ll b/llvm/test/Transforms/GVN/assume-equal.ll
index a27b0e45bf9e1..0c922daf82b32 100644
--- a/llvm/test/Transforms/GVN/assume-equal.ll
+++ b/llvm/test/Transforms/GVN/assume-equal.ll
@@ -343,6 +343,50 @@ meh:
   ret i1 %k
 }
 
+define i8 @assume_ptr_eq_
diff erent_prov_matters(ptr %p, ptr %p2) {
+; CHECK-LABEL: define i8 @assume_ptr_eq_
diff erent_prov_matters(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[P2:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], [[P2]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[V:%.*]] = load i8, ptr [[P2]], align 1
+; CHECK-NEXT:    ret i8 [[V]]
+;
+  %cmp = icmp eq ptr %p, %p2
+  call void @llvm.assume(i1 %cmp)
+  %v = load i8, ptr %p2
+  ret i8 %v
+}
+
+define i1 @assume_ptr_eq_
diff erent_prov_does_not_matter(ptr %p, ptr %p2) {
+; CHECK-LABEL: define i1 @assume_ptr_eq_
diff erent_prov_does_not_matter(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[P2:%.*]]) {
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], [[P2]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[P]], null
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %cmp = icmp eq ptr %p, %p2
+  call void @llvm.assume(i1 %cmp)
+  %c = icmp eq ptr %p2, null
+  ret i1 %c
+}
+
+define i8 @assume_ptr_eq_same_prov(ptr %p, i64 %x) {
+; CHECK-LABEL: define i8 @assume_ptr_eq_same_prov(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[X:%.*]]) {
+; CHECK-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[P]], [[P2]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
+; CHECK-NEXT:    ret i8 [[V]]
+;
+  %p2 = getelementptr i8, ptr %p, i64 %x
+  %cmp = icmp eq ptr %p, %p2
+  call void @llvm.assume(i1 %cmp)
+  %v = load i8, ptr %p2
+  ret i8 %v
+}
+
 declare noalias ptr @_Znwm(i64)
 declare void @_ZN1AC1Ev(ptr)
 declare void @llvm.assume(i1)

diff  --git a/llvm/test/Transforms/GVN/lifetime-simple.ll b/llvm/test/Transforms/GVN/lifetime-simple.ll
index 30883bd9dc6d3..89ca127a47fda 100644
--- a/llvm/test/Transforms/GVN/lifetime-simple.ll
+++ b/llvm/test/Transforms/GVN/lifetime-simple.ll
@@ -29,7 +29,7 @@ define void @assume_eq_arg(ptr %arg) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[ALLOCA]], [[ARG]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
 ; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 4, ptr [[ALLOCA]])
-; CHECK-NEXT:    store volatile i32 0, ptr [[ARG]], align 4
+; CHECK-NEXT:    store volatile i32 0, ptr [[ALLOCA]], align 4
 ; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 4, ptr [[ALLOCA]])
 ; CHECK-NEXT:    ret void
 ;


        


More information about the llvm-commits mailing list