[llvm-branch-commits] [llvm] [DSE] Make DSE eliminate stores to objects with a sized dead_on_return (PR #173694)
Aiden Grossman via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jan 14 09:22:35 PST 2026
https://github.com/boomanaiden154 updated https://github.com/llvm/llvm-project/pull/173694
>From ba9d3c13c2efe720833d62f1c6cbc150eb399ceb Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Sat, 27 Dec 2025 02:05:36 +0000
Subject: [PATCH 1/2] formatting
Created using spr 1.3.7
---
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 25d473b5beb72..78734beac4bbe 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1214,7 +1214,8 @@ struct DSEState {
return OW_None;
}
- bool isInvisibleToCallerAfterRet(const Value *V, const Value *Ptr, const LocationSize StoreSize) {
+ bool isInvisibleToCallerAfterRet(const Value *V, const Value *Ptr,
+ const LocationSize StoreSize) {
if (isa<AllocaInst>(V))
return true;
@@ -1774,7 +1775,8 @@ struct DSEState {
BasicBlock *MaybeKillingBlock = UseInst->getParent();
if (PostOrderNumbers.find(MaybeKillingBlock)->second <
PostOrderNumbers.find(MaybeDeadAccess->getBlock())->second) {
- if (!isInvisibleToCallerAfterRet(KillingUndObj, KillingLoc.Ptr, KillingLoc.Size)) {
+ if (!isInvisibleToCallerAfterRet(KillingUndObj, KillingLoc.Ptr,
+ KillingLoc.Size)) {
LLVM_DEBUG(dbgs()
<< " ... found killing def " << *UseInst << "\n");
KillingDefs.insert(UseInst);
@@ -1792,7 +1794,8 @@ struct DSEState {
// For accesses to locations visible after the function returns, make sure
// that the location is dead (=overwritten) along all paths from
// MaybeDeadAccess to the exit.
- if (!isInvisibleToCallerAfterRet(KillingUndObj, KillingLoc.Ptr, KillingLoc.Size)) {
+ if (!isInvisibleToCallerAfterRet(KillingUndObj, KillingLoc.Ptr,
+ KillingLoc.Size)) {
SmallPtrSet<BasicBlock *, 16> KillingBlocks;
for (Instruction *KD : KillingDefs)
KillingBlocks.insert(KD->getParent());
>From 805d7b8f4c1bb9d394a6d0760bc7de2a274fda30 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Wed, 14 Jan 2026 17:22:23 +0000
Subject: [PATCH 2/2] feedback
Created using spr 1.3.7
---
.../Scalar/DeadStoreElimination.cpp | 27 ++++++++++------
.../Transforms/DeadStoreElimination/simple.ll | 31 +++++++++++++++++--
2 files changed, 46 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 78734beac4bbe..20436b92412f9 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1018,16 +1018,19 @@ struct DSEState {
// Treat byval, inalloca or dead on return arguments the same as Allocas,
// stores to them are dead at the end of the function.
for (Argument &AI : F.args()) {
- if (AI.hasPassPointeeByValueCopyAttr() ||
- (AI.getType()->isPointerTy() &&
- AI.getDeadOnReturnInfo().coversAllReachableMemory()))
+ if (AI.hasPassPointeeByValueCopyAttr()) {
InvisibleToCallerAfterRet.insert({&AI, true});
- if (AI.getType()->isPointerTy() &&
- !AI.getDeadOnReturnInfo().coversAllReachableMemory()) {
- if (uint64_t DeadOnReturnBytes =
- AI.getDeadOnReturnInfo().getNumberOfDeadBytes())
- InvisibleToCallerAfterRetBounded.insert({&AI, DeadOnReturnBytes});
+ continue;
}
+
+ if (!AI.getType()->isPointerTy())
+ continue;
+
+ const DeadOnReturnInfo &Info = AI.getDeadOnReturnInfo();
+ if (Info.coversAllReachableMemory())
+ InvisibleToCallerAfterRet.insert({&AI, true});
+ else if (uint64_t DeadBytes = Info.getNumberOfDeadBytes())
+ InvisibleToCallerAfterRetBounded.insert({&AI, DeadBytes});
}
// Collect whether there is any irreducible control flow in the function.
@@ -1225,8 +1228,11 @@ struct DSEState {
const Value *BaseValue =
GetPointerBaseWithConstantOffset(Ptr, ValueOffset, DL);
assert(BaseValue == V);
- if (ValueOffset + StoreSize.toRaw() <
- InvisibleToCallerAfterRetBounded[BaseValue])
+ // This store is only invisible after return if we are in bounds of the
+ // range marked dead.
+ if (ValueOffset + StoreSize.getValue() <=
+ InvisibleToCallerAfterRetBounded[BaseValue] &&
+ ValueOffset >= 0)
return true;
}
if (I.second && isInvisibleToCallerOnUnwind(V) && isNoAliasCall(V))
@@ -1899,6 +1905,7 @@ struct DSEState {
if (CapturedBeforeReturn.erase(UO))
ShouldIterateEndOfFunctionDSE = true;
InvisibleToCallerAfterRet.erase(UO);
+ InvisibleToCallerAfterRetBounded.erase(UO);
}
}
}
diff --git a/llvm/test/Transforms/DeadStoreElimination/simple.ll b/llvm/test/Transforms/DeadStoreElimination/simple.ll
index 7619842ea18cf..855cae3f70259 100644
--- a/llvm/test/Transforms/DeadStoreElimination/simple.ll
+++ b/llvm/test/Transforms/DeadStoreElimination/simple.ll
@@ -901,6 +901,18 @@ define void @test_dead_on_return_oob(ptr dead_on_return(4) %p) {
ret void
}
+define void @test_dead_on_return_zero_offset(ptr dead_on_return(8) %p) {
+; CHECK-LABEL: @test_dead_on_return_zero_offset(
+; CHECK-NEXT: [[LOCAL_VAR:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: call void @opaque(ptr [[LOCAL_VAR]])
+; CHECK-NEXT: ret void
+;
+ %local.var = alloca ptr
+ call void @opaque(ptr %local.var)
+ store ptr %local.var, ptr %p
+ ret void
+}
+
define void @test_dead_on_return_inbounds(ptr dead_on_return(16) %p) {
; CHECK-LABEL: @test_dead_on_return_inbounds(
; CHECK-NEXT: [[LOCAL_VAR:%.*]] = alloca ptr, align 8
@@ -914,8 +926,8 @@ define void @test_dead_on_return_inbounds(ptr dead_on_return(16) %p) {
ret void
}
-define void @test_on_return_overlapping_oob(ptr dead_on_return(8) %p) {
-; CHECK-LABEL: @test_on_return_overlapping_oob(
+define void @test_dead_on_return_overlapping_oob(ptr dead_on_return(8) %p) {
+; CHECK-LABEL: @test_dead_on_return_overlapping_oob(
; CHECK-NEXT: [[LOCAL_VAR:%.*]] = alloca ptr, align 8
; CHECK-NEXT: call void @opaque(ptr [[LOCAL_VAR]])
; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 4
@@ -929,5 +941,20 @@ define void @test_on_return_overlapping_oob(ptr dead_on_return(8) %p) {
ret void
}
+define void @test_dead_on_return_negative_oob(ptr dead_on_return(8) %p) {
+; CHECK-LABEL: @test_dead_on_return_negative_oob(
+; CHECK-NEXT: [[LOCAL_VAR:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: call void @opaque(ptr [[LOCAL_VAR]])
+; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 -4
+; CHECK-NEXT: store ptr [[LOCAL_VAR]], ptr [[P1]], align 8
+; CHECK-NEXT: ret void
+;
+ %local.var = alloca ptr
+ call void @opaque(ptr %local.var)
+ %p1 = getelementptr inbounds i8, ptr %p, i64 -4
+ store ptr %local.var, ptr %p1
+ ret void
+}
+
declare void @opaque(ptr)
declare void @maythrow() memory(none)
More information about the llvm-branch-commits
mailing list