Skip to content

Commit 25dad10

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
1 parent 9f374a7 commit 25dad10

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
@@ -159,6 +159,16 @@ static cl::opt<unsigned> MemorySSAPathCheckLimit(
159159
cl::desc("The maximum number of blocks to check when trying to prove that "
160160
"all paths to an exit go through a killing block (default = 50)"));
161161

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

1286+
// Only optimize defining access of KillingDef when directly starting at its
1287+
// defining access. The defining access also must only access KillingLoc. At
1288+
// the moment we only support instructions with a single write location, so
1289+
// it should be sufficient to disable optimizations for instructions that
1290+
// also read from memory.
1291+
bool CanOptimize = OptimizeMemorySSA &&
1292+
KillingDef->getDefiningAccess() == StartAccess &&
1293+
!KillingI->mayReadFromMemory();
1294+
12761295
// Find the next clobbering Mod access for DefLoc, starting at StartAccess.
12771296
Optional<MemoryLocation> CurrentLoc;
12781297
for (;; Current = cast<MemoryDef>(Current)->getDefiningAccess()) {
@@ -1314,8 +1333,10 @@ struct DSEState {
13141333
Instruction *CurrentI = CurrentDef->getMemoryInst();
13151334

13161335
if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(KillingUndObj),
1317-
TLI))
1336+
TLI)) {
1337+
CanOptimize = false;
13181338
continue;
1339+
}
13191340

13201341
// Before we try to remove anything, check for any extra throwing
13211342
// instructions that block us from DSEing
@@ -1352,29 +1373,48 @@ struct DSEState {
13521373
// If Current does not have an analyzable write location or is not
13531374
// removable, skip it.
13541375
CurrentLoc = getLocForWriteEx(CurrentI);
1355-
if (!CurrentLoc || !isRemovable(CurrentI))
1376+
if (!CurrentLoc || !isRemovable(CurrentI)) {
1377+
CanOptimize = false;
13561378
continue;
1379+
}
13571380

13581381
// AliasAnalysis does not account for loops. Limit elimination to
13591382
// candidates for which we can guarantee they always store to the same
13601383
// memory location and not located in different loops.
13611384
if (!isGuaranteedLoopIndependent(CurrentI, KillingI, *CurrentLoc)) {
13621385
LLVM_DEBUG(dbgs() << " ... not guaranteed loop independent\n");
13631386
WalkerStepLimit -= 1;
1387+
CanOptimize = false;
13641388
continue;
13651389
}
13661390

13671391
if (IsMemTerm) {
13681392
// If the killing def is a memory terminator (e.g. lifetime.end), check
13691393
// the next candidate if the current Current does not write the same
13701394
// underlying object as the terminator.
1371-
if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI))
1395+
if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI)) {
1396+
CanOptimize = false;
13721397
continue;
1398+
}
13731399
} else {
13741400
int64_t KillingOffset = 0;
13751401
int64_t DeadOffset = 0;
13761402
auto OR = isOverwrite(KillingI, CurrentI, KillingLoc, *CurrentLoc,
13771403
KillingOffset, DeadOffset);
1404+
if (CanOptimize) {
1405+
// CurrentDef is the earliest write clobber of KillingDef. Use it as
1406+
// optimized access. Do not optimize if CurrentDef is already the
1407+
// defining access of KillingDef.
1408+
if (CurrentDef != KillingDef->getDefiningAccess() &&
1409+
(OR == OW_Complete || OR == OW_MaybePartial))
1410+
KillingDef->setOptimized(CurrentDef);
1411+
1412+
// Once a may-aliasing def is encountered do not set an optimized
1413+
// access.
1414+
if (OR != OW_None)
1415+
CanOptimize = false;
1416+
}
1417+
13781418
// If Current does not write to the same object as KillingDef, check
13791419
// the next candidate.
13801420
if (OR == OW_Unknown || OR == OW_None)

0 commit comments

Comments
 (0)