19
19
#include " llvm/ADT/PostOrderIterator.h"
20
20
#include " llvm/ADT/ScopeExit.h"
21
21
#include " llvm/ADT/SmallString.h"
22
+ #include " llvm/Analysis/CFG.h"
22
23
#include " llvm/Analysis/PtrUseVisitor.h"
23
24
#include " llvm/Analysis/StackLifetime.h"
24
25
#include " llvm/Config/llvm-config.h"
@@ -1440,17 +1441,22 @@ namespace {
1440
1441
struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
1441
1442
using Base = PtrUseVisitor<AllocaUseVisitor>;
1442
1443
AllocaUseVisitor (const DataLayout &DL, const DominatorTree &DT,
1443
- const CoroBeginInst &CB, const SuspendCrossingInfo &Checker,
1444
+ const coro::Shape &CoroShape,
1445
+ const SuspendCrossingInfo &Checker,
1444
1446
bool ShouldUseLifetimeStartInfo)
1445
- : PtrUseVisitor(DL), DT(DT), CoroBegin(CB), Checker(Checker),
1446
- ShouldUseLifetimeStartInfo (ShouldUseLifetimeStartInfo) {}
1447
+ : PtrUseVisitor(DL), DT(DT), CoroShape(CoroShape), Checker(Checker),
1448
+ ShouldUseLifetimeStartInfo (ShouldUseLifetimeStartInfo) {
1449
+ for (AnyCoroSuspendInst *SuspendInst : CoroShape.CoroSuspends )
1450
+ CoroSuspendBBs.insert (SuspendInst->getParent ());
1451
+ }
1447
1452
1448
1453
void visit (Instruction &I) {
1449
1454
Users.insert (&I);
1450
1455
Base::visit (I);
1451
1456
// If the pointer is escaped prior to CoroBegin, we have to assume it would
1452
1457
// be written into before CoroBegin as well.
1453
- if (PI.isEscaped () && !DT.dominates (&CoroBegin, PI.getEscapingInst ())) {
1458
+ if (PI.isEscaped () &&
1459
+ !DT.dominates (CoroShape.CoroBegin , PI.getEscapingInst ())) {
1454
1460
MayWriteBeforeCoroBegin = true ;
1455
1461
}
1456
1462
}
@@ -1553,10 +1559,19 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
1553
1559
// When we found the lifetime markers refers to a
1554
1560
// subrange of the original alloca, ignore the lifetime
1555
1561
// markers to avoid misleading the analysis.
1556
- if (II.getIntrinsicID () != Intrinsic::lifetime_start || !IsOffsetKnown ||
1557
- !Offset.isZero ())
1562
+ if (!IsOffsetKnown || !Offset.isZero ())
1563
+ return Base::visitIntrinsicInst (II);
1564
+ switch (II.getIntrinsicID ()) {
1565
+ default :
1558
1566
return Base::visitIntrinsicInst (II);
1559
- LifetimeStarts.insert (&II);
1567
+ case Intrinsic::lifetime_start:
1568
+ LifetimeStarts.insert (&II);
1569
+ LifetimeStartBBs.push_back (II.getParent ());
1570
+ break ;
1571
+ case Intrinsic::lifetime_end:
1572
+ LifetimeEndBBs.insert (II.getParent ());
1573
+ break ;
1574
+ }
1560
1575
}
1561
1576
1562
1577
void visitCallBase (CallBase &CB) {
@@ -1586,14 +1601,17 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
1586
1601
1587
1602
private:
1588
1603
const DominatorTree &DT;
1589
- const CoroBeginInst &CoroBegin ;
1604
+ const coro::Shape &CoroShape ;
1590
1605
const SuspendCrossingInfo &Checker;
1591
1606
// All alias to the original AllocaInst, created before CoroBegin and used
1592
1607
// after CoroBegin. Each entry contains the instruction and the offset in the
1593
1608
// original Alloca. They need to be recreated after CoroBegin off the frame.
1594
1609
DenseMap<Instruction *, std::optional<APInt>> AliasOffetMap{};
1595
1610
SmallPtrSet<Instruction *, 4 > Users{};
1596
1611
SmallPtrSet<IntrinsicInst *, 2 > LifetimeStarts{};
1612
+ SmallVector<BasicBlock *> LifetimeStartBBs{};
1613
+ SmallPtrSet<BasicBlock *, 2 > LifetimeEndBBs{};
1614
+ SmallPtrSet<const BasicBlock *, 2 > CoroSuspendBBs{};
1597
1615
bool MayWriteBeforeCoroBegin{false };
1598
1616
bool ShouldUseLifetimeStartInfo{true };
1599
1617
@@ -1605,10 +1623,19 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
1605
1623
// every basic block that uses the pointer to see if they cross suspension
1606
1624
// points. The uses cover both direct uses as well as indirect uses.
1607
1625
if (ShouldUseLifetimeStartInfo && !LifetimeStarts.empty ()) {
1608
- for (auto *I : Users)
1609
- for (auto *S : LifetimeStarts)
1610
- if (Checker.isDefinitionAcrossSuspend (*S, I))
1611
- return true ;
1626
+ // If there is no explicit lifetime.end, then assume the address can
1627
+ // cross suspension points.
1628
+ if (LifetimeEndBBs.empty ())
1629
+ return true ;
1630
+
1631
+ // If there is a path from a lifetime.start to a suspend without a
1632
+ // corresponding lifetime.end, then the alloca's lifetime persists
1633
+ // beyond that suspension point and the alloca must go on the frame.
1634
+ llvm::SmallVector<BasicBlock *> Worklist (LifetimeStartBBs);
1635
+ if (isManyPotentiallyReachableFromMany (Worklist, CoroSuspendBBs,
1636
+ &LifetimeEndBBs, &DT))
1637
+ return true ;
1638
+
1612
1639
// Addresses are guaranteed to be identical after every lifetime.start so
1613
1640
// we cannot use the local stack if the address escaped and there is a
1614
1641
// suspend point between lifetime markers. This should also cover the
@@ -1646,13 +1673,13 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
1646
1673
}
1647
1674
1648
1675
void handleMayWrite (const Instruction &I) {
1649
- if (!DT.dominates (& CoroBegin, &I))
1676
+ if (!DT.dominates (CoroShape. CoroBegin , &I))
1650
1677
MayWriteBeforeCoroBegin = true ;
1651
1678
}
1652
1679
1653
1680
bool usedAfterCoroBegin (Instruction &I) {
1654
1681
for (auto &U : I.uses ())
1655
- if (DT.dominates (& CoroBegin, U))
1682
+ if (DT.dominates (CoroShape. CoroBegin , U))
1656
1683
return true ;
1657
1684
return false ;
1658
1685
}
@@ -1661,7 +1688,7 @@ struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
1661
1688
// We track all aliases created prior to CoroBegin but used after.
1662
1689
// These aliases may need to be recreated after CoroBegin if the alloca
1663
1690
// need to live on the frame.
1664
- if (DT.dominates (& CoroBegin, &I) || !usedAfterCoroBegin (I))
1691
+ if (DT.dominates (CoroShape. CoroBegin , &I) || !usedAfterCoroBegin (I))
1665
1692
return ;
1666
1693
1667
1694
if (!IsOffsetKnown) {
@@ -2830,8 +2857,7 @@ static void collectFrameAlloca(AllocaInst *AI, coro::Shape &Shape,
2830
2857
bool ShouldUseLifetimeStartInfo =
2831
2858
(Shape.ABI != coro::ABI::Async && Shape.ABI != coro::ABI::Retcon &&
2832
2859
Shape.ABI != coro::ABI::RetconOnce);
2833
- AllocaUseVisitor Visitor{AI->getModule ()->getDataLayout (), DT,
2834
- *Shape.CoroBegin , Checker,
2860
+ AllocaUseVisitor Visitor{AI->getModule ()->getDataLayout (), DT, Shape, Checker,
2835
2861
ShouldUseLifetimeStartInfo};
2836
2862
Visitor.visitPtr (*AI);
2837
2863
if (!Visitor.getShouldLiveOnFrame ())
0 commit comments