25typedef SmallPtrSet<BasicBlock *, 8> VisitedBlocksSet;
27static bool isNonSpilledIntrinsic(Instruction &
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()) {
64 VisitedOrFreeBBs.insert(FI->getParent());
67 return !isSuspendReachableFrom(AI->getParent(), VisitedOrFreeBBs);
74lowerNonLocalAlloca(CoroAllocaAllocInst *AI,
const coro::Shape &
Shape,
75 SmallVectorImpl<Instruction *> &DeadInsts) {
79 for (User *U : AI->users()) {
81 U->replaceAllUsesWith(
Alloc);
84 Builder.SetInsertPoint(FI);
91 DeadInsts.push_back(AI);
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 visitInsertElementInst(InsertElementInst &
I) {
191 void visitInsertValueInst(InsertValueInst &
I) {
196 void visitStoreInst(StoreInst &
SI) {
201 if (
SI.getValueOperand() !=
U->get())
214 auto IsSimpleStoreThenLoad = [&]() {
215 auto *AI = dyn_cast<AllocaInst>(
SI.getPointerOperand());
222 SmallVector<Instruction *, 4> StoreAliases = {AI};
223 while (!StoreAliases.empty()) {
225 for (User *U :
I->users()) {
228 if (
auto *LI = dyn_cast<LoadInst>(U)) {
235 if (
auto *S = dyn_cast<StoreInst>(U))
236 if (S->getPointerOperand() ==
I)
238 if (isa<LifetimeIntrinsic>(U))
242 if (
auto *BI = dyn_cast<BitCastInst>(U)) {
243 StoreAliases.push_back(BI);
253 if (!IsSimpleStoreThenLoad())
258 void visitMemIntrinsic(MemIntrinsic &
MI) { handleMayWrite(
MI); }
260 void visitBitCastInst(BitCastInst &BC) {
261 Base::visitBitCastInst(BC);
265 void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) {
266 Base::visitAddrSpaceCastInst(ASC);
270 void visitGetElementPtrInst(GetElementPtrInst &GEPI) {
272 Base::visitGetElementPtrInst(GEPI);
276 void visitIntrinsicInst(IntrinsicInst &
II) {
277 switch (
II.getIntrinsicID()) {
279 return Base::visitIntrinsicInst(
II);
280 case Intrinsic::lifetime_start:
281 LifetimeStarts.insert(&
II);
282 LifetimeStartBBs.push_back(
II.getParent());
284 case Intrinsic::lifetime_end:
285 LifetimeEndBBs.insert(
II.getParent());
290 void visitCallBase(CallBase &CB) {
291 for (
unsigned Op = 0, OpCount = CB.arg_size(); Op < OpCount; ++Op)
292 if (
U->get() == CB.getArgOperand(Op) && !CB.doesNotCapture(Op))
297 bool getShouldLiveOnFrame()
const {
298 if (!ShouldLiveOnFrame)
299 ShouldLiveOnFrame = computeShouldLiveOnFrame();
300 return *ShouldLiveOnFrame;
303 bool getMayWriteBeforeCoroBegin()
const {
return MayWriteBeforeCoroBegin; }
305 DenseMap<Instruction *, std::optional<APInt>> getAliasesCopy()
const {
306 assert(getShouldLiveOnFrame() &&
"This method should only be called if the "
307 "alloca needs to live on the frame.");
308 for (
const auto &
P : AliasOffetMap)
311 "created before CoroBegin.");
312 return AliasOffetMap;
316 const DominatorTree &DT;
317 const coro::Shape &CoroShape;
318 const SuspendCrossingInfo &Checker;
322 DenseMap<Instruction *, std::optional<APInt>> AliasOffetMap{};
323 SmallPtrSet<Instruction *, 4>
Users{};
324 SmallPtrSet<IntrinsicInst *, 2> LifetimeStarts{};
325 SmallVector<BasicBlock *> LifetimeStartBBs{};
326 SmallPtrSet<BasicBlock *, 2> LifetimeEndBBs{};
327 SmallPtrSet<const BasicBlock *, 2> CoroSuspendBBs{};
328 bool MayWriteBeforeCoroBegin{
false};
329 bool ShouldUseLifetimeStartInfo{
true};
331 mutable std::optional<bool> ShouldLiveOnFrame{};
333 bool computeShouldLiveOnFrame()
const {
338 if (ShouldUseLifetimeStartInfo && !LifetimeStarts.empty()) {
341 if (LifetimeEndBBs.empty())
349 &LifetimeEndBBs, &DT))
356 if (PI.isEscaped()) {
357 for (
auto *
A : LifetimeStarts) {
358 for (
auto *
B : LifetimeStarts) {
359 if (Checker.hasPathOrLoopCrossingSuspendPoint(
A->getParent(),
380 for (
auto *U1 :
Users)
381 for (
auto *U2 :
Users)
382 if (Checker.isDefinitionAcrossSuspend(*U1, U2))
388 void handleMayWrite(
const Instruction &
I) {
389 if (!DT.dominates(CoroShape.CoroBegin, &
I))
390 MayWriteBeforeCoroBegin =
true;
393 bool usedAfterCoroBegin(Instruction &
I) {
394 for (
auto &U :
I.uses())
395 if (DT.dominates(CoroShape.CoroBegin, U))
400 void handleAlias(Instruction &
I) {
404 if (DT.dominates(CoroShape.CoroBegin, &
I) || !usedAfterCoroBegin(
I))
407 if (!IsOffsetKnown) {
408 AliasOffetMap[&
I].reset();
410 auto [Itr,
Inserted] = AliasOffetMap.try_emplace(&
I, Offset);
411 if (!Inserted && Itr->second && *Itr->second != Offset) {
421static void collectFrameAlloca(AllocaInst *AI,
const coro::Shape &
Shape,
422 const SuspendCrossingInfo &Checker,
423 SmallVectorImpl<AllocaInfo> &Allocas,
424 const DominatorTree &DT) {
435 if (AI->hasMetadata(LLVMContext::MD_coro_outside_frame))
441 bool ShouldUseLifetimeStartInfo =
444 AllocaUseVisitor Visitor{AI->getDataLayout(), DT,
Shape, Checker,
445 ShouldUseLifetimeStartInfo};
446 Visitor.visitPtr(*AI);
447 if (!Visitor.getShouldLiveOnFrame())
449 Allocas.emplace_back(AI, Visitor.getAliasesCopy(),
450 Visitor.getMayWriteBeforeCoroBegin());
459 for (
User *U :
A.users())
480 if (isLocalAlloca(AI)) {
490 auto Alloc = lowerNonLocalAlloca(AI,
Shape, DeadInstructions);
504 collectFrameAlloca(AI,
Shape, Checker, Allocas, DT);
508 for (
User *U :
I.users())
511 if (
I.getType()->isTokenTy())
513 "token definition is separated from the use by a suspend point");
525 for (
auto &Iter : Spills) {
526 auto *V = Iter.first;
532 Spills[V].push_back(DVR->Marker->MarkedInstr);
546 auto collectUsers = [&](
Value *Def) {
547 for (
User *U : Def->users()) {
549 if (Inst->getParent() != CoroBegin->
getParent() ||
556 for (
auto &
I : Spills)
557 collectUsers(
I.first);
558 for (
auto &
I : Allocas)
559 collectUsers(
I.Alloca);
562 while (!Worklist.
empty()) {
564 for (
User *U : Def->users()) {
595 Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::Captures);
599 InsertPt = CSI->getParent()->getSingleSuccessor()->getFirstNonPHIIt();
609 auto *NewBB =
SplitEdge(
II->getParent(),
II->getNormalDest());
610 InsertPt = NewBB->getTerminator()->getIterator();
615 InsertPt = splitBeforeCatchSwitch(CSI)->getIterator();
619 assert(!
I->isTerminator() &&
"unexpected terminator");
622 InsertPt =
I->getNextNode()->getIterator();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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.
bool isDefinitionAcrossSuspend(BasicBlock *DefBB, User *U) const
LLVM Value Representation.
const ParentTy * getParent() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
@ BasicBlock
Various leaf nodes.
SmallMapVector< Value *, SmallVector< Instruction *, 2 >, 8 > SpillInfo
@ 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)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
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...
AllocaInst * PromiseAlloca
SmallVector< AnyCoroSuspendInst *, 4 > CoroSuspends
LLVM_ABI Value * emitAlloc(IRBuilder<> &Builder, Value *Size, CallGraph *CG) const
Allocate memory according to the rules of the active lowering.
SwitchLoweringStorage SwitchLowering
CoroBeginInst * CoroBegin
BasicBlock::iterator getInsertPtAfterFramePtr() const
LLVM_ABI void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const
Deallocate memory according to the rules of the active lowering.