23 #include "llvm/Config/llvm-config.h" 37 #define DEBUG_TYPE "coro-suspend-crossing" 43 class BlockToIndexMapping {
47 size_t size()
const {
return V.
size(); }
57 assert(
I != V.
end() && *
I == BB &&
"BasicBlockNumberng: Unknown block");
78 struct SuspendCrossingInfo {
79 BlockToIndexMapping Mapping;
90 BasicBlock *BB = Mapping.indexToBlock(&BD - &Block[0]);
95 return Block[Mapping.blockToIndex(BB)];
104 size_t const DefIndex = Mapping.blockToIndex(DefBB);
105 size_t const UseIndex = Mapping.blockToIndex(UseBB);
107 assert(Block[UseIndex].Consumes[DefIndex] &&
"use must consume def");
108 bool const Result = Block[UseIndex].Kills[DefIndex];
110 <<
" answer is " << Result <<
"\n");
114 bool isDefinitionAcrossSuspend(
BasicBlock *DefBB,
User *U)
const {
115 auto *
I = cast<Instruction>(U);
119 if (
auto *PN = dyn_cast<PHINode>(
I))
120 if (PN->getNumIncomingValues() > 1)
124 return hasPathCrossingSuspendPoint(DefBB, UseBB);
127 bool isDefinitionAcrossSuspend(
Argument &A,
User *U)
const {
132 return isDefinitionAcrossSuspend(I.
getParent(), U);
137 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 140 dbgs() << Label <<
":";
141 for (
size_t I = 0,
N = BV.
size();
I <
N; ++
I)
143 dbgs() <<
" " << Mapping.indexToBlock(I)->getName();
148 for (
size_t I = 0,
N = Block.size();
I <
N; ++
I) {
151 dump(
" Consumes", Block[
I].Consumes);
152 dump(
" Kills", Block[
I].Kills);
160 const size_t N = Mapping.size();
164 for (
size_t I = 0;
I <
N; ++
I) {
166 B.Consumes.resize(N);
175 getBlockData(CE->getParent()).End =
true;
183 auto &
B = getBlockData(SuspendBlock);
185 B.Kills |=
B.Consumes;
188 markSuspendBlock(CSI);
202 for (
size_t I = 0;
I <
N; ++
I) {
206 auto SuccNo = Mapping.blockToIndex(
SI);
210 auto &S = Block[SuccNo];
211 auto SavedConsumes = S.Consumes;
212 auto SavedKills = S.Kills;
215 S.Consumes |=
B.Consumes;
221 S.Kills |=
B.Consumes;
226 S.Kills |= S.Consumes;
236 S.Kills.reset(SuccNo);
240 Changed |= (S.Kills != SavedKills) || (S.Consumes != SavedConsumes);
242 if (S.Kills != SavedKills) {
248 if (S.Consumes != SavedConsumes) {
259 #undef DEBUG_TYPE // "coro-suspend-crossing" 260 #define DEBUG_TYPE "coro-frame" 269 unsigned FieldNo = 0;
283 unsigned fieldIndex()
const {
284 assert(FieldNo &&
"Accessing unassigned field");
287 void setFieldIndex(
unsigned FieldNumber) {
288 assert(!FieldNo &&
"Reassigning field number");
289 FieldNo = FieldNumber;
300 dbgs() <<
"------------- " << Title <<
"--------------\n";
301 Value *CurrentValue =
nullptr;
302 for (
auto const &
E : Spills) {
303 if (CurrentValue !=
E.def()) {
304 CurrentValue =
E.def();
305 CurrentValue->
dump();
318 struct PaddingCalculator {
321 unsigned StructSize = 0;
328 void addType(
Type *Ty) {
330 if ((StructSize & (TyAlign - 1)) != 0)
331 StructSize =
alignTo(StructSize, TyAlign);
337 for (
auto *Ty : Types)
341 unsigned computePadding(
Type *Ty,
unsigned ForcedAlignment) {
343 auto Natural =
alignTo(StructSize, TyAlign);
344 auto Forced =
alignTo(StructSize, ForcedAlignment);
347 if (Natural != Forced)
348 return std::max(Natural, Forced) - StructSize;
355 ArrayType *getPaddingType(
Type *Ty,
unsigned ForcedAlignment) {
356 if (
auto Padding = computePadding(Ty, ForcedAlignment))
376 PaddingCalculator Padder(C, DL);
378 Name.append(
".Frame");
383 auto *FnPtrTy = FnTy->getPointerTo();
392 Value *CurrentDef =
nullptr;
394 Padder.addTypes(Types);
397 for (
auto &S : Spills) {
398 if (CurrentDef == S.def())
401 CurrentDef = S.def();
407 if (
auto *AI = dyn_cast<AllocaInst>(CurrentDef)) {
408 Ty = AI->getAllocatedType();
409 if (
unsigned AllocaAlignment = AI->getAlignment()) {
412 if (
auto PaddingTy = Padder.getPaddingType(Ty, AllocaAlignment)) {
413 Types.push_back(PaddingTy);
414 Padder.addType(PaddingTy);
420 S.setFieldIndex(Types.size());
477 cast<Instruction>(Builder.CreateBitCast(CB, FramePtrTy,
"FramePtr"));
478 Type *FrameTy = FramePtrTy->getElementType();
480 Value *CurrentValue =
nullptr;
482 Value *CurrentReload =
nullptr;
497 auto CreateReload = [&](
Instruction *InsertBefore) {
498 assert(Index &&
"accessing unassigned field number");
499 Builder.SetInsertPoint(InsertBefore);
500 auto *
G = Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0, Index,
502 Twine(
".reload.addr"));
503 return isa<AllocaInst>(CurrentValue)
505 : Builder.CreateLoad(
G,
509 for (
auto const &
E : Spills) {
511 if (CurrentValue !=
E.def()) {
512 CurrentValue =
E.def();
513 CurrentBlock =
nullptr;
514 CurrentReload =
nullptr;
516 Index =
E.fieldIndex();
518 if (
auto *AI = dyn_cast<AllocaInst>(CurrentValue)) {
522 if (!AI->isStaticAlloca())
529 if (isa<Argument>(CurrentValue)) {
533 InsertPt = FramePtr->getNextNode();
534 }
else if (
auto *II = dyn_cast<InvokeInst>(CurrentValue)) {
537 auto NewBB =
SplitEdge(II->getParent(), II->getNormalDest());
538 InsertPt = NewBB->getTerminator();
539 }
else if (dyn_cast<PHINode>(CurrentValue)) {
542 if (
auto *CSI = dyn_cast<CatchSwitchInst>(DefBlock->
getTerminator()))
549 assert(!cast<Instruction>(
E.def())->isTerminator() &&
550 "unexpected terminator");
551 InsertPt = cast<Instruction>(
E.def())->getNextNode();
554 Builder.SetInsertPoint(InsertPt);
555 auto *
G = Builder.CreateConstInBoundsGEP2_32(
556 FrameTy, FramePtr, 0, Index,
558 Builder.CreateStore(CurrentValue,
G);
563 if (CurrentBlock !=
E.userBlock()) {
564 CurrentBlock =
E.userBlock();
571 if (
auto *PN = dyn_cast<PHINode>(
E.user())) {
572 assert(PN->getNumIncomingValues() == 1 &&
"unexpected number of incoming " 573 "values in the PHINode");
574 PN->replaceAllUsesWith(CurrentReload);
575 PN->eraseFromParent();
580 E.user()->replaceUsesOfWith(CurrentValue, CurrentReload);
583 BasicBlock *FramePtrBB = FramePtr->getParent();
591 for (
auto &
P : Allocas) {
593 Builder.CreateConstInBoundsGEP2_32(FrameTy, FramePtr, 0,
P.second);
596 G->takeName(
P.first);
597 P.first->replaceAllUsesWith(
G);
598 P.first->eraseFromParent();
605 if (
auto *II = dyn_cast<InvokeInst>(TI))
606 II->setUnwindDest(Succ);
607 else if (
auto *CS = dyn_cast<CatchSwitchInst>(TI))
608 CS->setUnwindDest(Succ);
609 else if (
auto *CR = dyn_cast<CleanupReturnInst>(TI))
610 CR->setUnwindDest(Succ);
619 PHINode *LandingPadReplacement) {
626 if (LandingPadReplacement == PN)
637 assert(BBIdx != (
unsigned)-1 &&
"Invalid PHI Index!");
646 PHINode *LandingPadReplacement) {
648 if (!LandingPadReplacement && !PadInst->
isEHPad())
655 if (LandingPadReplacement) {
656 auto *NewLP = OriginalPad->
clone();
662 Value *ParentPad =
nullptr;
663 if (
auto *FuncletPad = dyn_cast<FuncletPadInst>(PadInst))
664 ParentPad = FuncletPad->getParentPad();
665 else if (
auto *CatchSwitch = dyn_cast<CatchSwitchInst>(PadInst))
666 ParentPad = CatchSwitch->getParentPad();
699 if ((LandingPad = dyn_cast_or_null<LandingPadInst>(BB.
getFirstNonPHI()))) {
713 IncomingBB->setName(BB.
getName() +
Twine(
".from.") + Pred->getName());
714 auto *PN = cast<PHINode>(&BB.
front());
716 int Index = PN->getBasicBlockIndex(IncomingBB);
717 Value *V = PN->getIncomingValue(Index);
720 &IncomingBB->
front());
722 PN->setIncomingValue(Index, InputV);
724 }
while (PN != ReplPHI);
739 if (
auto *PN = dyn_cast<PHINode>(&BB.front()))
740 if (PN->getNumIncomingValues() > 1)
750 return isa<CastInst>(&V) || isa<GetElementPtrInst>(&V) ||
751 isa<BinaryOperator>(&V) || isa<CmpInst>(&V) || isa<SelectInst>(&V);
757 return isa<CoroIdInst>(&
I) || isa<CoroSaveInst>(&I) ||
758 isa<CoroSuspendInst>(&
I);
769 for (
auto const &
E : Spills) {
771 if (CurrentDef !=
E.def()) {
772 CurrentDef = cast<Instruction>(
E.def());
773 CurrentBlock =
nullptr;
774 CurrentMaterialization =
nullptr;
778 if (CurrentBlock !=
E.userBlock()) {
779 CurrentBlock =
E.userBlock();
780 CurrentMaterialization = cast<Instruction>(CurrentDef)->clone();
786 if (
auto *PN = dyn_cast<PHINode>(
E.user())) {
787 assert(PN->getNumIncomingValues() == 1 &&
"unexpected number of incoming " 788 "values in the PHINode");
789 PN->replaceAllUsesWith(CurrentMaterialization);
790 PN->eraseFromParent();
796 E.user()->replaceUsesOfWith(CurrentDef, CurrentMaterialization);
814 Value *CurrentValue =
nullptr;
816 for (
auto const &
E : Spills) {
817 if (CurrentValue ==
E.def())
820 CurrentValue =
E.def();
831 if (!DT.
dominates(CoroBegin, cast<Instruction>(UI)))
833 " dominated by CoroBegin");
843 I->moveBefore(InsertPt);
850 if (&BB->front() ==
I) {
851 if (BB->getSinglePredecessor()) {
856 return BB->splitBasicBlock(I, Name);
893 SuspendCrossingInfo Checker(F, Shape);
898 for (
int Repeat = 0; Repeat < 4; ++Repeat) {
902 for (
User *U :
I.users())
903 if (Checker.isDefinitionAcrossSuspend(
I, U))
904 Spills.emplace_back(&
I, U);
917 for (
User *U : A.users())
918 if (Checker.isDefinitionAcrossSuspend(A, U))
919 Spills.emplace_back(&A, U);
931 for (
User *U :
I.users())
932 if (Checker.isDefinitionAcrossSuspend(
I, U)) {
934 if (
I.getType()->isTokenTy())
936 "token definition is separated from the use by a suspend point");
937 Spills.emplace_back(&
I, U);
static Instruction * splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch)
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A parsed version of the target data layout string in and methods for querying it. ...
static IntegerType * getInt1Ty(LLVMContext &C)
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
This class represents an incoming formal argument to a Function.
CoroBeginInst * CoroBegin
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This class represents lattice values for constants.
void push_back(const T &Elt)
static void updatePhiNodes(BasicBlock *DestBB, BasicBlock *OldPred, BasicBlock *NewPred, PHINode *LandingPadReplacement)
static void rewritePHIs(BasicBlock &BB)
static void setUnwindEdgeTo(Instruction *TI, BasicBlock *Succ)
static void dump(StringRef Title, SpillInfo const &Spills)
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
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...
LLVMContext & getContext() const
Get the context in which this basic block lives.
iterator begin()
Instruction iterator methods.
BasicBlock * SplitEdge(BasicBlock *From, BasicBlock *To, DominatorTree *DT=nullptr, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr)
Split the edge connecting specified block.
void dump() const
Support for debugging, callable in GDB: V->dump()
amdgpu Simplify well known AMD library false Value Value const Twine & Name
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
int getBasicBlockIndex(const BasicBlock *BB) const
Return the first index of the specified basic block in the value list for this PHI.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
PointerType * getType() const
Overload to return most specific pointer type.
Class to represent struct types.
static bool materializable(Instruction &V)
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
This represents the llvm.coro.suspend instruction.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
void setName(const Twine &Name)
Change the name of the value.
AllocaInst * getPromise() const
Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following: ...
Type * getType() const
All values are typed, get the type of this value.
Class to represent array types.
auto lower_bound(R &&Range, ForwardIt I) -> decltype(adl_begin(Range))
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Value * getParentPad() const
SmallVector< CoroSuspendInst *, 4 > CoroSuspends
void setBody(ArrayRef< Type *> Elements, bool isPacked=false)
Specify a body for an opaque identified type.
void takeName(Value *V)
Transfer the name from V to this value.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree...
Class to represent pointers.
const BasicBlock & getEntryBlock() const
The landingpad instruction holds all of the information necessary to generate correct exception handl...
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
static void moveSpillUsesAfterCoroBegin(Function &F, SpillInfo const &Spills, CoroBeginInst *CoroBegin)
const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction...
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
This is an important class for using LLVM in a threaded context.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
const Instruction & front() const
Interval::pred_iterator pred_begin(Interval *I)
pred_begin/pred_end - define methods so that Intervals may be used just like BasicBlocks can with the...
static Type * getVoidTy(LLVMContext &C)
This represents the llvm.coro.end instruction.
static FunctionType * get(Type *Result, ArrayRef< Type *> Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Interval::pred_iterator pred_end(Interval *I)
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
bool LowerDbgDeclare(Function &F)
Lowers llvm.dbg.declare intrinsics into appropriate set of llvm.dbg.value intrinsics.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static bool isCoroutineStructureIntrinsic(Instruction &I)
void sort(IteratorTy Start, IteratorTy End)
Iterator for intrusive lists based on ilist_node.
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
void setIncomingBlock(unsigned i, BasicBlock *BB)
static CleanupPadInst * Create(Value *ParentPad, ArrayRef< Value *> Args=None, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
bool dominates(const Instruction *Def, const Use &U) const
Return true if Def dominates a use in User.
unsigned getABITypeAlignment(Type *Ty) const
Returns the minimum ABI-required alignment for the specified type.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
void buildCoroutineFrame(Function &F, Shape &Shape)
static BranchInst * Create(BasicBlock *IfTrue, Instruction *InsertBefore=nullptr)
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
unsigned Log2_64_Ceil(uint64_t Value)
Return the ceil log base 2 of the specified value, 64 if the value is zero.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
This class represents the llvm.coro.begin instruction.
A range adaptor for a pair of iterators.
iterator_range< user_iterator > users()
static BasicBlock * splitBlockIfNotFirst(Instruction *I, const Twine &Name)
uint64_t getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
static void rewriteMaterializableInstructions(IRBuilder<> &IRB, SpillInfo const &Spills)
const Function * getParent() const
void emplace_back(ArgTypes &&... Args)
StringRef getName() const
Return a constant reference to the value's name.
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
const Function * getParent() const
Return the enclosing method, or null if none.
static Instruction * insertSpills(SpillInfo &Spills, coro::Shape &Shape)
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
size_type size() const
size - Returns the number of bits in this bitvector.
BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
CoroIdInst * getId() const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SmallVector< CoroEndInst *, 4 > CoroEnds
LLVM_NODISCARD char front() const
front - Get the first character in the string.
AllocaInst * PromiseAlloca
static BasicBlock * ehAwareSplitEdge(BasicBlock *BB, BasicBlock *Succ, LandingPadInst *OriginalPad, PHINode *LandingPadReplacement)
static StructType * buildFrameType(Function &F, coro::Shape &Shape, SpillInfo &Spills)
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
succ_range successors(Instruction *I)
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
static CleanupReturnInst * Create(Value *CleanupPad, BasicBlock *UnwindBB=nullptr, Instruction *InsertBefore=nullptr)
static const Function * getParent(const Value *V)
bool isEHPad() const
Return true if the instruction is a variety of EH-block.
StringRef - Represent a constant reference to a string, i.e.
inst_range instructions(Function *F)
BasicBlock * AllocaSpillBlock
static void splitAround(Instruction *I, const Twine &Name)
static IntegerType * getInt8Ty(LLVMContext &C)
CoroSaveInst * getCoroSave() const
Type * getElementType() const
iterator_range< arg_iterator > args()
A wrapper class for inspecting calls to intrinsic functions.
const BasicBlock * getParent() const