Skip to content

Commit efe8aa2

Browse files
committed
Revert "Reapply "Revert "[MemCpyOpt] implement multi BB stack-move optimization""
Suspecting incorrect lifetime markers. This reverts commit 3a1409f.
1 parent cf29d0a commit efe8aa2

File tree

7 files changed

+118
-211
lines changed

7 files changed

+118
-211
lines changed

llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ class MemMoveInst;
3434
class MemorySSA;
3535
class MemorySSAUpdater;
3636
class MemSetInst;
37-
class PostDominatorTree;
3837
class StoreInst;
3938
class TargetLibraryInfo;
4039
class Value;
@@ -44,7 +43,6 @@ class MemCpyOptPass : public PassInfoMixin<MemCpyOptPass> {
4443
AAResults *AA = nullptr;
4544
AssumptionCache *AC = nullptr;
4645
DominatorTree *DT = nullptr;
47-
PostDominatorTree *PDT = nullptr;
4846
MemorySSA *MSSA = nullptr;
4947
MemorySSAUpdater *MSSAU = nullptr;
5048

@@ -55,8 +53,7 @@ class MemCpyOptPass : public PassInfoMixin<MemCpyOptPass> {
5553

5654
// Glue for the old PM.
5755
bool runImpl(Function &F, TargetLibraryInfo *TLI, AAResults *AA,
58-
AssumptionCache *AC, DominatorTree *DT, PostDominatorTree *PDT,
59-
MemorySSA *MSSA);
56+
AssumptionCache *AC, DominatorTree *DT, MemorySSA *MSSA);
6057

6158
private:
6259
// Helper functions

llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp

Lines changed: 46 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@
1919
#include "llvm/ADT/iterator_range.h"
2020
#include "llvm/Analysis/AliasAnalysis.h"
2121
#include "llvm/Analysis/AssumptionCache.h"
22-
#include "llvm/Analysis/CFG.h"
2322
#include "llvm/Analysis/CaptureTracking.h"
2423
#include "llvm/Analysis/GlobalsModRef.h"
2524
#include "llvm/Analysis/Loads.h"
2625
#include "llvm/Analysis/MemoryLocation.h"
2726
#include "llvm/Analysis/MemorySSA.h"
2827
#include "llvm/Analysis/MemorySSAUpdater.h"
29-
#include "llvm/Analysis/PostDominators.h"
3028
#include "llvm/Analysis/TargetLibraryInfo.h"
3129
#include "llvm/Analysis/ValueTracking.h"
3230
#include "llvm/IR/BasicBlock.h"
@@ -1417,74 +1415,6 @@ bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy,
14171415
return true;
14181416
}
14191417

1420-
using InsertionPt = PointerUnion<Instruction *, BasicBlock *>;
1421-
/// Find the nearest Instruction or BasicBlock that dominates both I1 and
1422-
/// I2.
1423-
static InsertionPt findNearestCommonDominator(InsertionPt I1, InsertionPt I2,
1424-
DominatorTree *DT) {
1425-
auto GetParent = [](InsertionPt I) {
1426-
if (auto *BB = dyn_cast<BasicBlock *>(I))
1427-
return BB;
1428-
return cast<Instruction *>(I)->getParent();
1429-
};
1430-
BasicBlock *BB1 = GetParent(I1);
1431-
BasicBlock *BB2 = GetParent(I2);
1432-
if (BB1 == BB2) {
1433-
// BasicBlock InsertionPt means the terminator.
1434-
if (isa<BasicBlock *>(I1))
1435-
return I2;
1436-
if (isa<BasicBlock *>(I2))
1437-
return I1;
1438-
return cast<Instruction *>(I1)->comesBefore(cast<Instruction *>(I2)) ? I1
1439-
: I2;
1440-
}
1441-
1442-
// These checks are necessary, because findNearestCommonDominator for NodeT
1443-
// doesn't handle these.
1444-
if (!DT->isReachableFromEntry(BB2))
1445-
return I1;
1446-
if (!DT->isReachableFromEntry(BB1))
1447-
return I2;
1448-
1449-
BasicBlock *DomBB = DT->findNearestCommonDominator(BB1, BB2);
1450-
if (BB2 == DomBB)
1451-
return I2;
1452-
if (BB1 == DomBB)
1453-
return I1;
1454-
return DomBB;
1455-
}
1456-
1457-
/// Find the nearest Instruction or BasicBlock that post-dominates both I1 and
1458-
/// I2.
1459-
static InsertionPt findNearestCommonPostDominator(InsertionPt I1,
1460-
InsertionPt I2,
1461-
PostDominatorTree *PDT) {
1462-
auto GetParent = [](InsertionPt I) {
1463-
if (auto *BB = dyn_cast<BasicBlock *>(I))
1464-
return BB;
1465-
return cast<Instruction *>(I)->getParent();
1466-
};
1467-
BasicBlock *BB1 = GetParent(I1);
1468-
BasicBlock *BB2 = GetParent(I2);
1469-
if (BB1 == BB2) {
1470-
// BasicBlock InsertionPt means the first non-phi instruction.
1471-
if (isa<BasicBlock *>(I1))
1472-
return I2;
1473-
if (isa<BasicBlock *>(I2))
1474-
return I1;
1475-
return cast<Instruction *>(I1)->comesBefore(cast<Instruction *>(I2)) ? I2
1476-
: I1;
1477-
}
1478-
BasicBlock *PDomBB = PDT->findNearestCommonDominator(BB1, BB2);
1479-
if (!PDomBB)
1480-
return nullptr;
1481-
if (BB2 == PDomBB)
1482-
return I2;
1483-
if (BB1 == PDomBB)
1484-
return I1;
1485-
return PDomBB;
1486-
}
1487-
14881418
// Attempts to optimize the pattern whereby memory is copied from an alloca to
14891419
// another alloca, where the two allocas don't have conflicting mod/ref. If
14901420
// successful, the two allocas can be merged into one and the transfer can be
@@ -1510,7 +1440,8 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
15101440
return false;
15111441
}
15121442

1513-
// Check that copy is full with static size.
1443+
// 1. Check that copy is full. Calculate the static size of the allocas to be
1444+
// merged, bail out if we can't.
15141445
const DataLayout &DL = DestAlloca->getModule()->getDataLayout();
15151446
std::optional<TypeSize> SrcSize = SrcAlloca->getAllocationSize(DL);
15161447
if (!SrcSize || SrcSize->isScalable() || Size != SrcSize->getFixedValue()) {
@@ -1524,16 +1455,19 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
15241455
return false;
15251456
}
15261457

1527-
if (!SrcAlloca->isStaticAlloca() || !DestAlloca->isStaticAlloca())
1458+
// 2-1. Check that src and dest are static allocas, which are not affected by
1459+
// stacksave/stackrestore.
1460+
if (!SrcAlloca->isStaticAlloca() || !DestAlloca->isStaticAlloca() ||
1461+
SrcAlloca->getParent() != Load->getParent() ||
1462+
SrcAlloca->getParent() != Store->getParent())
15281463
return false;
15291464

1530-
// Check that src and dest are never captured, unescaped allocas. Also
1531-
// find the nearest common dominator and postdominator for all users in
1532-
// order to shrink wrap the lifetimes, and instructions with noalias metadata
1533-
// to remove them.
1465+
// 2-2. Check that src and dest are never captured, unescaped allocas. Also
1466+
// collect lifetime markers first/last users in order to shrink wrap the
1467+
// lifetimes, and instructions with noalias metadata to remove them.
15341468

15351469
SmallVector<Instruction *, 4> LifetimeMarkers;
1536-
InsertionPt Dom = nullptr, PDom = nullptr;
1470+
Instruction *FirstUser = nullptr, *LastUser = nullptr;
15371471
SmallSet<Instruction *, 4> NoAliasInstrs;
15381472

15391473
// Recursively track the user and check whether modified alias exist.
@@ -1571,13 +1505,12 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
15711505
continue;
15721506
case UseCaptureKind::NO_CAPTURE: {
15731507
auto *UI = cast<Instruction>(U.getUser());
1574-
if (!Dom) {
1575-
PDom = Dom = UI;
1576-
} else {
1577-
Dom = findNearestCommonDominator(Dom, UI, DT);
1578-
if (PDom)
1579-
PDom = findNearestCommonPostDominator(PDom, UI, PDT);
1580-
}
1508+
if (DestAlloca->getParent() != UI->getParent())
1509+
return false;
1510+
if (!FirstUser || UI->comesBefore(FirstUser))
1511+
FirstUser = UI;
1512+
if (!LastUser || LastUser->comesBefore(UI))
1513+
LastUser = UI;
15811514
if (UI->isLifetimeStartOrEnd()) {
15821515
// We note the locations of these intrinsic calls so that we can
15831516
// delete them later if the optimization succeeds, this is safe
@@ -1601,64 +1534,37 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
16011534
return true;
16021535
};
16031536

1604-
// Check that dest has no Mod/Ref, from the alloca to the Store, except full
1605-
// size lifetime intrinsics. And collect modref inst for the reachability
1606-
// check.
1537+
// 3. Check that dest has no Mod/Ref, except full size lifetime intrinsics,
1538+
// from the alloca to the Store.
16071539
ModRefInfo DestModRef = ModRefInfo::NoModRef;
16081540
MemoryLocation DestLoc(DestAlloca, LocationSize::precise(Size));
1609-
SmallVector<BasicBlock *, 8> ReachabilityWorklist;
16101541
auto DestModRefCallback = [&](Instruction *UI) -> bool {
16111542
// We don't care about the store itself.
16121543
if (UI == Store)
16131544
return true;
16141545
ModRefInfo Res = BAA.getModRefInfo(UI, DestLoc);
1615-
DestModRef |= Res;
1616-
if (isModOrRefSet(Res)) {
1617-
// Instructions reachability checks.
1618-
// FIXME: adding the Instruction version isPotentiallyReachableFromMany on
1619-
// lib/Analysis/CFG.cpp (currently only for BasicBlocks) might be helpful.
1620-
if (UI->getParent() == Store->getParent()) {
1621-
// The same block case is special because it's the only time we're
1622-
// looking within a single block to see which instruction comes first.
1623-
// Once we start looking at multiple blocks, the first instruction of
1624-
// the block is reachable, so we only need to determine reachability
1625-
// between whole blocks.
1626-
BasicBlock *BB = UI->getParent();
1627-
1628-
// If A comes before B, then B is definitively reachable from A.
1629-
if (UI->comesBefore(Store))
1630-
return false;
1631-
1632-
// If the user's parent block is entry, no predecessor exists.
1633-
if (BB->isEntryBlock())
1634-
return true;
1546+
// FIXME: For multi-BB cases, we need to see reachability from it to
1547+
// store.
1548+
// Bailout if Dest may have any ModRef before Store.
1549+
if (UI->comesBefore(Store) && isModOrRefSet(Res))
1550+
return false;
1551+
DestModRef |= BAA.getModRefInfo(UI, DestLoc);
16351552

1636-
// Otherwise, continue doing the normal per-BB CFG walk.
1637-
ReachabilityWorklist.append(succ_begin(BB), succ_end(BB));
1638-
} else {
1639-
ReachabilityWorklist.push_back(UI->getParent());
1640-
}
1641-
}
16421553
return true;
16431554
};
16441555

16451556
if (!CaptureTrackingWithModRef(DestAlloca, DestModRefCallback))
16461557
return false;
1647-
// Bailout if Dest may have any ModRef before Store.
1648-
if (!ReachabilityWorklist.empty() &&
1649-
isPotentiallyReachableFromMany(ReachabilityWorklist, Store->getParent(),
1650-
nullptr, DT, nullptr))
1651-
return false;
16521558

1653-
// Check that, from after the Load to the end of the BB,
1654-
// - if the dest has any Mod, src has no Ref, and
1655-
// - if the dest has any Ref, src has no Mod except full-sized lifetimes.
1559+
// 3. Check that, from after the Load to the end of the BB,
1560+
// 3-1. if the dest has any Mod, src has no Ref, and
1561+
// 3-2. if the dest has any Ref, src has no Mod except full-sized lifetimes.
16561562
MemoryLocation SrcLoc(SrcAlloca, LocationSize::precise(Size));
16571563

16581564
auto SrcModRefCallback = [&](Instruction *UI) -> bool {
1659-
// Any ModRef post-dominated by Load doesn't matter, also Load and Store
1660-
// themselves can be ignored.
1661-
if (PDT->dominates(Load, UI) || UI == Load || UI == Store)
1565+
// Any ModRef before Load doesn't matter, also Load and Store can be
1566+
// ignored.
1567+
if (UI->comesBefore(Load) || UI == Load || UI == Store)
16621568
return true;
16631569
ModRefInfo Res = BAA.getModRefInfo(UI, SrcLoc);
16641570
if ((isModSet(DestModRef) && isRefSet(Res)) ||
@@ -1690,48 +1596,22 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
16901596
ConstantInt *AllocaSize = ConstantInt::get(Type::getInt64Ty(C), Size);
16911597
// Create a new lifetime start marker before the first user of src or alloca
16921598
// users.
1693-
MemoryAccess *StartMA;
1694-
if (auto *DomI = dyn_cast_if_present<Instruction *>(Dom)) {
1695-
Builder.SetInsertPoint(DomI->getParent(), DomI->getIterator());
1696-
auto *Start = Builder.CreateLifetimeStart(SrcAlloca, AllocaSize);
1697-
StartMA = MSSAU->createMemoryAccessBefore(Start, nullptr,
1698-
MSSA->getMemoryAccess(DomI));
1699-
} else {
1700-
auto *DomB = cast<BasicBlock *>(Dom);
1701-
Builder.SetInsertPoint(DomB->getTerminator());
1702-
auto *Start = Builder.CreateLifetimeStart(SrcAlloca, AllocaSize);
1703-
StartMA = MSSAU->createMemoryAccessInBB(
1704-
Start, nullptr, Start->getParent(), MemorySSA::BeforeTerminator);
1705-
}
1599+
Builder.SetInsertPoint(FirstUser->getParent(), FirstUser->getIterator());
1600+
auto *Start = Builder.CreateLifetimeStart(SrcAlloca, AllocaSize);
1601+
auto *FirstMA = MSSA->getMemoryAccess(FirstUser);
1602+
auto *StartMA = MSSAU->createMemoryAccessBefore(Start, nullptr, FirstMA);
17061603
MSSAU->insertDef(cast<MemoryDef>(StartMA), /*RenameUses=*/true);
17071604

17081605
// Create a new lifetime end marker after the last user of src or alloca
1709-
// users. If there's no such postdominator, just don't bother; we could
1710-
// create one at each exit block, but that'd be essentially semantically
1711-
// meaningless.
1712-
// If the PDom is the terminator (e.g. invoke), see the next immediate post
1713-
// dominator.
1714-
if (auto *PDomI = dyn_cast_if_present<Instruction *>(PDom);
1715-
PDomI && PDomI->isTerminator()) {
1716-
auto *IPDomNode = (*PDT)[PDomI->getParent()]->getIDom();
1717-
PDom = IPDomNode ? IPDomNode->getBlock() : nullptr;
1718-
}
1719-
if (PDom) {
1720-
MemoryAccess *EndMA;
1721-
if (auto *PDomI = dyn_cast<Instruction *>(PDom)) {
1722-
// If PDom is Instruction ptr, insert after it, because it's a user of
1723-
// SrcAlloca.
1724-
Builder.SetInsertPoint(PDomI->getParent(), ++PDomI->getIterator());
1725-
auto *End = Builder.CreateLifetimeEnd(SrcAlloca, AllocaSize);
1726-
EndMA = MSSAU->createMemoryAccessAfter(End, nullptr,
1727-
MSSA->getMemoryAccess(PDomI));
1728-
} else {
1729-
auto *PDomB = cast<BasicBlock *>(PDom);
1730-
Builder.SetInsertPoint(PDomB, PDomB->getFirstInsertionPt());
1731-
auto *End = Builder.CreateLifetimeEnd(SrcAlloca, AllocaSize);
1732-
EndMA = MSSAU->createMemoryAccessInBB(End, nullptr, End->getParent(),
1733-
MemorySSA::Beginning);
1734-
}
1606+
// users.
1607+
// FIXME: If the last user is the terminator for the bb, we can insert
1608+
// lifetime.end marker to the immidiate post-dominator, but currently do
1609+
// nothing.
1610+
if (!LastUser->isTerminator()) {
1611+
Builder.SetInsertPoint(LastUser->getParent(), ++LastUser->getIterator());
1612+
auto *End = Builder.CreateLifetimeEnd(SrcAlloca, AllocaSize);
1613+
auto *LastMA = MSSA->getMemoryAccess(LastUser);
1614+
auto *EndMA = MSSAU->createMemoryAccessAfter(End, nullptr, LastMA);
17351615
MSSAU->insertDef(cast<MemoryDef>(EndMA), /*RenameUses=*/true);
17361616
}
17371617

@@ -2119,10 +1999,9 @@ PreservedAnalyses MemCpyOptPass::run(Function &F, FunctionAnalysisManager &AM) {
21191999
auto *AA = &AM.getResult<AAManager>(F);
21202000
auto *AC = &AM.getResult<AssumptionAnalysis>(F);
21212001
auto *DT = &AM.getResult<DominatorTreeAnalysis>(F);
2122-
auto *PDT = &AM.getResult<PostDominatorTreeAnalysis>(F);
21232002
auto *MSSA = &AM.getResult<MemorySSAAnalysis>(F);
21242003

2125-
bool MadeChange = runImpl(F, &TLI, AA, AC, DT, PDT, &MSSA->getMSSA());
2004+
bool MadeChange = runImpl(F, &TLI, AA, AC, DT, &MSSA->getMSSA());
21262005
if (!MadeChange)
21272006
return PreservedAnalyses::all();
21282007

@@ -2134,14 +2013,12 @@ PreservedAnalyses MemCpyOptPass::run(Function &F, FunctionAnalysisManager &AM) {
21342013

21352014
bool MemCpyOptPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
21362015
AliasAnalysis *AA_, AssumptionCache *AC_,
2137-
DominatorTree *DT_, PostDominatorTree *PDT_,
2138-
MemorySSA *MSSA_) {
2016+
DominatorTree *DT_, MemorySSA *MSSA_) {
21392017
bool MadeChange = false;
21402018
TLI = TLI_;
21412019
AA = AA_;
21422020
AC = AC_;
21432021
DT = DT_;
2144-
PDT = PDT_;
21452022
MSSA = MSSA_;
21462023
MemorySSAUpdater MSSAU_(MSSA_);
21472024
MSSAU = &MSSAU_;

llvm/test/Other/new-pm-defaults.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@
190190
; CHECK-O23SZ-NEXT: Running pass: GVNPass
191191
; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis
192192
; CHECK-O1-NEXT: Running pass: MemCpyOptPass
193-
; CHECK-O1-NEXT: Running analysis: PostDominatorTreeAnalysis
194193
; CHECK-O-NEXT: Running pass: SCCPPass
195194
; CHECK-O-NEXT: Running pass: BDCEPass
196195
; CHECK-O-NEXT: Running analysis: DemandedBitsAnalysis
@@ -202,7 +201,7 @@
202201
; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis
203202
; CHECK-O1-NEXT: Running pass: CoroElidePass
204203
; CHECK-O-NEXT: Running pass: ADCEPass
205-
; CHECK-O23SZ-NEXT: Running analysis: PostDominatorTreeAnalysis
204+
; CHECK-O-NEXT: Running analysis: PostDominatorTreeAnalysis
206205
; CHECK-O23SZ-NEXT: Running pass: MemCpyOptPass
207206
; CHECK-O23SZ-NEXT: Running pass: DSEPass
208207
; CHECK-O23SZ-NEXT: Running pass: MoveAutoInitPass on foo

llvm/test/Other/new-pm-lto-defaults.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@
103103
; CHECK-O23SZ-NEXT: Running pass: GVNPass on foo
104104
; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis on foo
105105
; CHECK-O23SZ-NEXT: Running pass: MemCpyOptPass on foo
106-
; CHECK-O23SZ-NEXT: Running analysis: PostDominatorTreeAnalysis on foo
107106
; CHECK-O23SZ-NEXT: Running pass: DSEPass on foo
107+
; CHECK-O23SZ-NEXT: Running analysis: PostDominatorTreeAnalysis on foo
108108
; CHECK-O23SZ-NEXT: Running pass: MoveAutoInitPass on foo
109109
; CHECK-O23SZ-NEXT: Running pass: MergedLoadStoreMotionPass on foo
110110
; CHECK-O23SZ-NEXT: Running pass: LoopSimplifyPass on foo

llvm/test/Other/new-pm-thinlto-postlink-defaults.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@
125125
; CHECK-O23SZ-NEXT: Running pass: GVNPass
126126
; CHECK-O23SZ-NEXT: Running analysis: MemoryDependenceAnalysis
127127
; CHECK-O1-NEXT: Running pass: MemCpyOptPass
128-
; CHECK-O1-NEXT: Running analysis: PostDominatorTreeAnalysis
129128
; CHECK-O-NEXT: Running pass: SCCPPass
130129
; CHECK-O-NEXT: Running pass: BDCEPass
131130
; CHECK-O-NEXT: Running analysis: DemandedBitsAnalysis
@@ -136,7 +135,7 @@
136135
; CHECK-O23SZ-NEXT: Invalidating analysis: LazyValueAnalysis
137136
; CHECK-O1-NEXT: Running pass: CoroElidePass
138137
; CHECK-O-NEXT: Running pass: ADCEPass
139-
; CHECK-O23SZ-NEXT: Running analysis: PostDominatorTreeAnalysis
138+
; CHECK-O-NEXT: Running analysis: PostDominatorTreeAnalysis
140139
; CHECK-O23SZ-NEXT: Running pass: MemCpyOptPass
141140
; CHECK-O23SZ-NEXT: Running pass: DSEPass
142141
; CHECK-O23SZ-NEXT: Running pass: MoveAutoInitPass on foo

0 commit comments

Comments
 (0)