Skip to content

Commit fa652d9

Browse files
committed
Check whether an arg can from Alloca that doesn't escape
1 parent 69d43a5 commit fa652d9

File tree

2 files changed

+53
-31
lines changed

2 files changed

+53
-31
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,16 +1665,11 @@ struct DSEState {
16651665
// original MD. Stop walk.
16661666
// If KillingDef is a CallInst with "initializes" attribute, the reads in
16671667
// the callee would be dominated by initializations, so it should be safe.
1668-
// Note that in `getInitializesArgMemLoc`, we only check the aliasing
1669-
// among arguments. If aliasing through global variables, we consider it
1670-
// as read clobber.
16711668
bool IsKillingDefFromInitAttr = false;
16721669
if (IsInitializesAttrMemLoc) {
1673-
if (auto *CB = dyn_cast<CallBase>(UseInst))
1674-
IsKillingDefFromInitAttr =
1675-
KillingI == UseInst &&
1676-
KillingUndObj == getUnderlyingObject(MaybeDeadLoc.Ptr) &&
1677-
CB->onlyAccessesInaccessibleMemOrArgMem();
1670+
if (KillingI == UseInst &&
1671+
KillingUndObj == getUnderlyingObject(MaybeDeadLoc.Ptr))
1672+
IsKillingDefFromInitAttr = true;
16781673
}
16791674

16801675
if (isReadClobber(MaybeDeadLoc, UseInst) && !IsKillingDefFromInitAttr) {
@@ -2266,6 +2261,39 @@ struct DSEState {
22662261
bool eliminateDeadDefs(const MemoryDefWrapper &KillingDefWrapper);
22672262
};
22682263

2264+
// Return true if "Arg" is an Alloca or GEP from Alloca, and the alloca ptr
2265+
// doesn't escape.
2266+
bool ValidFromAlloca(Value *Arg) {
2267+
const auto *AI = dyn_cast<AllocaInst>(Arg);
2268+
const auto *GEP = dyn_cast<GetElementPtrInst>(Arg);
2269+
if (!AI) {
2270+
if (!GEP || !dyn_cast<AllocaInst>(GEP->getPointerOperand()))
2271+
return false;
2272+
}
2273+
2274+
// No need for a visited set as we don't look through phis.
2275+
SmallVector<Use *, 4> Worklist;
2276+
for (Use &U : Arg->uses())
2277+
Worklist.push_back(&U);
2278+
2279+
while (!Worklist.empty()) {
2280+
Use *U = Worklist.pop_back_val();
2281+
Instruction *I = cast<Instruction>(U->getUser());
2282+
2283+
if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) {
2284+
for (Use &U : GEP->uses())
2285+
Worklist.push_back(&U);
2286+
} else if (auto *CB = dyn_cast<CallBase>(I)) {
2287+
if (CB->isArgOperand(U)) {
2288+
unsigned ArgNo = CB->getArgOperandNo(U);
2289+
if (!CB->paramHasAttr(ArgNo, Attribute::NoCapture))
2290+
return false;
2291+
}
2292+
}
2293+
}
2294+
return true;
2295+
}
2296+
22692297
SmallVector<MemoryLocation, 1>
22702298
DSEState::getInitializesArgMemLoc(const Instruction *I) {
22712299
const CallBase *CB = dyn_cast<CallBase>(I);
@@ -2281,6 +2309,13 @@ DSEState::getInitializesArgMemLoc(const Instruction *I) {
22812309
Inits = InitializesAttr.getValueAsConstantRangeList();
22822310

22832311
Value *CurArg = CB->getArgOperand(Idx);
2312+
// Check whether "CurArg" could alias with global variables. We require
2313+
// either it's an Alloca that doesn't escape or the "CB" only accesses arg
2314+
// or inaccessible mem.
2315+
if (!Inits.empty() && !ValidFromAlloca(CurArg) &&
2316+
!CB->onlyAccessesInaccessibleMemOrArgMem())
2317+
Inits = ConstantRangeList();
2318+
22842319
// We don't perform incorrect DSE on unwind edges in the current function,
22852320
// and use the "initializes" attribute to kill dead stores if:
22862321
// - The call does not throw exceptions, "CB->doesNotThrow()".

llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,12 @@
22
; RUN: opt < %s -passes=dse -enable-dse-initializes-attr-improvement -S | FileCheck %s
33

44
declare void @p1_write_only(ptr nocapture noundef writeonly initializes((0, 2)) dead_on_unwind)
5-
65
declare void @p1_write_then_read(ptr nocapture noundef initializes((0, 2)) dead_on_unwind)
7-
memory(argmem: readwrite, inaccessiblemem: readwrite)
8-
96
declare void @p1_clobber(ptr nocapture noundef)
10-
117
declare void @p2_same_range(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef initializes((0, 2)) dead_on_unwind)
12-
memory(argmem: readwrite, inaccessiblemem: readwrite)
13-
148
declare void @p2_no_init(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef dead_on_unwind)
15-
169
declare void @p2_no_dead_on_unwind(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef initializes((0, 2)))
17-
memory(argmem: readwrite, inaccessiblemem: readwrite)
18-
1910
declare void @p2_no_dead_on_unwind_but_nounwind(ptr nocapture noundef initializes((0, 2)) dead_on_unwind, ptr nocapture noundef initializes((0, 2))) nounwind
20-
memory(argmem: readwrite, inaccessiblemem: readwrite)
2111

2212
; Function Attrs: mustprogress nounwind uwtable
2313
define i16 @p1_write_only_caller() {
@@ -225,25 +215,23 @@ define i16 @p2_no_dead_on_unwind_but_nounwind_alias_caller() {
225215
}
226216

227217
declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
228-
229218
declare void @large_p1(ptr nocapture noundef initializes((0, 200))) nounwind
230-
memory(argmem: readwrite, inaccessiblemem: readwrite)
231-
232219
declare void @large_p2(ptr nocapture noundef initializes((0, 200)), ptr nocapture noundef initializes((0, 100))) nounwind
233-
memory(argmem: readwrite, inaccessiblemem: readwrite)
234220

235221
; Function Attrs: mustprogress nounwind uwtable
236222
define i16 @large_p1_caller() {
237223
; CHECK-LABEL: @large_p1_caller(
238-
; CHECK-NEXT: [[PTR:%.*]] = alloca [200 x i8], align 1
239-
; CHECK-NEXT: call void @large_p1(ptr [[PTR]])
240-
; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[PTR]], align 2
224+
; CHECK-NEXT: [[PTR:%.*]] = alloca [300 x i8], align 1
225+
; CHECK-NEXT: [[TMP:%.*]] = getelementptr i8, ptr [[PTR]], i64 100
226+
; CHECK-NEXT: call void @large_p1(ptr [[TMP]])
227+
; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[TMP]], align 2
241228
; CHECK-NEXT: ret i16 [[L]]
242229
;
243-
%ptr = alloca [200 x i8]
244-
call void @llvm.memset.p0.i64(ptr %ptr, i8 42, i64 100, i1 false)
245-
call void @large_p1(ptr %ptr)
246-
%l = load i16, ptr %ptr
230+
%ptr = alloca [300 x i8]
231+
%tmp = getelementptr i8, ptr %ptr, i64 100
232+
call void @llvm.memset.p0.i64(ptr %tmp, i8 42, i64 100, i1 false)
233+
call void @large_p1(ptr %tmp)
234+
%l = load i16, ptr %tmp
247235
ret i16 %l
248236
}
249237

@@ -315,8 +303,7 @@ define i16 @large_p2_may_or_partial_alias_caller2(ptr %base1, ptr %base2) {
315303

316304
@g = global i16 123, align 2
317305

318-
declare void @read_global(ptr nocapture noundef initializes((0, 2)))
319-
memory(read, argmem: write, inaccessiblemem: none) nounwind
306+
declare void @read_global(ptr nocapture noundef initializes((0, 2))) nounwind
320307

321308
define i16 @global_var_alias() {
322309
; CHECK-LABEL: @global_var_alias(

0 commit comments

Comments
 (0)