[llvm] 4b5b36e - [GVN] Avoid creating lifetime of non-alloca
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 4 03:06:51 PDT 2025
Author: Nikita Popov
Date: 2025-08-04T12:06:40+02:00
New Revision: 4b5b36e5c4b887a86fc7164d6899caaa2e2f5aed
URL: https://github.com/llvm/llvm-project/commit/4b5b36e5c4b887a86fc7164d6899caaa2e2f5aed
DIFF: https://github.com/llvm/llvm-project/commit/4b5b36e5c4b887a86fc7164d6899caaa2e2f5aed.diff
LOG: [GVN] Avoid creating lifetime of non-alloca
There is a larger problem here in that we should not be performing
arbitrary pointer replacements for assumes. This is handled for
branches, but assume goes through a different code path.
Fixes https://github.com/llvm/llvm-project/issues/151785.
Added:
Modified:
llvm/lib/Analysis/Loads.cpp
llvm/lib/Transforms/Scalar/GVN.cpp
llvm/test/Transforms/GVN/lifetime-simple.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 6fc81d787c220..da76f5b3d498a 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -833,6 +833,10 @@ bool llvm::canReplacePointersInUseIfEqual(const Use &U, const Value *To,
if (!To->getType()->isPointerTy())
return true;
+ // Do not perform replacements in lifetime intrinsic arguments.
+ if (isa<LifetimeIntrinsic>(U.getUser()))
+ return false;
+
if (isPointerAlwaysReplaceable(&*U, To, DL))
return true;
return isPointerUseReplacable(U);
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index f6bf09d09433d..fa6ee95d33d10 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -2502,6 +2502,10 @@ bool GVNPass::replaceOperandsForInBlockEquality(Instruction *Instr) const {
Value *Operand = Instr->getOperand(OpNum);
auto It = ReplaceOperandsWithMap.find(Operand);
if (It != ReplaceOperandsWithMap.end()) {
+ // Do not replace lifetime alloca argument with something else.
+ if (Instr->isLifetimeStartOrEnd())
+ continue;
+
LLVM_DEBUG(dbgs() << "GVN replacing: " << *Operand << " with "
<< *It->second << " in instruction " << *Instr << '\n');
Instr->setOperand(OpNum, It->second);
diff --git a/llvm/test/Transforms/GVN/lifetime-simple.ll b/llvm/test/Transforms/GVN/lifetime-simple.ll
index 177f43f39d973..30883bd9dc6d3 100644
--- a/llvm/test/Transforms/GVN/lifetime-simple.ll
+++ b/llvm/test/Transforms/GVN/lifetime-simple.ll
@@ -22,5 +22,71 @@ entry:
ret i8 %1
}
+define void @assume_eq_arg(ptr %arg) {
+; CHECK-LABEL: define void @assume_eq_arg(
+; CHECK-SAME: ptr [[ARG:%.*]]) {
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
+; 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: call void @llvm.lifetime.end.p0(i64 4, ptr [[ALLOCA]])
+; CHECK-NEXT: ret void
+;
+ %alloca = alloca i32
+ %cmp = icmp eq ptr %alloca, %arg
+ call void @llvm.assume(i1 %cmp)
+ call void @llvm.lifetime.start.p0(i64 4, ptr %alloca)
+ store volatile i32 0, ptr %alloca
+ call void @llvm.lifetime.end.p0(i64 4, ptr %alloca)
+ ret void
+}
+
+define void @assume_eq_null() {
+; CHECK-LABEL: define void @assume_eq_null() {
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4, addrspace(1)
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(1) [[ALLOCA]], null
+; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT: call void @llvm.lifetime.start.p1(i64 4, ptr addrspace(1) [[ALLOCA]])
+; CHECK-NEXT: store volatile i32 0, ptr addrspace(1) null, align 4
+; CHECK-NEXT: call void @llvm.lifetime.end.p1(i64 4, ptr addrspace(1) [[ALLOCA]])
+; CHECK-NEXT: ret void
+;
+ %alloca = alloca i32, addrspace(1)
+ %cmp = icmp eq ptr addrspace(1) %alloca, null
+ call void @llvm.assume(i1 %cmp)
+ call void @llvm.lifetime.start.p1(i64 4, ptr addrspace(1) %alloca)
+ store volatile i32 0, ptr addrspace(1) %alloca
+ call void @llvm.lifetime.end.p1(i64 4, ptr addrspace(1) %alloca)
+ ret void
+}
+
+define void @dom_eq_null() {
+; CHECK-LABEL: define void @dom_eq_null() {
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4, addrspace(1)
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(1) [[ALLOCA]], null
+; CHECK-NEXT: br i1 [[CMP]], label %[[IF:.*]], label %[[ELSE:.*]]
+; CHECK: [[IF]]:
+; CHECK-NEXT: call void @llvm.lifetime.start.p1(i64 4, ptr addrspace(1) [[ALLOCA]])
+; CHECK-NEXT: store volatile i32 0, ptr addrspace(1) null, align 4
+; CHECK-NEXT: call void @llvm.lifetime.end.p1(i64 4, ptr addrspace(1) [[ALLOCA]])
+; CHECK-NEXT: ret void
+; CHECK: [[ELSE]]:
+; CHECK-NEXT: ret void
+;
+ %alloca = alloca i32, addrspace(1)
+ %cmp = icmp eq ptr addrspace(1) %alloca, null
+ br i1 %cmp, label %if, label %else
+
+if:
+ call void @llvm.lifetime.start.p1(i64 4, ptr addrspace(1) %alloca)
+ store volatile i32 0, ptr addrspace(1) %alloca
+ call void @llvm.lifetime.end.p1(i64 4, ptr addrspace(1) %alloca)
+ ret void
+
+else:
+ ret void
+}
+
declare void @llvm.lifetime.start.p0(i64 %S, ptr nocapture %P) readonly
declare void @llvm.lifetime.end.p0(i64 %S, ptr nocapture %P)
More information about the llvm-commits
mailing list