Skip to content

Commit 649a4bd

Browse files
committed
[DSE] Optimize defining access of defs while walking upwards.
This patch extends the code that walks memory defs upwards to find clobbering accesses to also try to optimize the clobbering defining access. We should be able to find set the optimized access of our starting def (KillingDef), if the following holds: 1. It is the first call of getDomMemoryDef for KillingDef (so Current == KillingDef->getDefiningAccess(). 2. No potentially aliasing defs are skipped. Then if a (partly) aliasing def is encountered, it can be used as optimized access for KillingDef. No further optimizations can be applied to KillingDef. I'd appreciate a careful look, as the existing documentation is not too clear on what is expected for optimized accesses. The motivation for this patch is to use the optimized accesses to cover more cases of redundant stores as follow-up to D111727. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D112313 (cherry-picked from 25dad10)
1 parent 44b44da commit 649a4bd

File tree

1 file changed

+43
-3
lines changed

1 file changed

+43
-3
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ static cl::opt<unsigned> MemorySSAPathCheckLimit(
157157
cl::desc("The maximum number of blocks to check when trying to prove that "
158158
"all paths to an exit go through a killing block (default = 50)"));
159159

160+
// This flags allows or disallows DSE to optimize MemorySSA during its
161+
// traversal. Note that DSE optimizing MemorySSA may impact other passes
162+
// downstream of the DSE invocation and can lead to issues not being
163+
// reproducible in isolation (i.e. when MemorySSA is built from scratch). In
164+
// those cases, the flag can be used to check if DSE's MemorySSA optimizations
165+
// impact follow-up passes.
166+
static cl::opt<bool>
167+
OptimizeMemorySSA("dse-optimize-memoryssa", cl::init(false), cl::Hidden,
168+
cl::desc("Allow DSE to optimize memory accesses"));
169+
160170
//===----------------------------------------------------------------------===//
161171
// Helper functions
162172
//===----------------------------------------------------------------------===//
@@ -1353,6 +1363,15 @@ struct DSEState {
13531363
Instruction *KillingI = KillingDef->getMemoryInst();
13541364
LLVM_DEBUG(dbgs() << " trying to get dominating access\n");
13551365

1366+
// Only optimize defining access of KillingDef when directly starting at its
1367+
// defining access. The defining access also must only access KillingLoc. At
1368+
// the moment we only support instructions with a single write location, so
1369+
// it should be sufficient to disable optimizations for instructions that
1370+
// also read from memory.
1371+
bool CanOptimize = OptimizeMemorySSA &&
1372+
KillingDef->getDefiningAccess() == StartAccess &&
1373+
!KillingI->mayReadFromMemory();
1374+
13561375
// Find the next clobbering Mod access for DefLoc, starting at StartAccess.
13571376
Optional<MemoryLocation> CurrentLoc;
13581377
for (;; Current = cast<MemoryDef>(Current)->getDefiningAccess()) {
@@ -1393,8 +1412,10 @@ struct DSEState {
13931412
MemoryDef *CurrentDef = cast<MemoryDef>(Current);
13941413
Instruction *CurrentI = CurrentDef->getMemoryInst();
13951414

1396-
if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(KillingUndObj)))
1415+
if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(KillingUndObj))) {
1416+
CanOptimize = false;
13971417
continue;
1418+
}
13981419

13991420
// Before we try to remove anything, check for any extra throwing
14001421
// instructions that block us from DSEing
@@ -1435,29 +1456,48 @@ struct DSEState {
14351456

14361457
// If Current does not have an analyzable write location, skip it
14371458
CurrentLoc = getLocForWriteEx(CurrentI);
1438-
if (!CurrentLoc)
1459+
if (!CurrentLoc) {
1460+
CanOptimize = false;
14391461
continue;
1462+
}
14401463

14411464
// AliasAnalysis does not account for loops. Limit elimination to
14421465
// candidates for which we can guarantee they always store to the same
14431466
// memory location and not located in different loops.
14441467
if (!isGuaranteedLoopIndependent(CurrentI, KillingI, *CurrentLoc)) {
14451468
LLVM_DEBUG(dbgs() << " ... not guaranteed loop independent\n");
14461469
WalkerStepLimit -= 1;
1470+
CanOptimize = false;
14471471
continue;
14481472
}
14491473

14501474
if (IsMemTerm) {
14511475
// If the killing def is a memory terminator (e.g. lifetime.end), check
14521476
// the next candidate if the current Current does not write the same
14531477
// underlying object as the terminator.
1454-
if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI))
1478+
if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI)) {
1479+
CanOptimize = false;
14551480
continue;
1481+
}
14561482
} else {
14571483
int64_t KillingOffset = 0;
14581484
int64_t DeadOffset = 0;
14591485
auto OR = isOverwrite(KillingI, CurrentI, KillingLoc, *CurrentLoc,
14601486
KillingOffset, DeadOffset);
1487+
if (CanOptimize) {
1488+
// CurrentDef is the earliest write clobber of KillingDef. Use it as
1489+
// optimized access. Do not optimize if CurrentDef is already the
1490+
// defining access of KillingDef.
1491+
if (CurrentDef != KillingDef->getDefiningAccess() &&
1492+
(OR == OW_Complete || OR == OW_MaybePartial))
1493+
KillingDef->setOptimized(CurrentDef);
1494+
1495+
// Once a may-aliasing def is encountered do not set an optimized
1496+
// access.
1497+
if (OR != OW_None)
1498+
CanOptimize = false;
1499+
}
1500+
14611501
// If Current does not write to the same object as KillingDef, check
14621502
// the next candidate.
14631503
if (OR == OW_Unknown || OR == OW_None)

0 commit comments

Comments
 (0)