67#define DEBUG_TYPE "expand-variadics"
75 cl::init(ExpandVariadicsMode::Unspecified),
77 "Use the implementation defaults"),
78 clEnumValN(ExpandVariadicsMode::Disable,
"disable",
79 "Disable the pass entirely"),
80 clEnumValN(ExpandVariadicsMode::Optimize,
"optimize",
81 "Optimise without changing ABI"),
82 clEnumValN(ExpandVariadicsMode::Lowering,
"lowering",
83 "Change variadic calling convention")));
85bool commandLineOverride() {
86 return ExpandVariadicsModeOption != ExpandVariadicsMode::Unspecified;
94class VariadicABIInfo {
96 VariadicABIInfo() =
default;
99 static std::unique_ptr<VariadicABIInfo> create(
const Triple &
T);
102 virtual bool enableForTarget() = 0;
107 virtual bool vaListPassedInSSARegister() = 0;
113 virtual Type *vaListParameterType(
Module &M) = 0;
122 struct VAArgSlotInfo {
129 bool vaEndIsNop() {
return true; }
130 bool vaCopyIsMemcpy() {
return true; }
132 virtual ~VariadicABIInfo() =
default;
166 std::unique_ptr<VariadicABIInfo> ABI;
170 Mode(commandLineOverride() ? ExpandVariadicsModeOption : Mode) {}
198 template <Intrinsic::ID ID,
typename InstructionType>
201 bool Changed =
false;
204 getPreexistingDeclaration(&M,
ID, {IntrinsicArgType})) {
206 if (
auto *
I = dyn_cast<InstructionType>(U))
207 Changed |= expandVAIntrinsicCall(Builder,
DL,
I);
209 if (Intrinsic->use_empty())
210 Intrinsic->eraseFromParent();
216 unsigned Addrspace) {
217 auto &Ctx = M.getContext();
219 bool Changed =
false;
222 Changed |= expandIntrinsicUsers<Intrinsic::vastart, VAStartInst>(
223 M, Builder, IntrinsicArgType);
224 Changed |= expandIntrinsicUsers<Intrinsic::vaend, VAEndInst>(
225 M, Builder, IntrinsicArgType);
226 Changed |= expandIntrinsicUsers<Intrinsic::vacopy, VACopyInst>(
227 M, Builder, IntrinsicArgType);
243 ArgTypes.
push_back(ABI->vaListParameterType(M));
251 uint64_t AsInt = AllocaTypeSize ? AllocaTypeSize->getFixedValue() : 0;
256 if (
F->isIntrinsic() || !
F->isVarArg() ||
257 F->hasFnAttribute(Attribute::Naked))
266 if (!
F->hasExactDefinition())
272 bool expansionApplicableToFunctionCall(
CallBase *CB) {
273 if (
CallInst *CI = dyn_cast<CallInst>(CB)) {
274 if (CI->isMustTailCall()) {
285 if (isa<InvokeInst>(CB)) {
294 class ExpandedCallFrame {
300 enum Tag { Store, Memcpy, Padding };
305 Source.push_back({V, Bytes, tag});
312 append<Memcpy>(
T, V, Bytes);
319 size_t size()
const {
return FieldTypes.
size(); }
320 bool empty()
const {
return FieldTypes.
empty(); }
323 const bool IsPacked =
true;
325 (
Twine(
Name) +
".vararg").str(), IsPacked);
333 for (
size_t I = 0;
I <
size();
I++) {
335 auto [V, bytes, tag] = Source[
I];
337 if (tag == Padding) {
356bool ExpandVariadics::runOnModule(
Module &M) {
357 bool Changed =
false;
358 if (Mode == ExpandVariadicsMode::Disable)
361 Triple TT(M.getTargetTriple());
362 ABI = VariadicABIInfo::create(TT);
366 if (!ABI->enableForTarget())
369 auto &Ctx = M.getContext();
386 unsigned Addrspace = 0;
387 Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace);
389 Addrspace =
DL.getAllocaAddrSpace();
391 Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace);
394 if (Mode != ExpandVariadicsMode::Lowering)
398 if (
F.isDeclaration())
406 if (
CallBase *CB = dyn_cast<CallBase>(&
I)) {
407 if (CB->isIndirectCall()) {
410 Changed |= expandCall(M, Builder, CB, FTy, 0);
422 bool Changed =
false;
424 if (!expansionApplicableToFunction(M, OriginalFunction))
427 [[maybe_unused]]
const bool OriginalFunctionIsDeclaration =
429 assert(rewriteABI() || !OriginalFunctionIsDeclaration);
433 replaceAllUsesWithNewDeclaration(M, OriginalFunction);
440 deriveFixedArityReplacement(M, Builder, OriginalFunction);
443 OriginalFunctionIsDeclaration);
447 [[maybe_unused]]
Function *VariadicWrapperDefine =
448 defineVariadicWrapper(M, Builder, VariadicWrapper, FixedArityReplacement);
449 assert(VariadicWrapperDefine == VariadicWrapper);
459 if (
CallBase *CB = dyn_cast<CallBase>(U)) {
460 Value *CalledOperand = CB->getCalledOperand();
461 if (VariadicWrapper == CalledOperand)
464 FixedArityReplacement);
472 Function *
const ExternallyAccessible =
473 rewriteABI() ? FixedArityReplacement : VariadicWrapper;
475 rewriteABI() ? VariadicWrapper : FixedArityReplacement;
481 ExternallyAccessible->
takeName(OriginalFunction);
503ExpandVariadics::replaceAllUsesWithNewDeclaration(
Module &M,
505 auto &Ctx = M.getContext();
510 NF->
setName(
F.getName() +
".varargs");
513 F.getParent()->getFunctionList().insert(
F.getIterator(), NF);
517 Attrs = Attrs.addParamAttributes(Ctx, FTy->getNumParams(), ParamAttrs);
533 assert(expansionApplicableToFunction(M, &
F));
535 auto &Ctx = M.getContext();
539 const bool FunctionIsDefinition = !
F.isDeclaration();
543 ArgTypes.
push_back(ABI->vaListParameterType(M));
545 FunctionType *NFTy = inlinableVariadicFunctionType(M, FTy);
551 F.getParent()->getFunctionList().insert(
F.getIterator(), NF);
552 NF->
setName(
F.getName() +
".valist");
558 Attrs = Attrs.addParamAttributes(Ctx, NFTy->getNumParams() - 1, ParamAttrs);
562 if (FunctionIsDefinition) {
568 NewArg->setName(Arg.getName());
571 NewArg->setName(
"varargs");
575 F.getAllMetadata(MDs);
576 for (
auto [KindID,
Node] : MDs)
593 Type *VaListTy = ABI->vaListType(Ctx);
602 sizeOfAlloca(Ctx,
DL, VaListInstance));
611 Type *ParameterType = ABI->vaListParameterType(M);
612 if (ABI->vaListPassedInSSARegister())
613 Args.push_back(Builder.
CreateLoad(ParameterType, VaListInstance));
622 sizeOfAlloca(Ctx,
DL, VaListInstance));
624 if (Result->getType()->isVoidTy())
629 return VariadicWrapper;
635 bool Changed =
false;
638 if (!expansionApplicableToFunctionCall(CB)) {
648 if (FuncType != VarargFunctionType) {
651 FuncType = VarargFunctionType;
656 Align MaxFieldAlign(1);
666 ExpandedCallFrame Frame;
670 for (
unsigned I = FuncType->getNumParams(), E = CB->
arg_size();
I < E; ++
I) {
681 DL.getTypeAllocSize(UnderlyingType).getFixedValue();
684 Type *FrameFieldType = UnderlyingType;
687 Value *SourceValue = ArgVal;
689 VariadicABIInfo::VAArgSlotInfo SlotInfo = ABI->slotInfo(
DL, UnderlyingType);
691 if (SlotInfo.Indirect) {
697 Builder.
CreateAlloca(UnderlyingType,
nullptr,
"IndirectAlloca");
701 Builder.
CreateMemCpy(CallerCopy, {}, ArgVal, {}, UnderlyingSize);
706 FrameFieldType =
DL.getAllocaPtrType(Ctx);
707 SourceValue = CallerCopy;
712 Align DataAlign = SlotInfo.DataAlign;
714 MaxFieldAlign = std::max(MaxFieldAlign, DataAlign);
717 if (
uint64_t Rem = CurrentOffset % DataAlignV) {
719 uint64_t Padding = DataAlignV - Rem;
720 Frame.padding(Ctx, Padding);
721 CurrentOffset += Padding;
724 if (SlotInfo.Indirect) {
725 Frame.store(Ctx, FrameFieldType, SourceValue);
728 Frame.memcpy(Ctx, FrameFieldType, SourceValue, UnderlyingSize);
730 Frame.store(Ctx, FrameFieldType, SourceValue);
733 CurrentOffset +=
DL.getTypeAllocSize(FrameFieldType).getFixedValue();
741 Frame.padding(Ctx, 1);
752 Align AllocaAlign = MaxFieldAlign;
754 StackAlign && *StackAlign > AllocaAlign)
755 AllocaAlign = *StackAlign;
765 new AllocaInst(VarargsTy,
DL.getAllocaAddrSpace(),
nullptr, AllocaAlign),
773 Frame.initializeStructAlloca(
DL, Builder, Alloced);
775 const unsigned NumArgs = FuncType->getNumParams();
782 if (!ABI->vaListPassedInSSARegister()) {
783 Type *VaListTy = ABI->vaListType(Ctx);
786 VaList = Builder.
CreateAlloca(VaListTy,
nullptr,
"va_argument");
791 Args.push_back(ABI->initializeVaList(M, Ctx, Builder, VaList, Alloced));
798 for (
unsigned ArgNo = 0; ArgNo < NumArgs; ArgNo++)
809 if (
CallInst *CI = dyn_cast<CallInst>(CB)) {
810 Value *Dst = NF ? NF : CI->getCalledOperand();
811 FunctionType *NFTy = inlinableVariadicFunctionType(M, VarargFunctionType);
813 NewCB =
CallInst::Create(NFTy, Dst, Args, OpBundles,
"", CI->getIterator());
821 CI->setTailCallKind(TCK);
838 NewCB->
copyMetadata(*CB, {LLVMContext::MD_prof, LLVMContext::MD_dbg});
845bool ExpandVariadics::expandVAIntrinsicCall(
IRBuilder<> &Builder,
858 if (ContainingFunction->
isVarArg()) {
864 bool PassedByValue = ABI->vaListPassedInSSARegister();
877 assert(ABI->vaCopyIsMemcpy());
885 {VaStartArg, PassedVaList});
894 assert(ABI->vaEndIsNop());
899bool ExpandVariadics::expandVAIntrinsicCall(
IRBuilder<> &Builder,
902 assert(ABI->vaCopyIsMemcpy());
906 Type *VaListTy = ABI->vaListType(Ctx);
916struct Amdgpu final :
public VariadicABIInfo {
918 bool enableForTarget()
override {
return true; }
920 bool vaListPassedInSSARegister()
override {
return true; }
923 return PointerType::getUnqual(Ctx);
926 Type *vaListParameterType(
Module &M)
override {
927 return PointerType::getUnqual(M.getContext());
938 return {
Align(4),
false};
942struct NVPTX final :
public VariadicABIInfo {
944 bool enableForTarget()
override {
return true; }
946 bool vaListPassedInSSARegister()
override {
return true; }
952 Type *vaListParameterType(
Module &M)
override {
964 Align A =
DL.getABITypeAlign(Parameter);
969struct Wasm final :
public VariadicABIInfo {
971 bool enableForTarget()
override {
973 return commandLineOverride();
976 bool vaListPassedInSSARegister()
override {
return true; }
979 return PointerType::getUnqual(Ctx);
982 Type *vaListParameterType(
Module &M)
override {
983 return PointerType::getUnqual(M.getContext());
994 Align A =
DL.getABITypeAlign(Parameter);
998 if (
auto *S = dyn_cast<StructType>(Parameter)) {
999 if (S->getNumElements() > 1) {
1000 return {
DL.getABITypeAlign(PointerType::getUnqual(Ctx)),
true};
1008std::unique_ptr<VariadicABIInfo> VariadicABIInfo::create(
const Triple &
T) {
1009 switch (
T.getArch()) {
1012 return std::make_unique<Amdgpu>();
1016 return std::make_unique<Wasm>();
1021 return std::make_unique<NVPTX>();
1031char ExpandVariadics::ID = 0;
1037 return new ExpandVariadics(M);
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
an instruction to allocate memory on the stack
Type * getAllocatedType() const
Return the type that is being allocated by the instruction.
std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
A container for analyses that lazily runs them and caches their results.
This class represents an incoming formal argument to a Function.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
AttributeSet getFnAttrs() const
The function attributes are returned.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
bool isEmpty() const
Return true if there are no attributes.
AttributeSet getRetAttrs() const
The attributes for the ret value are returned.
AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
void getOperandBundlesAsDefs(SmallVectorImpl< OperandBundleDef > &Defs) const
Return the list of operand bundles attached to this instruction as a vector of OperandBundleDefs.
Type * getParamByRefType(unsigned ArgNo) const
Extract the byref type for a call or parameter.
CallingConv::ID getCallingConv() const
bool paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Determine whether the argument or parameter has the given attribute.
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Type * getParamByValType(unsigned ArgNo) const
Extract the byval type for a call or parameter.
void setAttributes(AttributeList A)
Set the attributes for this call.
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
This is the shared class of boolean and integer constants.
void removeDeadConstantUsers() const
If there are any dead constant users dangling off of this constant, remove them.
A parsed version of the target data layout string in and methods for querying it.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
ExpandVariadicsPass(ExpandVariadicsMode Mode)
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
void splice(Function::iterator ToIt, Function *FromF)
Transfer all blocks from FromF to this function at ToIt.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
bool IsNewDbgInfoFormat
Is this function using intrinsics to record the position of debugging information,...
AttributeList getAttributes() const
Return the attribute list for this Function.
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
Argument * getArg(unsigned i) const
bool isVarArg() const
isVarArg - Return true if this function takes a variable number of arguments.
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
void setComdat(Comdat *C)
const Comdat * getComdat() const
void addMetadata(unsigned KindID, MDNode &MD)
Add a metadata attachment.
VisibilityTypes getVisibility() const
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
LinkageTypes getLinkage() const
void setLinkage(LinkageTypes LT)
@ DefaultVisibility
The GV is visible.
void setVisibility(VisibilityTypes V)
@ InternalLinkage
Rename collisions when linking (static functions).
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
CallInst * CreateLifetimeStart(Value *Ptr, ConstantInt *Size=nullptr)
Create a lifetime.start intrinsic.
CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, Instruction *FMFSource=nullptr, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
Value * CreateStructGEP(Type *Ty, Value *Ptr, unsigned Idx, const Twine &Name="")
ReturnInst * CreateRet(Value *V)
Create a 'ret <val>' instruction.
void SetCurrentDebugLocation(DebugLoc L)
Set location information used by debugging information.
void SetInsertPointPastAllocas(Function *F)
This specifies that created instructions should inserted at the beginning end of the specified functi...
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
InstTy * Insert(InstTy *I, const Twine &Name="") const
Insert and return the specified instruction.
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
LLVMContext & getContext() const
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
CallInst * CreateLifetimeEnd(Value *Ptr, ConstantInt *Size=nullptr)
Create a lifetime.end intrinsic.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
CallInst * CreateMemCpy(Value *Dst, MaybeAlign DstAlign, Value *Src, MaybeAlign SrcAlign, uint64_t Size, bool isVolatile=false, MDNode *TBAATag=nullptr, MDNode *TBAAStructTag=nullptr, MDNode *ScopeTag=nullptr, MDNode *NoAliasTag=nullptr)
Create and insert a memcpy between the specified pointers.
Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="")
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getStableDebugLoc() const
Fetch the debug location for this node, unless this is a debug intrinsic, in which case fetch the deb...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
const Function * getFunction() const
Return the function this instruction belongs to.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
This is an important class for using LLVM in a threaded context.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Class to represent struct types.
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Triple - Helper class for working with autoconf configuration names.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
static IntegerType * getInt8Ty(LLVMContext &C)
static IntegerType * getInt64Ty(LLVMContext &C)
This represents the llvm.va_copy intrinsic.
This represents the llvm.va_end intrinsic.
This represents the llvm.va_start intrinsic.
Value * getArgList() const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void setName(const Twine &Name)
Change the name of the value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVMContext & getContext() const
All values hold a context through their type.
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
const ParentTy * getParent() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Function * getDeclarationIfExists(Module *M, ID id, ArrayRef< Type * > Tys, FunctionType *FT=nullptr)
This version supports overloaded intrinsics.
FunctionType * getType(LLVMContext &Context, ID id, ArrayRef< Type * > Tys={})
Return the function type for an intrinsic.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
ModulePass * createExpandVariadicsPass(ExpandVariadicsMode)
@ Wasm
WebAssembly Exception Handling.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
constexpr T MinAlign(U A, V B)
A and B are either alignments or offsets.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This struct is a compact representation of a valid (non-zero power of two) alignment.
uint64_t value() const
This is a hole in the type system and should not be abused.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.