66//
77// ===----------------------------------------------------------------------===//
88// This file contains classes used to discover if for a particular value
9- // there from sue to definition that crosses a suspend block.
9+ // its definition precedes and its uses follow a suspend block. This is
10+ // referred to as a suspend crossing value.
1011//
1112// Using the information discovered we form a Coroutine Frame structure to
1213// contain those values. All uses of those values are replaced with appropriate
@@ -124,7 +125,8 @@ class SuspendCrossingInfo {
124125public:
125126#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
126127 void dump () const ;
127- void dump (StringRef Label, BitVector const &BV) const ;
128+ void dump (StringRef Label, BitVector const &BV,
129+ const ReversePostOrderTraversal<Function *> &RPOT) const ;
128130#endif
129131
130132 SuspendCrossingInfo (Function &F, coro::Shape &Shape);
@@ -207,21 +209,41 @@ class SuspendCrossingInfo {
207209} // end anonymous namespace
208210
209211#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
210- LLVM_DUMP_METHOD void SuspendCrossingInfo::dump (StringRef Label,
211- BitVector const &BV) const {
212+ static std::string getBasicBlockLabel (const BasicBlock *BB) {
213+ if (BB->hasName ())
214+ return BB->getName ().str ();
215+
216+ std::string S;
217+ raw_string_ostream OS (S);
218+ BB->printAsOperand (OS, false );
219+ return OS.str ().substr (1 );
220+ }
221+
222+ LLVM_DUMP_METHOD void SuspendCrossingInfo::dump (
223+ StringRef Label, BitVector const &BV,
224+ const ReversePostOrderTraversal<Function *> &RPOT) const {
212225 dbgs () << Label << " :" ;
213- for (size_t I = 0 , N = BV.size (); I < N; ++I)
214- if (BV[I])
215- dbgs () << " " << Mapping.indexToBlock (I)->getName ();
226+ for (const BasicBlock *BB : RPOT) {
227+ auto BBNo = Mapping.blockToIndex (BB);
228+ if (BV[BBNo])
229+ dbgs () << " " << getBasicBlockLabel (BB);
230+ }
216231 dbgs () << " \n " ;
217232}
218233
219234LLVM_DUMP_METHOD void SuspendCrossingInfo::dump () const {
220- for (size_t I = 0 , N = Block.size (); I < N; ++I) {
221- BasicBlock *const B = Mapping.indexToBlock (I);
222- dbgs () << B->getName () << " :\n " ;
223- dump (" Consumes" , Block[I].Consumes );
224- dump (" Kills" , Block[I].Kills );
235+ if (Block.empty ())
236+ return ;
237+
238+ BasicBlock *const B = Mapping.indexToBlock (0 );
239+ Function *F = B->getParent ();
240+
241+ ReversePostOrderTraversal<Function *> RPOT (F);
242+ for (const BasicBlock *BB : RPOT) {
243+ auto BBNo = Mapping.blockToIndex (BB);
244+ dbgs () << getBasicBlockLabel (BB) << " :\n " ;
245+ dump (" Consumes" , Block[BBNo].Consumes , RPOT);
246+ dump (" Kills" , Block[BBNo].Kills , RPOT);
225247 }
226248 dbgs () << " \n " ;
227249}
@@ -418,10 +440,7 @@ struct RematGraph {
418440#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
419441 void dump () const {
420442 dbgs () << " Entry (" ;
421- if (EntryNode->Node ->getParent ()->hasName ())
422- dbgs () << EntryNode->Node ->getParent ()->getName ();
423- else
424- EntryNode->Node ->getParent ()->printAsOperand (dbgs (), false );
443+ dbgs () << getBasicBlockLabel (EntryNode->Node ->getParent ());
425444 dbgs () << " ) : " << *EntryNode->Node << " \n " ;
426445 for (auto &E : Remats) {
427446 dbgs () << *(E.first ) << " \n " ;
@@ -551,7 +570,7 @@ struct FrameDataInfo {
551570
552571#ifndef NDEBUG
553572static void dumpSpills (StringRef Title, const SpillInfo &Spills) {
554- dbgs () << " ------------- " << Title << " --------------\n " ;
573+ dbgs () << " ------------- " << Title << " --------------\n " ;
555574 for (const auto &E : Spills) {
556575 E.first ->dump ();
557576 dbgs () << " user: " ;
@@ -813,7 +832,7 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,
813832 StackLifetime StackLifetimeAnalyzer (F, ExtractAllocas (),
814833 StackLifetime::LivenessType::May);
815834 StackLifetimeAnalyzer.run ();
816- auto IsAllocaInferenre = [&](const AllocaInst *AI1, const AllocaInst *AI2) {
835+ auto DoAllocasInterfere = [&](const AllocaInst *AI1, const AllocaInst *AI2) {
817836 return StackLifetimeAnalyzer.getLiveRange (AI1).overlaps (
818837 StackLifetimeAnalyzer.getLiveRange (AI2));
819838 };
@@ -833,13 +852,13 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,
833852 for (const auto &A : FrameData.Allocas ) {
834853 AllocaInst *Alloca = A.Alloca ;
835854 bool Merged = false ;
836- // Try to find if the Alloca is not inferenced with any existing
855+ // Try to find if the Alloca does not interfere with any existing
837856 // NonOverlappedAllocaSet. If it is true, insert the alloca to that
838857 // NonOverlappedAllocaSet.
839858 for (auto &AllocaSet : NonOverlapedAllocas) {
840859 assert (!AllocaSet.empty () && " Processing Alloca Set is not empty.\n " );
841- bool NoInference = none_of (AllocaSet, [&](auto Iter) {
842- return IsAllocaInferenre (Alloca, Iter);
860+ bool NoInterference = none_of (AllocaSet, [&](auto Iter) {
861+ return DoAllocasInterfere (Alloca, Iter);
843862 });
844863 // If the alignment of A is multiple of the alignment of B, the address
845864 // of A should satisfy the requirement for aligning for B.
@@ -852,7 +871,7 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,
852871 return LargestAlloca->getAlign ().value () % Alloca->getAlign ().value () ==
853872 0 ;
854873 }();
855- bool CouldMerge = NoInference && Alignable;
874+ bool CouldMerge = NoInterference && Alignable;
856875 if (!CouldMerge)
857876 continue ;
858877 AllocaSet.push_back (Alloca);
@@ -1714,6 +1733,51 @@ static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) {
17141733 return CleanupRet;
17151734}
17161735
1736+ static BasicBlock::iterator getSpillInsertionPt (const coro::Shape &Shape,
1737+ Value *Def,
1738+ const DominatorTree &DT) {
1739+ BasicBlock::iterator InsertPt;
1740+ if (auto *Arg = dyn_cast<Argument>(Def)) {
1741+ // For arguments, we will place the store instruction right after
1742+ // the coroutine frame pointer instruction, i.e. coro.begin.
1743+ InsertPt = Shape.getInsertPtAfterFramePtr ();
1744+
1745+ // If we're spilling an Argument, make sure we clear 'nocapture'
1746+ // from the coroutine function.
1747+ Arg->getParent ()->removeParamAttr (Arg->getArgNo (), Attribute::NoCapture);
1748+ } else if (auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) {
1749+ // Don't spill immediately after a suspend; splitting assumes
1750+ // that the suspend will be followed by a branch.
1751+ InsertPt = CSI->getParent ()->getSingleSuccessor ()->getFirstNonPHIIt ();
1752+ } else {
1753+ auto *I = cast<Instruction>(Def);
1754+ if (!DT.dominates (Shape.CoroBegin , I)) {
1755+ // If it is not dominated by CoroBegin, then spill should be
1756+ // inserted immediately after CoroFrame is computed.
1757+ InsertPt = Shape.getInsertPtAfterFramePtr ();
1758+ } else if (auto *II = dyn_cast<InvokeInst>(I)) {
1759+ // If we are spilling the result of the invoke instruction, split
1760+ // the normal edge and insert the spill in the new block.
1761+ auto *NewBB = SplitEdge (II->getParent (), II->getNormalDest ());
1762+ InsertPt = NewBB->getTerminator ()->getIterator ();
1763+ } else if (isa<PHINode>(I)) {
1764+ // Skip the PHINodes and EH pads instructions.
1765+ BasicBlock *DefBlock = I->getParent ();
1766+ if (auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->getTerminator ()))
1767+ InsertPt = splitBeforeCatchSwitch (CSI)->getIterator ();
1768+ else
1769+ InsertPt = DefBlock->getFirstInsertionPt ();
1770+ } else {
1771+ assert (!I->isTerminator () && " unexpected terminator" );
1772+ // For all other values, the spill is placed immediately after
1773+ // the definition.
1774+ InsertPt = I->getNextNode ()->getIterator ();
1775+ }
1776+ }
1777+
1778+ return InsertPt;
1779+ }
1780+
17171781// Replace all alloca and SSA values that are accessed across suspend points
17181782// with GetElementPointer from coroutine frame + loads and stores. Create an
17191783// AllocaSpillBB that will become the new entry block for the resume parts of
@@ -1736,9 +1800,8 @@ static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) {
17361800//
17371801//
17381802static void insertSpills (const FrameDataInfo &FrameData, coro::Shape &Shape) {
1739- auto *CB = Shape.CoroBegin ;
1740- LLVMContext &C = CB->getContext ();
1741- Function *F = CB->getFunction ();
1803+ LLVMContext &C = Shape.CoroBegin ->getContext ();
1804+ Function *F = Shape.CoroBegin ->getFunction ();
17421805 IRBuilder<> Builder (C);
17431806 StructType *FrameTy = Shape.FrameTy ;
17441807 Value *FramePtr = Shape.FramePtr ;
@@ -1799,47 +1862,16 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
17991862 auto SpillAlignment = Align (FrameData.getAlign (Def));
18001863 // Create a store instruction storing the value into the
18011864 // coroutine frame.
1802- BasicBlock::iterator InsertPt;
1865+ BasicBlock::iterator InsertPt = getSpillInsertionPt (Shape, Def, DT);
1866+
18031867 Type *ByValTy = nullptr ;
18041868 if (auto *Arg = dyn_cast<Argument>(Def)) {
1805- // For arguments, we will place the store instruction right after
1806- // the coroutine frame pointer instruction, i.e. coro.begin.
1807- InsertPt = Shape.getInsertPtAfterFramePtr ();
1808-
18091869 // If we're spilling an Argument, make sure we clear 'nocapture'
18101870 // from the coroutine function.
18111871 Arg->getParent ()->removeParamAttr (Arg->getArgNo (), Attribute::NoCapture);
18121872
18131873 if (Arg->hasByValAttr ())
18141874 ByValTy = Arg->getParamByValType ();
1815- } else if (auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) {
1816- // Don't spill immediately after a suspend; splitting assumes
1817- // that the suspend will be followed by a branch.
1818- InsertPt = CSI->getParent ()->getSingleSuccessor ()->getFirstNonPHIIt ();
1819- } else {
1820- auto *I = cast<Instruction>(Def);
1821- if (!DT.dominates (CB, I)) {
1822- // If it is not dominated by CoroBegin, then spill should be
1823- // inserted immediately after CoroFrame is computed.
1824- InsertPt = Shape.getInsertPtAfterFramePtr ();
1825- } else if (auto *II = dyn_cast<InvokeInst>(I)) {
1826- // If we are spilling the result of the invoke instruction, split
1827- // the normal edge and insert the spill in the new block.
1828- auto *NewBB = SplitEdge (II->getParent (), II->getNormalDest ());
1829- InsertPt = NewBB->getTerminator ()->getIterator ();
1830- } else if (isa<PHINode>(I)) {
1831- // Skip the PHINodes and EH pads instructions.
1832- BasicBlock *DefBlock = I->getParent ();
1833- if (auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->getTerminator ()))
1834- InsertPt = splitBeforeCatchSwitch (CSI)->getIterator ();
1835- else
1836- InsertPt = DefBlock->getFirstInsertionPt ();
1837- } else {
1838- assert (!I->isTerminator () && " unexpected terminator" );
1839- // For all other values, the spill is placed immediately after
1840- // the definition.
1841- InsertPt = I->getNextNode ()->getIterator ();
1842- }
18431875 }
18441876
18451877 auto Index = FrameData.getFieldIndex (Def);
@@ -1982,7 +2014,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
19822014 UsersToUpdate.clear ();
19832015 for (User *U : Alloca->users ()) {
19842016 auto *I = cast<Instruction>(U);
1985- if (DT.dominates (CB , I))
2017+ if (DT.dominates (Shape. CoroBegin , I))
19862018 UsersToUpdate.push_back (I);
19872019 }
19882020 if (UsersToUpdate.empty ())
@@ -2024,7 +2056,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
20242056 Builder.CreateStore (Value, G);
20252057 }
20262058 // For each alias to Alloca created before CoroBegin but used after
2027- // CoroBegin, we recreate them after CoroBegin by appplying the offset
2059+ // CoroBegin, we recreate them after CoroBegin by applying the offset
20282060 // to the pointer in the frame.
20292061 for (const auto &Alias : A.Aliases ) {
20302062 auto *FramePtr = GetFramePointer (Alloca);
@@ -2033,7 +2065,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
20332065 auto *AliasPtr =
20342066 Builder.CreatePtrAdd (FramePtr, ConstantInt::get (ITy, Value));
20352067 Alias.first ->replaceUsesWithIf (
2036- AliasPtr, [&](Use &U) { return DT.dominates (CB , U); });
2068+ AliasPtr, [&](Use &U) { return DT.dominates (Shape. CoroBegin , U); });
20372069 }
20382070 }
20392071
@@ -2046,7 +2078,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
20462078 // If there is memory accessing to promise alloca before CoroBegin;
20472079 bool HasAccessingPromiseBeforeCB = llvm::any_of (PA->uses (), [&](Use &U) {
20482080 auto *Inst = dyn_cast<Instruction>(U.getUser ());
2049- if (!Inst || DT.dominates (CB , Inst))
2081+ if (!Inst || DT.dominates (Shape. CoroBegin , Inst))
20502082 return false ;
20512083
20522084 if (auto *CI = dyn_cast<CallInst>(Inst)) {
@@ -2692,7 +2724,7 @@ static void eliminateSwiftError(Function &F, coro::Shape &Shape) {
26922724 }
26932725}
26942726
2695- // / retcon and retcon.once conventions assume that all spill uses can be sunk
2727+ // / Async and Retcon{Once} conventions assume that all spill uses can be sunk
26962728// / after the coro.begin intrinsic.
26972729static void sinkSpillUsesAfterCoroBegin (Function &F,
26982730 const FrameDataInfo &FrameData,
@@ -2728,7 +2760,7 @@ static void sinkSpillUsesAfterCoroBegin(Function &F,
27282760 // Sort by dominance.
27292761 SmallVector<Instruction *, 64 > InsertionList (ToMove.begin (), ToMove.end ());
27302762 llvm::sort (InsertionList, [&Dom](Instruction *A, Instruction *B) -> bool {
2731- // If a dominates b it should preceed (<) b.
2763+ // If a dominates b it should precede (<) b.
27322764 return Dom.dominates (A, B);
27332765 });
27342766
@@ -3126,7 +3158,7 @@ void coro::buildCoroutineFrame(
31263158 cleanupSinglePredPHIs (F);
31273159
31283160 // Transforms multi-edge PHI Nodes, so that any value feeding into a PHI will
3129- // never has its definition separated from the PHI by the suspend point.
3161+ // never have its definition separated from the PHI by the suspend point.
31303162 rewritePHIs (F);
31313163
31323164 // Build suspend crossing info.
@@ -3223,6 +3255,7 @@ void coro::buildCoroutineFrame(
32233255 Shape.FramePtr = Shape.CoroBegin ;
32243256 // For now, this works for C++ programs only.
32253257 buildFrameDebugInfo (F, Shape, FrameData);
3258+ // Insert spills and reloads
32263259 insertSpills (FrameData, Shape);
32273260 lowerLocalAllocas (LocalAllocas, DeadInstructions);
32283261
0 commit comments