19
19
#include " llvm/ADT/iterator_range.h"
20
20
#include " llvm/Analysis/AliasAnalysis.h"
21
21
#include " llvm/Analysis/AssumptionCache.h"
22
+ #include " llvm/Analysis/CFG.h"
22
23
#include " llvm/Analysis/CaptureTracking.h"
23
24
#include " llvm/Analysis/GlobalsModRef.h"
24
25
#include " llvm/Analysis/Loads.h"
25
26
#include " llvm/Analysis/MemoryLocation.h"
26
27
#include " llvm/Analysis/MemorySSA.h"
27
28
#include " llvm/Analysis/MemorySSAUpdater.h"
29
+ #include " llvm/Analysis/PostDominators.h"
28
30
#include " llvm/Analysis/TargetLibraryInfo.h"
29
31
#include " llvm/Analysis/ValueTracking.h"
30
32
#include " llvm/IR/BasicBlock.h"
@@ -1440,8 +1442,7 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
1440
1442
return false ;
1441
1443
}
1442
1444
1443
- // 1. Check that copy is full. Calculate the static size of the allocas to be
1444
- // merged, bail out if we can't.
1445
+ // Check that copy is full with static size.
1445
1446
const DataLayout &DL = DestAlloca->getModule ()->getDataLayout ();
1446
1447
std::optional<TypeSize> SrcSize = SrcAlloca->getAllocationSize (DL);
1447
1448
if (!SrcSize || SrcSize->isScalable () || Size != SrcSize->getFixedValue ()) {
@@ -1455,19 +1456,15 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
1455
1456
return false ;
1456
1457
}
1457
1458
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 ())
1459
+ if (!SrcAlloca->isStaticAlloca () || !DestAlloca->isStaticAlloca ())
1463
1460
return false ;
1464
1461
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.
1462
+ // Check that src and dest are never captured, unescaped allocas. Also
1463
+ // find the nearest common dominator and postdominator for all users in
1464
+ // order to shrink wrap the lifetimes, and instructions with noalias metadata
1465
+ // to remove them.
1468
1466
1469
1467
SmallVector<Instruction *, 4 > LifetimeMarkers;
1470
- Instruction *FirstUser = nullptr , *LastUser = nullptr ;
1471
1468
SmallSet<Instruction *, 4 > NoAliasInstrs;
1472
1469
1473
1470
// Recursively track the user and check whether modified alias exist.
@@ -1505,12 +1502,6 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
1505
1502
continue ;
1506
1503
case UseCaptureKind::NO_CAPTURE: {
1507
1504
auto *UI = cast<Instruction>(U.getUser ());
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;
1514
1505
if (UI->isLifetimeStartOrEnd ()) {
1515
1506
// We note the locations of these intrinsic calls so that we can
1516
1507
// delete them later if the optimization succeeds, this is safe
@@ -1534,37 +1525,64 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
1534
1525
return true ;
1535
1526
};
1536
1527
1537
- // 3. Check that dest has no Mod/Ref, except full size lifetime intrinsics,
1538
- // from the alloca to the Store.
1528
+ // Check that dest has no Mod/Ref, from the alloca to the Store, except full
1529
+ // size lifetime intrinsics. And collect modref inst for the reachability
1530
+ // check.
1539
1531
ModRefInfo DestModRef = ModRefInfo::NoModRef;
1540
1532
MemoryLocation DestLoc (DestAlloca, LocationSize::precise (Size));
1533
+ SmallVector<BasicBlock *, 8 > ReachabilityWorklist;
1541
1534
auto DestModRefCallback = [&](Instruction *UI) -> bool {
1542
1535
// We don't care about the store itself.
1543
1536
if (UI == Store)
1544
1537
return true ;
1545
1538
ModRefInfo Res = BAA.getModRefInfo (UI, DestLoc);
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);
1539
+ DestModRef |= Res;
1540
+ if (isModOrRefSet (Res)) {
1541
+ // Instructions reachability checks.
1542
+ // FIXME: adding the Instruction version isPotentiallyReachableFromMany on
1543
+ // lib/Analysis/CFG.cpp (currently only for BasicBlocks) might be helpful.
1544
+ if (UI->getParent () == Store->getParent ()) {
1545
+ // The same block case is special because it's the only time we're
1546
+ // looking within a single block to see which instruction comes first.
1547
+ // Once we start looking at multiple blocks, the first instruction of
1548
+ // the block is reachable, so we only need to determine reachability
1549
+ // between whole blocks.
1550
+ BasicBlock *BB = UI->getParent ();
1551
+
1552
+ // If A comes before B, then B is definitively reachable from A.
1553
+ if (UI->comesBefore (Store))
1554
+ return false ;
1555
+
1556
+ // If the user's parent block is entry, no predecessor exists.
1557
+ if (BB->isEntryBlock ())
1558
+ return true ;
1552
1559
1560
+ // Otherwise, continue doing the normal per-BB CFG walk.
1561
+ ReachabilityWorklist.append (succ_begin (BB), succ_end (BB));
1562
+ } else {
1563
+ ReachabilityWorklist.push_back (UI->getParent ());
1564
+ }
1565
+ }
1553
1566
return true ;
1554
1567
};
1555
1568
1556
1569
if (!CaptureTrackingWithModRef (DestAlloca, DestModRefCallback))
1557
1570
return false ;
1571
+ // Bailout if Dest may have any ModRef before Store.
1572
+ if (!ReachabilityWorklist.empty () &&
1573
+ isPotentiallyReachableFromMany (ReachabilityWorklist, Store->getParent (),
1574
+ nullptr , DT, nullptr ))
1575
+ return false ;
1558
1576
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.
1577
+ // Check that, from after the Load to the end of the BB,
1578
+ // - if the dest has any Mod, src has no Ref, and
1579
+ // - if the dest has any Ref, src has no Mod except full-sized lifetimes.
1562
1580
MemoryLocation SrcLoc (SrcAlloca, LocationSize::precise (Size));
1563
1581
1564
1582
auto SrcModRefCallback = [&](Instruction *UI) -> bool {
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)
1583
+ // Any ModRef post-dominated by Load doesn't matter, also Load and Store
1584
+ // themselves can be ignored.
1585
+ if (PDT-> dominates (Load, UI ) || UI == Load || UI == Store)
1568
1586
return true ;
1569
1587
ModRefInfo Res = BAA.getModRefInfo (UI, SrcLoc);
1570
1588
if ((isModSet (DestModRef) && isRefSet (Res)) ||
@@ -1588,34 +1606,10 @@ bool MemCpyOptPass::performStackMoveOptzn(Instruction *Load, Instruction *Store,
1588
1606
// Drop metadata on the source alloca.
1589
1607
SrcAlloca->dropUnknownNonDebugMetadata ();
1590
1608
1591
- // Do "shrink wrap" the lifetimes, if the original lifetime intrinsics exists.
1609
+ // TODO: Reconstruct merged lifetime markers.
1610
+ // Remove all other lifetime markers. if the original lifetime intrinsics
1611
+ // exists.
1592
1612
if (!LifetimeMarkers.empty ()) {
1593
- LLVMContext &C = SrcAlloca->getContext ();
1594
- IRBuilder<> Builder (C);
1595
-
1596
- ConstantInt *AllocaSize = ConstantInt::get (Type::getInt64Ty (C), Size);
1597
- // Create a new lifetime start marker before the first user of src or alloca
1598
- // users.
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);
1603
- MSSAU->insertDef (cast<MemoryDef>(StartMA), /* RenameUses=*/ true );
1604
-
1605
- // Create a new lifetime end marker after the last user of src or alloca
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);
1615
- MSSAU->insertDef (cast<MemoryDef>(EndMA), /* RenameUses=*/ true );
1616
- }
1617
-
1618
- // Remove all other lifetime markers.
1619
1613
for (Instruction *I : LifetimeMarkers)
1620
1614
eraseInstruction (I);
1621
1615
}
@@ -1999,9 +1993,10 @@ PreservedAnalyses MemCpyOptPass::run(Function &F, FunctionAnalysisManager &AM) {
1999
1993
auto *AA = &AM.getResult <AAManager>(F);
2000
1994
auto *AC = &AM.getResult <AssumptionAnalysis>(F);
2001
1995
auto *DT = &AM.getResult <DominatorTreeAnalysis>(F);
1996
+ auto *PDT = &AM.getResult <PostDominatorTreeAnalysis>(F);
2002
1997
auto *MSSA = &AM.getResult <MemorySSAAnalysis>(F);
2003
1998
2004
- bool MadeChange = runImpl (F, &TLI, AA, AC, DT, &MSSA->getMSSA ());
1999
+ bool MadeChange = runImpl (F, &TLI, AA, AC, DT, PDT, &MSSA->getMSSA ());
2005
2000
if (!MadeChange)
2006
2001
return PreservedAnalyses::all ();
2007
2002
@@ -2013,12 +2008,14 @@ PreservedAnalyses MemCpyOptPass::run(Function &F, FunctionAnalysisManager &AM) {
2013
2008
2014
2009
bool MemCpyOptPass::runImpl (Function &F, TargetLibraryInfo *TLI_,
2015
2010
AliasAnalysis *AA_, AssumptionCache *AC_,
2016
- DominatorTree *DT_, MemorySSA *MSSA_) {
2011
+ DominatorTree *DT_, PostDominatorTree *PDT_,
2012
+ MemorySSA *MSSA_) {
2017
2013
bool MadeChange = false ;
2018
2014
TLI = TLI_;
2019
2015
AA = AA_;
2020
2016
AC = AC_;
2021
2017
DT = DT_;
2018
+ PDT = PDT_;
2022
2019
MSSA = MSSA_;
2023
2020
MemorySSAUpdater MSSAU_ (MSSA_);
2024
2021
MSSAU = &MSSAU_;
0 commit comments