[llvm] fed817a - [DSE] Consider the aliasing through global variable while checking clobber (#120044)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 14 10:04:47 PST 2025
Author: Haopeng Liu
Date: 2025-01-14T10:04:41-08:00
New Revision: fed817a8b25e178cd701fefcdfe80c447d2ab212
URL: https://github.com/llvm/llvm-project/commit/fed817a8b25e178cd701fefcdfe80c447d2ab212
DIFF: https://github.com/llvm/llvm-project/commit/fed817a8b25e178cd701fefcdfe80c447d2ab212.diff
LOG: [DSE] Consider the aliasing through global variable while checking clobber (#120044)
While update the read clobber check for the "initializes" attr, we
checked the aliasing among arguments, but didn't consider the aliasing
through global variable. It causes problems in this example:
```
int g_var = 123;
void update(int* ptr) {
*ptr = g_var;
void foo() {
g_var = 0;
bar(&g_var);
}
```
We mistakenly removed `g_var = 0;` as a dead store.
Fix the issue by requiring the CallBase only access argmem or
inaccessiblemem.
Added:
Modified:
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index cae5b9c41a37f1..241c57e88b447e 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -2262,6 +2262,14 @@ struct DSEState {
bool eliminateDeadDefs(const MemoryDefWrapper &KillingDefWrapper);
};
+// Return true if "Arg" is function local and isn't captured before "CB".
+bool isFuncLocalAndNotCaptured(Value *Arg, const CallBase *CB,
+ EarliestEscapeAnalysis &EA) {
+ const Value *UnderlyingObj = getUnderlyingObject(Arg);
+ return isIdentifiedFunctionLocal(UnderlyingObj) &&
+ EA.isNotCapturedBefore(UnderlyingObj, CB, /*OrAt*/ true);
+}
+
SmallVector<MemoryLocation, 1>
DSEState::getInitializesArgMemLoc(const Instruction *I) {
const CallBase *CB = dyn_cast<CallBase>(I);
@@ -2277,6 +2285,13 @@ DSEState::getInitializesArgMemLoc(const Instruction *I) {
Inits = InitializesAttr.getValueAsConstantRangeList();
Value *CurArg = CB->getArgOperand(Idx);
+ // Check whether "CurArg" could alias with global variables. We require
+ // either it's function local and isn't captured before or the "CB" only
+ // accesses arg or inaccessible mem.
+ if (!Inits.empty() && !CB->onlyAccessesInaccessibleMemOrArgMem() &&
+ !isFuncLocalAndNotCaptured(CurArg, CB, EA))
+ Inits = ConstantRangeList();
+
// We don't perform incorrect DSE on unwind edges in the current function,
// and use the "initializes" attribute to kill dead stores if:
// - The call does not throw exceptions, "CB->doesNotThrow()".
diff --git a/llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll b/llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll
index d93da9b6612b05..e590c5bf4004af 100644
--- a/llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll
+++ b/llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll
@@ -39,6 +39,25 @@ define i16 @p1_write_then_read_caller() {
ret i16 %l
}
+declare void @fn_capture(ptr)
+define i16 @p1_write_then_read_caller_escape() {
+; CHECK-LABEL: @p1_write_then_read_caller_escape(
+; CHECK-NEXT: [[PTR:%.*]] = alloca i16, align 2
+; CHECK-NEXT: store i16 0, ptr [[PTR]], align 2
+; CHECK-NEXT: call void @fn_capture(ptr [[PTR]])
+; CHECK-NEXT: call void @p1_write_then_read(ptr [[PTR]])
+; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[PTR]], align 2
+; CHECK-NEXT: ret i16 [[L]]
+;
+ %ptr = alloca i16
+ store i16 0, ptr %ptr
+ call void @fn_capture(ptr %ptr)
+ call void @p1_write_then_read(ptr %ptr)
+ %l = load i16, ptr %ptr
+ ret i16 %l
+}
+
+
; Function Attrs: mustprogress nounwind uwtable
define i16 @p1_write_then_read_caller_with_clobber() {
; CHECK-LABEL: @p1_write_then_read_caller_with_clobber(
@@ -221,15 +240,17 @@ declare void @large_p2(ptr nocapture noundef initializes((0, 200)), ptr nocaptur
; Function Attrs: mustprogress nounwind uwtable
define i16 @large_p1_caller() {
; CHECK-LABEL: @large_p1_caller(
-; CHECK-NEXT: [[PTR:%.*]] = alloca [200 x i8], align 1
-; CHECK-NEXT: call void @large_p1(ptr [[PTR]])
-; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[PTR]], align 2
+; CHECK-NEXT: [[PTR:%.*]] = alloca [300 x i8], align 1
+; CHECK-NEXT: [[TMP:%.*]] = getelementptr i8, ptr [[PTR]], i64 100
+; CHECK-NEXT: call void @large_p1(ptr [[TMP]])
+; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[TMP]], align 2
; CHECK-NEXT: ret i16 [[L]]
;
- %ptr = alloca [200 x i8]
- call void @llvm.memset.p0.i64(ptr %ptr, i8 42, i64 100, i1 false)
- call void @large_p1(ptr %ptr)
- %l = load i16, ptr %ptr
+ %ptr = alloca [300 x i8]
+ %tmp = getelementptr i8, ptr %ptr, i64 100
+ call void @llvm.memset.p0.i64(ptr %tmp, i8 42, i64 100, i1 false)
+ call void @large_p1(ptr %tmp)
+ %l = load i16, ptr %tmp
ret i16 %l
}
@@ -299,3 +320,21 @@ define i16 @large_p2_may_or_partial_alias_caller2(ptr %base1, ptr %base2) {
ret i16 %l
}
+ at g = global i16 123, align 2
+
+declare void @read_global(ptr nocapture noundef initializes((0, 2))) nounwind
+ memory(read, argmem: write, inaccessiblemem: none) nounwind
+
+define i16 @global_var_alias() {
+; CHECK-LABEL: @global_var_alias(
+; CHECK-NEXT: store i16 0, ptr @g, align 4
+; CHECK-NEXT: call void @read_global(ptr @g)
+; CHECK-NEXT: [[L:%.*]] = load i16, ptr @g, align 2
+; CHECK-NEXT: ret i16 [[L]]
+;
+ store i16 0, ptr @g, align 4
+ call void @read_global(ptr @g)
+ %l = load i16, ptr @g
+ ret i16 %l
+}
+
More information about the llvm-commits
mailing list