Skip to content

Commit a012ba9

Browse files
author
tnowicki
committed
[llvm/llvm-project][Coroutines] Improve debugging and minor refactoring
* Fix comments in several places * Instead of using BB-getName() which will return an empty string if the BB has no name, getBasicBlockLabel will give the BBs label e.g. #### this makes the IR easier to read, otherwise we get lots of blocks with names like ".from.". * Use RPO when dumping SuspendCrossingInfo. Without this the dump order is determined by the ptr addresses and so is not consistent from run to run making IR diffs difficult to read. * Inference -> Interference * Pull the logic that determines insertion location out of insertSpills and into getSpillInsertionPt, to differentiate between these two operations. * Use Shape getters for CoroId instead of getting it manually. *
1 parent 808933f commit a012ba9

File tree

3 files changed

+115
-83
lines changed

3 files changed

+115
-83
lines changed

llvm/lib/Transforms/Coroutines/CoroEarly.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ void Lowerer::lowerEarlyIntrinsics(Function &F) {
203203
if (auto *CII = cast<CoroIdInst>(&I)) {
204204
if (CII->getInfo().isPreSplit()) {
205205
assert(F.isPresplitCoroutine() &&
206-
"The frontend uses Swtich-Resumed ABI should emit "
206+
"The frontend uses Switch-Resumed ABI should emit "
207207
"\"presplitcoroutine\" attribute for the coroutine.");
208208
setCannotDuplicate(CII);
209209
CII->setCoroutineSelf();

llvm/lib/Transforms/Coroutines/CoroFrame.cpp

Lines changed: 110 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
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 preceeds 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
@@ -52,6 +53,16 @@ extern cl::opt<bool> UseNewDbgInfoFormat;
5253

5354
enum { SmallVectorThreshold = 32 };
5455

56+
static std::string getBasicBlockLabel(const BasicBlock *BB) {
57+
if (BB->hasName())
58+
return BB->getName().str();
59+
60+
std::string S;
61+
raw_string_ostream OS(S);
62+
BB->printAsOperand(OS, false);
63+
return OS.str().substr(1);
64+
}
65+
5566
// Provides two way mapping between the blocks and numbers.
5667
namespace {
5768
class BlockToIndexMapping {
@@ -123,8 +134,9 @@ class SuspendCrossingInfo {
123134

124135
public:
125136
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
126-
void dump() const;
127-
void dump(StringRef Label, BitVector const &BV) const;
137+
void dump(const ReversePostOrderTraversal<Function *> &RPOT) const;
138+
void dump(StringRef Label, BitVector const &BV,
139+
const ReversePostOrderTraversal<Function *> &RPOT) const;
128140
#endif
129141

130142
SuspendCrossingInfo(Function &F, coro::Shape &Shape);
@@ -207,21 +219,25 @@ class SuspendCrossingInfo {
207219
} // end anonymous namespace
208220

209221
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
210-
LLVM_DUMP_METHOD void SuspendCrossingInfo::dump(StringRef Label,
211-
BitVector const &BV) const {
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

219-
LLVM_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);
234+
LLVM_DUMP_METHOD void SuspendCrossingInfo::dump(
235+
const ReversePostOrderTraversal<Function *> &RPOT) const {
236+
for (const BasicBlock *BB : RPOT) {
237+
auto BBNo = Mapping.blockToIndex(BB);
238+
dbgs() << getBasicBlockLabel(BB) << ":\n";
239+
dump(" Consumes", Block[BBNo].Consumes, RPOT);
240+
dump(" Kills", Block[BBNo].Kills, RPOT);
225241
}
226242
dbgs() << "\n";
227243
}
@@ -335,7 +351,7 @@ SuspendCrossingInfo::SuspendCrossingInfo(Function &F, coro::Shape &Shape)
335351
while (computeBlockData</*Initialize*/ false>(RPOT))
336352
;
337353

338-
LLVM_DEBUG(dump());
354+
LLVM_DEBUG(dump(RPOT));
339355
}
340356

341357
namespace {
@@ -419,7 +435,7 @@ struct RematGraph {
419435
void dump() const {
420436
dbgs() << "Entry (";
421437
if (EntryNode->Node->getParent()->hasName())
422-
dbgs() << EntryNode->Node->getParent()->getName();
438+
dbgs() << getBasicBlockLabel(EntryNode->Node->getParent());
423439
else
424440
EntryNode->Node->getParent()->printAsOperand(dbgs(), false);
425441
dbgs() << ") : " << *EntryNode->Node << "\n";
@@ -551,7 +567,7 @@ struct FrameDataInfo {
551567

552568
#ifndef NDEBUG
553569
static void dumpSpills(StringRef Title, const SpillInfo &Spills) {
554-
dbgs() << "------------- " << Title << "--------------\n";
570+
dbgs() << "------------- " << Title << " --------------\n";
555571
for (const auto &E : Spills) {
556572
E.first->dump();
557573
dbgs() << " user: ";
@@ -813,7 +829,7 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,
813829
StackLifetime StackLifetimeAnalyzer(F, ExtractAllocas(),
814830
StackLifetime::LivenessType::May);
815831
StackLifetimeAnalyzer.run();
816-
auto IsAllocaInferenre = [&](const AllocaInst *AI1, const AllocaInst *AI2) {
832+
auto DoAllocasInterfere = [&](const AllocaInst *AI1, const AllocaInst *AI2) {
817833
return StackLifetimeAnalyzer.getLiveRange(AI1).overlaps(
818834
StackLifetimeAnalyzer.getLiveRange(AI2));
819835
};
@@ -833,13 +849,13 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,
833849
for (const auto &A : FrameData.Allocas) {
834850
AllocaInst *Alloca = A.Alloca;
835851
bool Merged = false;
836-
// Try to find if the Alloca is not inferenced with any existing
852+
// Try to find if the Alloca does not interfere with any existing
837853
// NonOverlappedAllocaSet. If it is true, insert the alloca to that
838854
// NonOverlappedAllocaSet.
839855
for (auto &AllocaSet : NonOverlapedAllocas) {
840856
assert(!AllocaSet.empty() && "Processing Alloca Set is not empty.\n");
841-
bool NoInference = none_of(AllocaSet, [&](auto Iter) {
842-
return IsAllocaInferenre(Alloca, Iter);
857+
bool NoInterference = none_of(AllocaSet, [&](auto Iter) {
858+
return DoAllocasInterfere(Alloca, Iter);
843859
});
844860
// If the alignment of A is multiple of the alignment of B, the address
845861
// of A should satisfy the requirement for aligning for B.
@@ -852,7 +868,7 @@ void FrameTypeBuilder::addFieldForAllocas(const Function &F,
852868
return LargestAlloca->getAlign().value() % Alloca->getAlign().value() ==
853869
0;
854870
}();
855-
bool CouldMerge = NoInference && Alignable;
871+
bool CouldMerge = NoInterference && Alignable;
856872
if (!CouldMerge)
857873
continue;
858874
AllocaSet.push_back(Alloca);
@@ -1730,6 +1746,51 @@ static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) {
17301746
return CleanupRet;
17311747
}
17321748

1749+
static BasicBlock::iterator getSpillInsertionPt(const coro::Shape &Shape,
1750+
Value *Def,
1751+
const DominatorTree &DT) {
1752+
BasicBlock::iterator InsertPt;
1753+
if (auto *Arg = dyn_cast<Argument>(Def)) {
1754+
// For arguments, we will place the store instruction right after
1755+
// the coroutine frame pointer instruction, i.e. coro.begin.
1756+
InsertPt = Shape.getInsertPtAfterFramePtr();
1757+
1758+
// If we're spilling an Argument, make sure we clear 'nocapture'
1759+
// from the coroutine function.
1760+
Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::NoCapture);
1761+
} else if (auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) {
1762+
// Don't spill immediately after a suspend; splitting assumes
1763+
// that the suspend will be followed by a branch.
1764+
InsertPt = CSI->getParent()->getSingleSuccessor()->getFirstNonPHIIt();
1765+
} else {
1766+
auto *I = cast<Instruction>(Def);
1767+
if (!DT.dominates(Shape.CoroBegin, I)) {
1768+
// If it is not dominated by CoroBegin, then spill should be
1769+
// inserted immediately after CoroFrame is computed.
1770+
InsertPt = Shape.getInsertPtAfterFramePtr();
1771+
} else if (auto *II = dyn_cast<InvokeInst>(I)) {
1772+
// If we are spilling the result of the invoke instruction, split
1773+
// the normal edge and insert the spill in the new block.
1774+
auto *NewBB = SplitEdge(II->getParent(), II->getNormalDest());
1775+
InsertPt = NewBB->getTerminator()->getIterator();
1776+
} else if (isa<PHINode>(I)) {
1777+
// Skip the PHINodes and EH pads instructions.
1778+
BasicBlock *DefBlock = I->getParent();
1779+
if (auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->getTerminator()))
1780+
InsertPt = splitBeforeCatchSwitch(CSI)->getIterator();
1781+
else
1782+
InsertPt = DefBlock->getFirstInsertionPt();
1783+
} else {
1784+
assert(!I->isTerminator() && "unexpected terminator");
1785+
// For all other values, the spill is placed immediately after
1786+
// the definition.
1787+
InsertPt = I->getNextNode()->getIterator();
1788+
}
1789+
}
1790+
1791+
return InsertPt;
1792+
}
1793+
17331794
// Replace all alloca and SSA values that are accessed across suspend points
17341795
// with GetElementPointer from coroutine frame + loads and stores. Create an
17351796
// AllocaSpillBB that will become the new entry block for the resume parts of
@@ -1752,9 +1813,8 @@ static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) {
17521813
//
17531814
//
17541815
static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
1755-
auto *CB = Shape.CoroBegin;
1756-
LLVMContext &C = CB->getContext();
1757-
Function *F = CB->getFunction();
1816+
LLVMContext &C = Shape.CoroBegin->getContext();
1817+
Function *F = Shape.CoroBegin->getFunction();
17581818
IRBuilder<> Builder(C);
17591819
StructType *FrameTy = Shape.FrameTy;
17601820
Value *FramePtr = Shape.FramePtr;
@@ -1815,47 +1875,16 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
18151875
auto SpillAlignment = Align(FrameData.getAlign(Def));
18161876
// Create a store instruction storing the value into the
18171877
// coroutine frame.
1818-
BasicBlock::iterator InsertPt;
1878+
BasicBlock::iterator InsertPt = getSpillInsertionPt(Shape, Def, DT);
1879+
18191880
Type *ByValTy = nullptr;
18201881
if (auto *Arg = dyn_cast<Argument>(Def)) {
1821-
// For arguments, we will place the store instruction right after
1822-
// the coroutine frame pointer instruction, i.e. coro.begin.
1823-
InsertPt = Shape.getInsertPtAfterFramePtr();
1824-
18251882
// If we're spilling an Argument, make sure we clear 'nocapture'
18261883
// from the coroutine function.
18271884
Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::NoCapture);
18281885

18291886
if (Arg->hasByValAttr())
18301887
ByValTy = Arg->getParamByValType();
1831-
} else if (auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) {
1832-
// Don't spill immediately after a suspend; splitting assumes
1833-
// that the suspend will be followed by a branch.
1834-
InsertPt = CSI->getParent()->getSingleSuccessor()->getFirstNonPHIIt();
1835-
} else {
1836-
auto *I = cast<Instruction>(Def);
1837-
if (!DT.dominates(CB, I)) {
1838-
// If it is not dominated by CoroBegin, then spill should be
1839-
// inserted immediately after CoroFrame is computed.
1840-
InsertPt = Shape.getInsertPtAfterFramePtr();
1841-
} else if (auto *II = dyn_cast<InvokeInst>(I)) {
1842-
// If we are spilling the result of the invoke instruction, split
1843-
// the normal edge and insert the spill in the new block.
1844-
auto *NewBB = SplitEdge(II->getParent(), II->getNormalDest());
1845-
InsertPt = NewBB->getTerminator()->getIterator();
1846-
} else if (isa<PHINode>(I)) {
1847-
// Skip the PHINodes and EH pads instructions.
1848-
BasicBlock *DefBlock = I->getParent();
1849-
if (auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->getTerminator()))
1850-
InsertPt = splitBeforeCatchSwitch(CSI)->getIterator();
1851-
else
1852-
InsertPt = DefBlock->getFirstInsertionPt();
1853-
} else {
1854-
assert(!I->isTerminator() && "unexpected terminator");
1855-
// For all other values, the spill is placed immediately after
1856-
// the definition.
1857-
InsertPt = I->getNextNode()->getIterator();
1858-
}
18591888
}
18601889

18611890
auto Index = FrameData.getFieldIndex(Def);
@@ -1998,7 +2027,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
19982027
UsersToUpdate.clear();
19992028
for (User *U : Alloca->users()) {
20002029
auto *I = cast<Instruction>(U);
2001-
if (DT.dominates(CB, I))
2030+
if (DT.dominates(Shape.CoroBegin, I))
20022031
UsersToUpdate.push_back(I);
20032032
}
20042033
if (UsersToUpdate.empty())
@@ -2040,7 +2069,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
20402069
Builder.CreateStore(Value, G);
20412070
}
20422071
// For each alias to Alloca created before CoroBegin but used after
2043-
// CoroBegin, we recreate them after CoroBegin by appplying the offset
2072+
// CoroBegin, we recreate them after CoroBegin by applying the offset
20442073
// to the pointer in the frame.
20452074
for (const auto &Alias : A.Aliases) {
20462075
auto *FramePtr = GetFramePointer(Alloca);
@@ -2049,7 +2078,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
20492078
auto *AliasPtr =
20502079
Builder.CreatePtrAdd(FramePtr, ConstantInt::get(ITy, Value));
20512080
Alias.first->replaceUsesWithIf(
2052-
AliasPtr, [&](Use &U) { return DT.dominates(CB, U); });
2081+
AliasPtr, [&](Use &U) { return DT.dominates(Shape.CoroBegin, U); });
20532082
}
20542083
}
20552084

@@ -2062,7 +2091,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
20622091
// If there is memory accessing to promise alloca before CoroBegin;
20632092
bool HasAccessingPromiseBeforeCB = llvm::any_of(PA->uses(), [&](Use &U) {
20642093
auto *Inst = dyn_cast<Instruction>(U.getUser());
2065-
if (!Inst || DT.dominates(CB, Inst))
2094+
if (!Inst || DT.dominates(Shape.CoroBegin, Inst))
20662095
return false;
20672096

20682097
if (auto *CI = dyn_cast<CallInst>(Inst)) {
@@ -2105,8 +2134,9 @@ static void movePHIValuesToInsertedBlock(BasicBlock *SuccBB,
21052134
do {
21062135
int Index = PN->getBasicBlockIndex(InsertedBB);
21072136
Value *V = PN->getIncomingValue(Index);
2108-
PHINode *InputV = PHINode::Create(
2109-
V->getType(), 1, V->getName() + Twine(".") + SuccBB->getName());
2137+
PHINode *InputV =
2138+
PHINode::Create(V->getType(), 1,
2139+
V->getName() + Twine(".") + getBasicBlockLabel(SuccBB));
21102140
InputV->insertBefore(InsertedBB->begin());
21112141
InputV->addIncoming(V, PredBB);
21122142
PN->setIncomingValue(Index, InputV);
@@ -2151,10 +2181,10 @@ static void rewritePHIsForCleanupPad(BasicBlock *CleanupPadBB,
21512181
Builder.CreateUnreachable();
21522182

21532183
// Create a new cleanuppad which will be the dispatcher.
2154-
auto *NewCleanupPadBB =
2155-
BasicBlock::Create(CleanupPadBB->getContext(),
2156-
CleanupPadBB->getName() + Twine(".corodispatch"),
2157-
CleanupPadBB->getParent(), CleanupPadBB);
2184+
auto *NewCleanupPadBB = BasicBlock::Create(
2185+
CleanupPadBB->getContext(),
2186+
getBasicBlockLabel(CleanupPadBB) + Twine(".corodispatch"),
2187+
CleanupPadBB->getParent(), CleanupPadBB);
21582188
Builder.SetInsertPoint(NewCleanupPadBB);
21592189
auto *SwitchType = Builder.getInt8Ty();
21602190
auto *SetDispatchValuePN =
@@ -2168,13 +2198,14 @@ static void rewritePHIsForCleanupPad(BasicBlock *CleanupPadBB,
21682198
SmallVector<BasicBlock *, 8> Preds(predecessors(CleanupPadBB));
21692199
for (BasicBlock *Pred : Preds) {
21702200
// Create a new cleanuppad and move the PHI values to there.
2171-
auto *CaseBB = BasicBlock::Create(CleanupPadBB->getContext(),
2172-
CleanupPadBB->getName() +
2173-
Twine(".from.") + Pred->getName(),
2174-
CleanupPadBB->getParent(), CleanupPadBB);
2201+
auto *CaseBB =
2202+
BasicBlock::Create(CleanupPadBB->getContext(),
2203+
getBasicBlockLabel(CleanupPadBB) + Twine(".from.") +
2204+
getBasicBlockLabel(Pred),
2205+
CleanupPadBB->getParent(), CleanupPadBB);
21752206
updatePhiNodes(CleanupPadBB, Pred, CaseBB);
2176-
CaseBB->setName(CleanupPadBB->getName() + Twine(".from.") +
2177-
Pred->getName());
2207+
CaseBB->setName(getBasicBlockLabel(CleanupPadBB) + Twine(".from.") +
2208+
getBasicBlockLabel(Pred));
21782209
Builder.SetInsertPoint(CaseBB);
21792210
Builder.CreateBr(CleanupPadBB);
21802211
movePHIValuesToInsertedBlock(CleanupPadBB, CaseBB, NewCleanupPadBB);
@@ -2264,7 +2295,8 @@ static void rewritePHIs(BasicBlock &BB) {
22642295
SmallVector<BasicBlock *, 8> Preds(predecessors(&BB));
22652296
for (BasicBlock *Pred : Preds) {
22662297
auto *IncomingBB = ehAwareSplitEdge(Pred, &BB, LandingPad, ReplPHI);
2267-
IncomingBB->setName(BB.getName() + Twine(".from.") + Pred->getName());
2298+
IncomingBB->setName(getBasicBlockLabel(&BB) + Twine(".from.") +
2299+
getBasicBlockLabel(Pred));
22682300

22692301
// Stop the moving of values at ReplPHI, as this is either null or the PHI
22702302
// that replaced the landing pad.
@@ -2708,7 +2740,7 @@ static void eliminateSwiftError(Function &F, coro::Shape &Shape) {
27082740
}
27092741
}
27102742

2711-
/// retcon and retcon.once conventions assume that all spill uses can be sunk
2743+
/// Async and Retcon{Once} conventions assume that all spill uses can be sunk
27122744
/// after the coro.begin intrinsic.
27132745
static void sinkSpillUsesAfterCoroBegin(Function &F,
27142746
const FrameDataInfo &FrameData,
@@ -3142,7 +3174,7 @@ void coro::buildCoroutineFrame(
31423174
cleanupSinglePredPHIs(F);
31433175

31443176
// Transforms multi-edge PHI Nodes, so that any value feeding into a PHI will
3145-
// never has its definition separated from the PHI by the suspend point.
3177+
// never have its definition separated from the PHI by the suspend point.
31463178
rewritePHIs(F);
31473179

31483180
// Build suspend crossing info.
@@ -3239,6 +3271,7 @@ void coro::buildCoroutineFrame(
32393271
Shape.FramePtr = Shape.CoroBegin;
32403272
// For now, this works for C++ programs only.
32413273
buildFrameDebugInfo(F, Shape, FrameData);
3274+
// Insert spills and reloads
32423275
insertSpills(FrameData, Shape);
32433276
lowerLocalAllocas(LocalAllocas, DeadInstructions);
32443277

0 commit comments

Comments
 (0)