23 #define DEBUG_TYPE "coro-elide"
35 Lowerer(
Module &M) : LowererBase(M) {}
38 bool shouldElide()
const;
55 if (ValueTy != IntrTy) {
82 if (
auto *
Call = dyn_cast<CallInst>(&
I))
86 if (
Call->isMustTailCall())
88 "marked as musttail");
89 Call->setTailCall(
false);
96 return cast<PointerType>(ArgType)->getElementType();
102 if (!isa<AllocaInst>(&
I))
121 for (
auto *CA : CoroAllocs) {
122 CA->replaceAllUsesWith(False);
123 CA->eraseFromParent();
130 auto *Frame =
new AllocaInst(FrameTy,
"", InsertPt);
134 for (
auto *CB : CoroBegins) {
135 CB->replaceAllUsesWith(FrameVoidPtr);
136 CB->eraseFromParent();
144 bool Lowerer::shouldElide()
const {
147 if (CoroAllocs.empty())
158 if (
auto *CB = dyn_cast<CoroBeginInst>(DA->getFrame()))
159 ReferencedCoroBegins.
insert(CB);
167 return ReferencedCoroBegins.
size() == CoroBegins.size();
179 if (
auto *CB = dyn_cast<CoroBeginInst>(U))
180 CoroBegins.push_back(CB);
181 else if (
auto *CA = dyn_cast<CoroAllocInst>(U))
182 CoroAllocs.push_back(CA);
183 else if (
auto *CF = dyn_cast<CoroFreeInst>(U))
184 CoroFrees.push_back(CF);
193 if (
auto *II = dyn_cast<CoroSubFnInst>(U))
194 switch (II->getIndex()) {
196 ResumeAddr.push_back(II);
199 DestroyAddr.push_back(II);
209 assert(Resumers &&
"PostSplit coro.id Info argument must refer to an array"
210 "of coroutine subfunctions");
211 auto *ResumeAddrConstant =
216 bool ShouldElide = shouldElide();
225 auto *FrameTy =
getFrameType(cast<Function>(ResumeAddrConstant));
226 elideHeapAllocations(CoroId->
getFunction(), FrameTy, AA);
238 if (
auto *SubFn = dyn_cast<CoroSubFnInst>(&
I))
242 if (DevirtAddr.
empty())
247 assert(DevirtFn &&
"coro.devirt.fn not found");
262 std::unique_ptr<Lowerer>
L;
264 bool doInitialization(
Module &M)
override {
266 L = llvm::make_unique<Lowerer>(M);
270 bool runOnFunction(
Function &F)
override {
274 bool Changed =
false;
283 if (
auto *CII = dyn_cast<CoroIdInst>(&
I))
284 if (CII->getInfo().isPostSplit())
286 if (CII->getCoroutine() != CII->getFunction())
287 L->CoroIds.push_back(CII);
293 AAResults &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
295 for (
auto *CII :
L->CoroIds)
296 Changed |=
L->processCoroId(CII, AA);
308 CoroElide,
"coro-elide",
309 "Coroutine frame allocation elision and indirect calls replacement",
false,
Pass interface - Implemented by all 'passes'.
void push_back(const T &Elt)
static ConstantInt * getFalse(LLVMContext &Context)
This represents the llvm.coro.alloc instruction.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
A Module instance is used to store all the information related to an LLVM module. ...
This class represents a function call, abstracting a target machine's calling convention.
libcalls Conditionally eliminate dead library calls
The two locations do not alias at all.
iv Induction Variable Users
AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
The main low level interface to the alias analysis implementation.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
static bool replaceDevirtTrigger(Function &F)
This class represents the llvm.coro.subfn.addr instruction.
LLVM_NODISCARD bool empty() const
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
This class represents a no-op cast from one type to another.
const Function * getFunction() const
Return the function this instruction belongs to.
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
static Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
#define CORO_PRESPLIT_ATTR
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.
This is an important base class in LLVM.
Pass * createCoroElidePass()
Analyze coroutines use sites, devirtualize resume/destroy calls and elide heap allocation for corouti...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Represent the analysis usage information of a pass.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
FunctionPass class - This class is used to implement most global optimizations.
static void removeTailCallAttribute(AllocaInst *Frame, AAResults &AA)
bool isPointerTy() const
True if this is an instance of PointerType.
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
coro Coroutine frame allocation elision and indirect calls replacement
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static Type * getFrameType(Function *Resume)
Representation for a specific memory location.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Type * getType() const
All values are typed, get the type of this value.
coro Coroutine frame allocation elision and indirect calls false
const BasicBlock & getEntryBlock() const
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
This class represents the llvm.coro.begin instruction.
ConstantArray - Constant Array Declarations.
iterator_range< user_iterator > users()
phi node Eliminate PHI nodes for register allocation
static Instruction * getFirstNonAllocaInTheEntryBlock(Function *F)
static bool operandReferences(CallInst *CI, AllocaInst *Frame, AAResults &AA)
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
static void replaceWithConstant(Constant *Value, SmallVectorImpl< CoroSubFnInst * > &Users)
iterator_range< value_op_iterator > operand_values()
#define CORO_DEVIRT_TRIGGER_FN
void replaceCoroFree(CoroIdInst *CoroId, bool Elide)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
const ArgumentListType & getArgumentList() const
Get the underlying elements of the Function...
bool declaresIntrinsics(Module &M, std::initializer_list< StringRef >)
static Constant * getExtractValue(Constant *Agg, ArrayRef< unsigned > Idxs, Type *OnlyIfReducedTy=nullptr)
inst_range instructions(Function *F)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object...
INITIALIZE_PASS_BEGIN(CoroElide,"coro-elide","Coroutine frame allocation elision and indirect calls replacement", false, false) INITIALIZE_PASS_END(CoroElide
bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI=nullptr, const DominatorTree *DT=nullptr, AssumptionCache *AC=nullptr)
Replace all uses of 'I' with 'SimpleV' and simplify the uses recursively.
an instruction to allocate memory on the stack