25typedef SmallPtrSet<BasicBlock *, 8> VisitedBlocksSet;
27static bool isNonSpilledIntrinsic(Instruction &
I) {
30 return isa<CoroIdInst>(&
I) || isa<CoroSaveInst>(&
I);
35static bool isSuspendReachableFrom(BasicBlock *
From,
36 VisitedBlocksSet &VisitedOrFreeBBs) {
40 if (!VisitedOrFreeBBs.insert(
From).second)
49 if (isSuspendReachableFrom(Succ, VisitedOrFreeBBs))
58static bool isLocalAlloca(CoroAllocaAllocInst *AI) {
61 VisitedBlocksSet VisitedOrFreeBBs;
62 for (
auto *User : AI->users()) {
63 if (
auto FI = dyn_cast<CoroAllocaFreeInst>(User))
64 VisitedOrFreeBBs.insert(FI->getParent());
67 return !isSuspendReachableFrom(AI->getParent(), VisitedOrFreeBBs);
74lowerNonLocalAlloca(CoroAllocaAllocInst *AI,
const coro::Shape &Shape,
75 SmallVectorImpl<Instruction *> &DeadInsts) {
76 IRBuilder<> Builder(AI);
77 auto Alloc = Shape.emitAlloc(Builder, AI->getSize(),
nullptr);
79 for (User *U : AI->users()) {
80 if (isa<CoroAllocaGetInst>(U)) {
81 U->replaceAllUsesWith(
Alloc);
83 auto FI = cast<CoroAllocaFreeInst>(U);
84 Builder.SetInsertPoint(FI);
85 Shape.emitDealloc(Builder,
Alloc,
nullptr);
87 DeadInsts.push_back(cast<Instruction>(U));
91 DeadInsts.push_back(AI);
94 return cast<Instruction>(
Alloc);
106static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) {
107 BasicBlock *CurrentBlock = CatchSwitch->getParent();
108 BasicBlock *NewBlock = CurrentBlock->splitBasicBlock(CatchSwitch);
109 CurrentBlock->getTerminator()->eraseFromParent();
150struct AllocaUseVisitor : PtrUseVisitor<AllocaUseVisitor> {
151 using Base = PtrUseVisitor<AllocaUseVisitor>;
152 AllocaUseVisitor(
const DataLayout &
DL,
const DominatorTree &DT,
153 const coro::Shape &CoroShape,
154 const SuspendCrossingInfo &Checker,
155 bool ShouldUseLifetimeStartInfo)
156 : PtrUseVisitor(
DL), DT(DT), CoroShape(CoroShape), Checker(Checker),
157 ShouldUseLifetimeStartInfo(ShouldUseLifetimeStartInfo) {
158 for (AnyCoroSuspendInst *SuspendInst : CoroShape.CoroSuspends)
159 CoroSuspendBBs.insert(SuspendInst->getParent());
162 void visit(Instruction &
I) {
167 if (PI.isEscaped() &&
168 !DT.dominates(CoroShape.CoroBegin, PI.getEscapingInst())) {
169 MayWriteBeforeCoroBegin =
true;
176 void visitPHINode(PHINode &
I) {
181 void visitSelectInst(SelectInst &
I) {
186 void visitStoreInst(StoreInst &
SI) {
191 if (
SI.getValueOperand() !=
U->get())
204 auto IsSimpleStoreThenLoad = [&]() {
205 auto *AI = dyn_cast<AllocaInst>(
SI.getPointerOperand());
212 SmallVector<Instruction *, 4> StoreAliases = {AI};
213 while (!StoreAliases.empty()) {
214 Instruction *
I = StoreAliases.pop_back_val();
215 for (User *U :
I->users()) {
218 if (
auto *LI = dyn_cast<LoadInst>(U)) {
225 if (
auto *S = dyn_cast<StoreInst>(U))
226 if (S->getPointerOperand() ==
I)
228 if (isa<LifetimeIntrinsic>(U))
232 if (
auto *BI = dyn_cast<BitCastInst>(U)) {
233 StoreAliases.push_back(BI);
243 if (!IsSimpleStoreThenLoad())
248 void visitMemIntrinsic(MemIntrinsic &
MI) { handleMayWrite(
MI); }
250 void visitBitCastInst(BitCastInst &BC) {
251 Base::visitBitCastInst(BC);
255 void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
256 Base::visitAddrSpaceCastInst(ASC);
260 void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
262 Base::visitGetElementPtrInst(GEPI);
266 void visitIntrinsicInst(IntrinsicInst &
II) {
267 switch (
II.getIntrinsicID()) {
269 return Base::visitIntrinsicInst(
II);
270 case Intrinsic::lifetime_start:
271 LifetimeStarts.insert(&
II);
272 LifetimeStartBBs.push_back(
II.getParent());
274 case Intrinsic::lifetime_end:
275 LifetimeEndBBs.insert(
II.getParent());
280 void visitCallBase(CallBase &CB) {
281 for (
unsigned Op = 0, OpCount = CB.arg_size(); Op < OpCount; ++Op)
282 if (
U->get() == CB.getArgOperand(Op) && !CB.doesNotCapture(Op))
287 bool getShouldLiveOnFrame()
const {
288 if (!ShouldLiveOnFrame)
289 ShouldLiveOnFrame = computeShouldLiveOnFrame();
290 return *ShouldLiveOnFrame;
293 bool getMayWriteBeforeCoroBegin()
const {
return MayWriteBeforeCoroBegin; }
295 DenseMap<Instruction *, std::optional<APInt>> getAliasesCopy()
const {
296 assert(getShouldLiveOnFrame() &&
"This method should only be called if the "
297 "alloca needs to live on the frame.");
298 for (
const auto &
P : AliasOffetMap)
301 "created before CoroBegin.");
302 return AliasOffetMap;
306 const DominatorTree &DT;
307 const coro::Shape &CoroShape;
308 const SuspendCrossingInfo &Checker;
312 DenseMap<Instruction *, std::optional<APInt>> AliasOffetMap{};
313 SmallPtrSet<Instruction *, 4>
Users{};
314 SmallPtrSet<IntrinsicInst *, 2> LifetimeStarts{};
315 SmallVector<BasicBlock *> LifetimeStartBBs{};
316 SmallPtrSet<BasicBlock *, 2> LifetimeEndBBs{};
317 SmallPtrSet<const BasicBlock *, 2> CoroSuspendBBs{};
318 bool MayWriteBeforeCoroBegin{
false};
319 bool ShouldUseLifetimeStartInfo{
true};
321 mutable std::optional<bool> ShouldLiveOnFrame{};
323 bool computeShouldLiveOnFrame()
const {
328 if (ShouldUseLifetimeStartInfo && !LifetimeStarts.empty()) {
331 if (LifetimeEndBBs.empty())
339 &LifetimeEndBBs, &DT))
346 if (PI.isEscaped()) {
347 for (
auto *
A : LifetimeStarts) {
348 for (
auto *
B : LifetimeStarts) {
349 if (Checker.hasPathOrLoopCrossingSuspendPoint(
A->getParent(),
370 for (
auto *U1 :
Users)
371 for (
auto *U2 :
Users)
372 if (Checker.isDefinitionAcrossSuspend(*U1, U2))
378 void handleMayWrite(
const Instruction &
I) {
379 if (!DT.dominates(CoroShape.CoroBegin, &
I))
380 MayWriteBeforeCoroBegin =
true;
383 bool usedAfterCoroBegin(Instruction &
I) {
384 for (
auto &U :
I.uses())
385 if (DT.dominates(CoroShape.CoroBegin, U))
390 void handleAlias(Instruction &
I) {
394 if (DT.dominates(CoroShape.CoroBegin, &
I) || !usedAfterCoroBegin(
I))
397 if (!IsOffsetKnown) {
398 AliasOffetMap[&
I].reset();
401 if (!Inserted && Itr->second && *Itr->second !=
Offset) {
411static void collectFrameAlloca(AllocaInst *AI,
const coro::Shape &Shape,
412 const SuspendCrossingInfo &Checker,
413 SmallVectorImpl<AllocaInfo> &Allocas,
414 const DominatorTree &DT) {
415 if (Shape.CoroSuspends.empty())
420 if (AI == Shape.SwitchLowering.PromiseAlloca)
425 if (AI->hasMetadata(LLVMContext::MD_coro_outside_frame))
431 bool ShouldUseLifetimeStartInfo =
434 AllocaUseVisitor Visitor{AI->getDataLayout(), DT, Shape, Checker,
435 ShouldUseLifetimeStartInfo};
436 Visitor.visitPtr(*AI);
437 if (!Visitor.getShouldLiveOnFrame())
439 Allocas.emplace_back(AI, Visitor.getAliasesCopy(),
440 Visitor.getMayWriteBeforeCoroBegin());
449 for (
User *U :
A.users())
450 if (Checker.isDefinitionAcrossSuspend(
A, U))
451 Spills[&
A].push_back(cast<Instruction>(U));
468 if (
auto AI = dyn_cast<CoroAllocaAllocInst>(&
I)) {
470 if (isLocalAlloca(AI)) {
480 auto Alloc = lowerNonLocalAlloca(AI,
Shape, DeadInstructions);
483 if (Checker.isDefinitionAcrossSuspend(*
Alloc, U))
484 Spills[
Alloc].push_back(cast<Instruction>(U));
490 if (isa<CoroAllocaGetInst>(
I))
493 if (
auto *AI = dyn_cast<AllocaInst>(&
I)) {
494 collectFrameAlloca(AI,
Shape, Checker, Allocas, DT);
498 for (
User *U :
I.users())
499 if (Checker.isDefinitionAcrossSuspend(
I, U)) {
501 if (
I.getType()->isTokenTy())
503 "token definition is separated from the use by a suspend point");
504 Spills[&
I].push_back(cast<Instruction>(U));
515 for (
auto &Iter : Spills) {
516 auto *V = Iter.first;
521 if (Checker.isDefinitionAcrossSuspend(*V, DVR->Marker->MarkedInstr))
522 Spills[V].push_back(DVR->Marker->MarkedInstr);
536 auto collectUsers = [&](
Value *Def) {
537 for (
User *U : Def->users()) {
538 auto Inst = cast<Instruction>(U);
539 if (Inst->getParent() != CoroBegin->
getParent() ||
546 for (
auto &
I : Spills)
547 collectUsers(
I.first);
548 for (
auto &
I : Allocas)
549 collectUsers(
I.Alloca);
552 while (!Worklist.
empty()) {
554 for (
User *U : Def->users()) {
555 auto Inst = cast<Instruction>(U);
578 if (
auto *Arg = dyn_cast<Argument>(Def)) {
585 Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::Captures);
586 }
else if (
auto *CSI = dyn_cast<AnyCoroSuspendInst>(Def)) {
589 InsertPt = CSI->getParent()->getSingleSuccessor()->getFirstNonPHIIt();
591 auto *
I = cast<Instruction>(Def);
596 }
else if (
auto *
II = dyn_cast<InvokeInst>(
I)) {
599 auto *NewBB =
SplitEdge(
II->getParent(),
II->getNormalDest());
600 InsertPt = NewBB->getTerminator()->getIterator();
601 }
else if (isa<PHINode>(
I)) {
604 if (
auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->
getTerminator()))
605 InsertPt = splitBeforeCatchSwitch(CSI)->getIterator();
609 assert(!
I->isTerminator() &&
"unexpected terminator");
612 InsertPt =
I->getNextNode()->getIterator();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
iv Induction Variable Users
uint64_t IntrinsicInst * II
StandardInstrumentations SI(Mod->getContext(), Debug, VerifyEach)
This file provides a collection of visitors which walk the (instruction) uses of a pointer.
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
This class represents an incoming formal argument to a Function.
LLVM Basic Block Representation.
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
static CleanupPadInst * Create(Value *ParentPad, ArrayRef< Value * > Args={}, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static CleanupReturnInst * Create(Value *CleanupPad, BasicBlock *UnwindBB=nullptr, InsertPosition InsertBefore=nullptr)
This class represents the llvm.coro.begin or llvm.coro.begin.custom.abi instructions.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
LLVM_ABI void moveBefore(InstListType::iterator InsertPos)
Unlink this instruction from its current basic block and insert it into the basic block that MovePos ...
iterator end()
Get an iterator to the end of the SetVector.
iterator begin()
Get an iterator to the beginning of the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
A SetVector that performs no allocations if smaller than a certain size.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM Value Representation.
const ParentTy * getParent() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
@ BasicBlock
Various leaf nodes.
@ Async
The "async continuation" lowering, where each suspend point creates a single continuation function.
@ RetconOnce
The "unique returned-continuation" lowering, where each suspend point creates a single continuation f...
@ Retcon
The "returned-continuation" lowering, where each suspend point creates a single continuation function...
BasicBlock::iterator getSpillInsertionPt(const coro::Shape &, Value *Def, const DominatorTree &DT)
bool isSuspendBlock(BasicBlock *BB)
void sinkSpillUsesAfterCoroBegin(const DominatorTree &DT, CoroBeginInst *CoroBegin, coro::SpillInfo &Spills, SmallVectorImpl< coro::AllocaInfo > &Allocas)
Async and Retcon{Once} conventions assume that all spill uses can be sunk after the coro....
void collectSpillsFromArgs(SpillInfo &Spills, Function &F, const SuspendCrossingInfo &Checker)
void collectSpillsFromDbgInfo(SpillInfo &Spills, Function &F, const SuspendCrossingInfo &Checker)
void collectSpillsAndAllocasFromInsts(SpillInfo &Spills, SmallVector< AllocaInfo, 8 > &Allocas, SmallVector< Instruction *, 4 > &DeadInstructions, SmallVector< CoroAllocaAllocInst *, 4 > &LocalAllocas, Function &F, const SuspendCrossingInfo &Checker, const DominatorTree &DT, const coro::Shape &Shape)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI void findDbgValues(Value *V, SmallVectorImpl< DbgVariableRecord * > &DbgVariableRecords)
Finds the dbg.values describing a value.
auto successors(const MachineBasicBlock *BB)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI bool isManyPotentiallyReachableFromMany(SmallVectorImpl< BasicBlock * > &Worklist, const SmallPtrSetImpl< const BasicBlock * > &StopSet, const SmallPtrSetImpl< BasicBlock * > *ExclusionSet, const DominatorTree *DT=nullptr, const LoopInfo *LI=nullptr)
Determine whether there is a potentially a path from at least one block in 'Worklist' to at least one...
LLVM_ABI BasicBlock * SplitEdge(BasicBlock *From, BasicBlock *To, DominatorTree *DT=nullptr, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the edge connecting the specified blocks, and return the newly created basic block between From...
A MapVector that performs no allocations if smaller than a certain size.
CoroBeginInst * CoroBegin
BasicBlock::iterator getInsertPtAfterFramePtr() const