LLVM 24.0.0git
CoroSplit.cpp File Reference
#include "llvm/Transforms/Coroutines/CoroSplit.h"
#include "CoroCloner.h"
#include "CoroInternal.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PriorityWorklist.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ProfDataUtils.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Coroutines/MaterializationUtils.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/CallGraphUpdater.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <iterator>

Go to the source code of this file.

Macros

#define DEBUG_TYPE   "coro-split"

Functions

static void lowerAwaitSuspend (IRBuilder<> &Builder, CoroAwaitSuspendInst *CB, coro::Shape &Shape)
static void lowerAwaitSuspends (Function &F, coro::Shape &Shape)
static void maybeFreeRetconStorage (IRBuilder<> &Builder, const coro::Shape &Shape, Value *FramePtr, CallGraph *CG)
static ValuecreateSwitchDestroyPtr (const coro::Shape &Shape, IRBuilder<> &Builder, Value *FramePtr)
 Create a pointer to the switch destroy function field in the coroutine frame.
static void replaceSwitchResumeCoroFree (const coro::Shape &Shape, Function &Resume, Function &Cleanup)
 Make resume-clone coro.free conditional on whether the frame is elided.
static bool replaceCoroEndAsync (AnyCoroEndInst *End)
 Replace an llvm.coro.end.async.
static void replaceFallthroughCoroEnd (AnyCoroEndInst *End, const coro::Shape &Shape, Value *FramePtr, bool InRamp, CallGraph *CG)
 Replace a non-unwind call to llvm.coro.end.
static ValuecreateSwitchIndexPtr (const coro::Shape &Shape, IRBuilder<> &Builder, Value *FramePtr)
 Create a pointer to the switch index field in the coroutine frame.
static void markCoroutineAsDone (IRBuilder<> &Builder, const coro::Shape &Shape, Value *FramePtr)
static void replaceUnwindCoroEnd (AnyCoroEndInst *End, const coro::Shape &Shape, Value *FramePtr, bool InRamp, CallGraph *CG)
 Replace an unwind call to llvm.coro.end.
static void replaceCoroEnd (AnyCoroEndInst *End, const coro::Shape &Shape, Value *FramePtr, bool InRamp, CallGraph *CG)
static FunctionTypegetFunctionTypeFromAsyncSuspend (AnyCoroSuspendInst *Suspend)
static FunctioncreateCloneDeclaration (Function &OrigF, coro::Shape &Shape, const Twine &Suffix, Module::iterator InsertBefore, AnyCoroSuspendInst *ActiveSuspend)
static void replaceSwiftErrorOps (Function &F, coro::Shape &Shape, ValueToValueMapTy *VMap)
static SmallVector< DbgVariableRecord * > collectDbgVariableRecords (Function &F)
 Returns all debug records in F.
static void updateScopeLine (Instruction *ActiveSuspend, DISubprogram &SPToUpdate)
 Adjust the scope line of the funclet to the first line number after the suspend point.
static void addFramePointerAttrs (AttributeList &Attrs, LLVMContext &Context, unsigned ParamIndex, uint64_t Size, Align Alignment, bool NoAlias)
static void addAsyncContextAttrs (AttributeList &Attrs, LLVMContext &Context, unsigned ParamIndex)
static void addSwiftSelfAttrs (AttributeList &Attrs, LLVMContext &Context, unsigned ParamIndex)
static void updateAsyncFuncPointerContextSize (coro::Shape &Shape)
static void replaceFrameSizeAndAlignment (coro::Shape &Shape)
static void postSplitCleanup (Function &F)
static void handleNoSuspendCoroutine (coro::Shape &Shape)
static bool hasCallsInBlockBetween (iterator_range< BasicBlock::iterator > R)
static bool hasCallsInBlocksBetween (BasicBlock *SaveBB, BasicBlock *ResDesBB)
static bool hasCallsBetween (Instruction *Save, Instruction *ResumeOrDestroy)
static bool simplifySuspendPoint (CoroSuspendInst *Suspend, CoroBeginInst *CoroBegin)
static void simplifySuspendPoints (coro::Shape &Shape)
static void replaceAsyncResumeFunction (CoroSuspendAsyncInst *Suspend, Value *Continuation)
static void coerceArguments (IRBuilder<> &Builder, FunctionType *FnTy, ArrayRef< Value * > FnArgs, SmallVectorImpl< Value * > &CallArgs)
 Coerce the arguments in FnArgs according to FnTy in CallArgs.
static void removeCoroEndsFromRampFunction (const coro::Shape &Shape)
 Remove calls to llvm.coro.end in the original function.
static void removeCoroIsInRampFromRampFunction (const coro::Shape &Shape)
static bool hasSafeElideCaller (Function &F)
static void doSplitCoroutine (Function &F, SmallVectorImpl< Function * > &Clones, coro::BaseABI &ABI, TargetTransformInfo &TTI, bool OptimizeFrame)
static LazyCallGraph::SCCupdateCallGraphAfterCoroutineSplit (LazyCallGraph::Node &N, const coro::Shape &Shape, const SmallVectorImpl< Function * > &Clones, LazyCallGraph::SCC &C, LazyCallGraph &CG, CGSCCAnalysisManager &AM, CGSCCUpdateResult &UR, FunctionAnalysisManager &FAM)
static void replacePrepare (CallInst *Prepare, LazyCallGraph &CG, LazyCallGraph::SCC &C)
 Replace a call to llvm.coro.prepare.retcon.
static bool replaceAllPrepares (Function *PrepareFn, LazyCallGraph &CG, LazyCallGraph::SCC &C)
static void addPrepareFunction (const Module &M, SmallVectorImpl< Function * > &Fns, StringRef Name)
static std::unique_ptr< coro::BaseABICreateNewABI (Function &F, coro::Shape &S, std::function< bool(Instruction &)> IsMatCallback, const SmallVector< CoroSplitPass::BaseABITy > GenCustomABIs)

Macro Definition Documentation

◆ DEBUG_TYPE

#define DEBUG_TYPE   "coro-split"

Definition at line 83 of file CoroSplit.cpp.

Function Documentation

◆ addAsyncContextAttrs()

void addAsyncContextAttrs ( AttributeList & Attrs,
LLVMContext & Context,
unsigned ParamIndex )
static

Definition at line 925 of file CoroSplit.cpp.

Referenced by llvm::coro::BaseCloner::create().

◆ addFramePointerAttrs()

void addFramePointerAttrs ( AttributeList & Attrs,
LLVMContext & Context,
unsigned ParamIndex,
uint64_t Size,
Align Alignment,
bool NoAlias )
static

Definition at line 910 of file CoroSplit.cpp.

References Size.

Referenced by llvm::coro::BaseCloner::create().

◆ addPrepareFunction()

void addPrepareFunction ( const Module & M,
SmallVectorImpl< Function * > & Fns,
StringRef Name )
static

◆ addSwiftSelfAttrs()

void addSwiftSelfAttrs ( AttributeList & Attrs,
LLVMContext & Context,
unsigned ParamIndex )
static

Definition at line 932 of file CoroSplit.cpp.

Referenced by llvm::coro::BaseCloner::create().

◆ coerceArguments()

void coerceArguments ( IRBuilder<> & Builder,
FunctionType * FnTy,
ArrayRef< Value * > FnArgs,
SmallVectorImpl< Value * > & CallArgs )
static

Coerce the arguments in FnArgs according to FnTy in CallArgs.

Definition at line 1774 of file CoroSplit.cpp.

References assert(), getType(), llvm::SmallVectorTemplateBase< T, bool >::push_back(), and llvm::ArrayRef< T >::size().

Referenced by llvm::coro::createMustTailCall().

◆ collectDbgVariableRecords()

SmallVector< DbgVariableRecord * > collectDbgVariableRecords ( Function & F)
static

Returns all debug records in F.

Definition at line 688 of file CoroSplit.cpp.

References F, llvm::filterDbgVars(), I, instructions, and llvm::SmallVectorTemplateBase< T, bool >::push_back().

Referenced by doSplitCoroutine(), and llvm::coro::BaseCloner::salvageDebugInfo().

◆ createCloneDeclaration()

◆ CreateNewABI()

◆ createSwitchDestroyPtr()

Value * createSwitchDestroyPtr ( const coro::Shape & Shape,
IRBuilder<> & Builder,
Value * FramePtr )
static

Create a pointer to the switch destroy function field in the coroutine frame.

Definition at line 172 of file CoroSplit.cpp.

References llvm::coro::Shape::SwitchLoweringStorage::DestroyOffset, FramePtr, llvm::Type::getInt64Ty(), llvm::Offset, and llvm::coro::Shape::SwitchLowering.

Referenced by replaceSwitchResumeCoroFree().

◆ createSwitchIndexPtr()

Value * createSwitchIndexPtr ( const coro::Shape & Shape,
IRBuilder<> & Builder,
Value * FramePtr )
static

Create a pointer to the switch index field in the coroutine frame.

Definition at line 358 of file CoroSplit.cpp.

References FramePtr, llvm::Type::getInt64Ty(), llvm::coro::Shape::SwitchLoweringStorage::IndexOffset, llvm::Offset, and llvm::coro::Shape::SwitchLowering.

Referenced by markCoroutineAsDone().

◆ doSplitCoroutine()

◆ getFunctionTypeFromAsyncSuspend()

◆ handleNoSuspendCoroutine()

◆ hasCallsBetween()

◆ hasCallsInBlockBetween()

bool hasCallsInBlockBetween ( iterator_range< BasicBlock::iterator > R)
static

Definition at line 1265 of file CoroSplit.cpp.

References I, and llvm::isa().

Referenced by hasCallsBetween(), and hasCallsInBlocksBetween().

◆ hasCallsInBlocksBetween()

◆ hasSafeElideCaller()

bool hasSafeElideCaller ( Function & F)
static

Definition at line 2072 of file CoroSplit.cpp.

References llvm::dyn_cast(), and F.

Referenced by doSplitCoroutine().

◆ lowerAwaitSuspend()

◆ lowerAwaitSuspends()

void lowerAwaitSuspends ( Function & F,
coro::Shape & Shape )
static

Definition at line 154 of file CoroSplit.cpp.

References llvm::coro::Shape::CoroAwaitSuspends, F, and lowerAwaitSuspend().

Referenced by doSplitCoroutine().

◆ markCoroutineAsDone()

◆ maybeFreeRetconStorage()

◆ postSplitCleanup()

void postSplitCleanup ( Function & F)
static

◆ removeCoroEndsFromRampFunction()

void removeCoroEndsFromRampFunction ( const coro::Shape & Shape)
static

Remove calls to llvm.coro.end in the original function.

Definition at line 2053 of file CoroSplit.cpp.

References llvm::coro::Shape::ABI, llvm::coro::Shape::CoroEnds, llvm::Instruction::eraseFromParent(), llvm::coro::Shape::FramePtr, replaceCoroEnd(), and llvm::coro::Switch.

Referenced by doSplitCoroutine().

◆ removeCoroIsInRampFromRampFunction()

void removeCoroIsInRampFromRampFunction ( const coro::Shape & Shape)
static

Definition at line 2064 of file CoroSplit.cpp.

References llvm::coro::Shape::CoroIsInRampInsts, llvm::ConstantInt::getTrue(), and II.

Referenced by doSplitCoroutine().

◆ replaceAllPrepares()

bool replaceAllPrepares ( Function * PrepareFn,
LazyCallGraph & CG,
LazyCallGraph::SCC & C )
static

◆ replaceAsyncResumeFunction()

◆ replaceCoroEnd()

◆ replaceCoroEndAsync()

bool replaceCoroEndAsync ( AnyCoroEndInst * End)
static

Replace an llvm.coro.end.async.

Will inline the must tail call function call if there is one.

Returns
true if cleanup of the coro.end block is needed, false otherwise.

Definition at line 223 of file CoroSplit.cpp.

References assert(), llvm::cast(), llvm::dyn_cast(), llvm::ilist_node_impl< OptionsT >::getIterator(), llvm::ilist_detail::node_parent_access< NodeTy, ParentTy >::getParent(), and llvm::InlineFunction().

Referenced by replaceFallthroughCoroEnd().

◆ replaceFallthroughCoroEnd()

◆ replaceFrameSizeAndAlignment()

◆ replacePrepare()

◆ replaceSwiftErrorOps()

◆ replaceSwitchResumeCoroFree()

void replaceSwitchResumeCoroFree ( const coro::Shape & Shape,
Function & Resume,
Function & Cleanup )
static

Make resume-clone coro.free conditional on whether the frame is elided.

The destroy slot holds the cleanup clone for an elided frame and the destroy clone for a heap frame. Load it before user code can reentrantly destroy the enclosing caller frame, then use the cached comparison to suppress only the deallocation. The resume clone has already performed the shared coroutine cleanup, so calling either clone here would run that cleanup twice.

Definition at line 186 of file CoroSplit.cpp.

References llvm::applyProfMetadataIfEnabled(), llvm::cast(), Cleanup, llvm::IRBuilderBase::CreateICmpEQ(), llvm::IRBuilderBase::CreateLoad(), llvm::IRBuilderBase::CreatePointerCast(), createSwitchDestroyPtr(), DEBUG_TYPE, llvm::dyn_cast(), FramePtr, llvm::ConstantPointerNull::get(), llvm::Function::getArg(), llvm::Function::getEntryBlock(), llvm::Instruction::getFunction(), llvm::coro::Shape::getSwitchResumePointerType(), llvm::BasicBlock::getTerminator(), llvm::Value::getType(), llvm::Null, llvm::SmallVectorTemplateBase< T, bool >::push_back(), llvm::Value::replaceAllUsesWith(), and llvm::setExplicitlyUnknownBranchWeightsIfProfiled().

◆ replaceUnwindCoroEnd()

◆ simplifySuspendPoint()

◆ simplifySuspendPoints()

◆ updateAsyncFuncPointerContextSize()

◆ updateCallGraphAfterCoroutineSplit()

◆ updateScopeLine()

void updateScopeLine ( Instruction * ActiveSuspend,
DISubprogram & SPToUpdate )
static

Adjust the scope line of the funclet to the first line number after the suspend point.

This avoids a jump in the line table from the function declaration (where prologue instructions are attributed to) to the suspend point. Only adjust the scope line when the files are the same. If no candidate line number is found, fallback to the line of ActiveSuspend.

Definition at line 863 of file CoroSplit.cpp.

References DL, llvm::dyn_cast_or_null(), llvm::BasicBlock::end(), llvm::Instruction::getDebugLoc(), llvm::DIScope::getFile(), llvm::ilist_node_impl< OptionsT >::getIterator(), llvm::ilist_node_with_parent< NodeTy, ParentTy, Options >::getNextNode(), llvm::skipDebugIntrinsics(), and llvm::Successor.

Referenced by llvm::coro::BaseCloner::create().