1*0fca6ea1SDimitry Andric //===-- ExpandVariadicsPass.cpp --------------------------------*- C++ -*-=// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This is an optimization pass for variadic functions. If called from codegen, 10*0fca6ea1SDimitry Andric // it can serve as the implementation of variadic functions for a given target. 11*0fca6ea1SDimitry Andric // 12*0fca6ea1SDimitry Andric // The strategy is to turn the ... part of a variadic function into a va_list 13*0fca6ea1SDimitry Andric // and fix up the call sites. The majority of the pass is target independent. 14*0fca6ea1SDimitry Andric // The exceptions are the va_list type itself and the rules for where to store 15*0fca6ea1SDimitry Andric // variables in memory such that va_arg can iterate over them given a va_list. 16*0fca6ea1SDimitry Andric // 17*0fca6ea1SDimitry Andric // The majority of the plumbing is splitting the variadic function into a 18*0fca6ea1SDimitry Andric // single basic block that packs the variadic arguments into a va_list and 19*0fca6ea1SDimitry Andric // a second function that does the work of the original. That packing is 20*0fca6ea1SDimitry Andric // exactly what is done by va_start. Further, the transform from ... to va_list 21*0fca6ea1SDimitry Andric // replaced va_start with an operation to copy a va_list from the new argument, 22*0fca6ea1SDimitry Andric // which is exactly a va_copy. This is useful for reducing target-dependence. 23*0fca6ea1SDimitry Andric // 24*0fca6ea1SDimitry Andric // A va_list instance is a forward iterator, where the primary operation va_arg 25*0fca6ea1SDimitry Andric // is dereference-then-increment. This interface forces significant convergent 26*0fca6ea1SDimitry Andric // evolution between target specific implementations. The variation in runtime 27*0fca6ea1SDimitry Andric // data layout is limited to that representable by the iterator, parameterised 28*0fca6ea1SDimitry Andric // by the type passed to the va_arg instruction. 29*0fca6ea1SDimitry Andric // 30*0fca6ea1SDimitry Andric // Therefore the majority of the target specific subtlety is packing arguments 31*0fca6ea1SDimitry Andric // into a stack allocated buffer such that a va_list can be initialised with it 32*0fca6ea1SDimitry Andric // and the va_arg expansion for the target will find the arguments at runtime. 33*0fca6ea1SDimitry Andric // 34*0fca6ea1SDimitry Andric // The aggregate effect is to unblock other transforms, most critically the 35*0fca6ea1SDimitry Andric // general purpose inliner. Known calls to variadic functions become zero cost. 36*0fca6ea1SDimitry Andric // 37*0fca6ea1SDimitry Andric // Consistency with clang is primarily tested by emitting va_arg using clang 38*0fca6ea1SDimitry Andric // then expanding the variadic functions using this pass, followed by trying 39*0fca6ea1SDimitry Andric // to constant fold the functions to no-ops. 40*0fca6ea1SDimitry Andric // 41*0fca6ea1SDimitry Andric // Target specific behaviour is tested in IR - mainly checking that values are 42*0fca6ea1SDimitry Andric // put into positions in call frames that make sense for that particular target. 43*0fca6ea1SDimitry Andric // 44*0fca6ea1SDimitry Andric // There is one "clever" invariant in use. va_start intrinsics that are not 45*0fca6ea1SDimitry Andric // within a varidic functions are an error in the IR verifier. When this 46*0fca6ea1SDimitry Andric // transform moves blocks from a variadic function into a fixed arity one, it 47*0fca6ea1SDimitry Andric // moves va_start intrinsics along with everything else. That means that the 48*0fca6ea1SDimitry Andric // va_start intrinsics that need to be rewritten to use the trailing argument 49*0fca6ea1SDimitry Andric // are exactly those that are in non-variadic functions so no further state 50*0fca6ea1SDimitry Andric // is needed to distinguish those that need to be rewritten. 51*0fca6ea1SDimitry Andric // 52*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 53*0fca6ea1SDimitry Andric 54*0fca6ea1SDimitry Andric #include "llvm/Transforms/IPO/ExpandVariadics.h" 55*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 56*0fca6ea1SDimitry Andric #include "llvm/IR/Constants.h" 57*0fca6ea1SDimitry Andric #include "llvm/IR/IRBuilder.h" 58*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 59*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 60*0fca6ea1SDimitry Andric #include "llvm/IR/PassManager.h" 61*0fca6ea1SDimitry Andric #include "llvm/InitializePasses.h" 62*0fca6ea1SDimitry Andric #include "llvm/Pass.h" 63*0fca6ea1SDimitry Andric #include "llvm/Support/CommandLine.h" 64*0fca6ea1SDimitry Andric #include "llvm/TargetParser/Triple.h" 65*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h" 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric #define DEBUG_TYPE "expand-variadics" 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric using namespace llvm; 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric namespace { 72*0fca6ea1SDimitry Andric 73*0fca6ea1SDimitry Andric cl::opt<ExpandVariadicsMode> ExpandVariadicsModeOption( 74*0fca6ea1SDimitry Andric DEBUG_TYPE "-override", cl::desc("Override the behaviour of " DEBUG_TYPE), 75*0fca6ea1SDimitry Andric cl::init(ExpandVariadicsMode::Unspecified), 76*0fca6ea1SDimitry Andric cl::values(clEnumValN(ExpandVariadicsMode::Unspecified, "unspecified", 77*0fca6ea1SDimitry Andric "Use the implementation defaults"), 78*0fca6ea1SDimitry Andric clEnumValN(ExpandVariadicsMode::Disable, "disable", 79*0fca6ea1SDimitry Andric "Disable the pass entirely"), 80*0fca6ea1SDimitry Andric clEnumValN(ExpandVariadicsMode::Optimize, "optimize", 81*0fca6ea1SDimitry Andric "Optimise without changing ABI"), 82*0fca6ea1SDimitry Andric clEnumValN(ExpandVariadicsMode::Lowering, "lowering", 83*0fca6ea1SDimitry Andric "Change variadic calling convention"))); 84*0fca6ea1SDimitry Andric 85*0fca6ea1SDimitry Andric bool commandLineOverride() { 86*0fca6ea1SDimitry Andric return ExpandVariadicsModeOption != ExpandVariadicsMode::Unspecified; 87*0fca6ea1SDimitry Andric } 88*0fca6ea1SDimitry Andric 89*0fca6ea1SDimitry Andric // Instances of this class encapsulate the target-dependant behaviour as a 90*0fca6ea1SDimitry Andric // function of triple. Implementing a new ABI is adding a case to the switch 91*0fca6ea1SDimitry Andric // in create(llvm::Triple) at the end of this file. 92*0fca6ea1SDimitry Andric // This class may end up instantiated in TargetMachine instances, keeping it 93*0fca6ea1SDimitry Andric // here for now until enough targets are implemented for the API to evolve. 94*0fca6ea1SDimitry Andric class VariadicABIInfo { 95*0fca6ea1SDimitry Andric protected: 96*0fca6ea1SDimitry Andric VariadicABIInfo() = default; 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric public: 99*0fca6ea1SDimitry Andric static std::unique_ptr<VariadicABIInfo> create(const Triple &T); 100*0fca6ea1SDimitry Andric 101*0fca6ea1SDimitry Andric // Allow overriding whether the pass runs on a per-target basis 102*0fca6ea1SDimitry Andric virtual bool enableForTarget() = 0; 103*0fca6ea1SDimitry Andric 104*0fca6ea1SDimitry Andric // Whether a valist instance is passed by value or by address 105*0fca6ea1SDimitry Andric // I.e. does it need to be alloca'ed and stored into, or can 106*0fca6ea1SDimitry Andric // it be passed directly in a SSA register 107*0fca6ea1SDimitry Andric virtual bool vaListPassedInSSARegister() = 0; 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric // The type of a va_list iterator object 110*0fca6ea1SDimitry Andric virtual Type *vaListType(LLVMContext &Ctx) = 0; 111*0fca6ea1SDimitry Andric 112*0fca6ea1SDimitry Andric // The type of a va_list as a function argument as lowered by C 113*0fca6ea1SDimitry Andric virtual Type *vaListParameterType(Module &M) = 0; 114*0fca6ea1SDimitry Andric 115*0fca6ea1SDimitry Andric // Initialize an allocated va_list object to point to an already 116*0fca6ea1SDimitry Andric // initialized contiguous memory region. 117*0fca6ea1SDimitry Andric // Return the value to pass as the va_list argument 118*0fca6ea1SDimitry Andric virtual Value *initializeVaList(Module &M, LLVMContext &Ctx, 119*0fca6ea1SDimitry Andric IRBuilder<> &Builder, AllocaInst *VaList, 120*0fca6ea1SDimitry Andric Value *Buffer) = 0; 121*0fca6ea1SDimitry Andric 122*0fca6ea1SDimitry Andric struct VAArgSlotInfo { 123*0fca6ea1SDimitry Andric Align DataAlign; // With respect to the call frame 124*0fca6ea1SDimitry Andric bool Indirect; // Passed via a pointer 125*0fca6ea1SDimitry Andric }; 126*0fca6ea1SDimitry Andric virtual VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) = 0; 127*0fca6ea1SDimitry Andric 128*0fca6ea1SDimitry Andric // Targets implemented so far all have the same trivial lowering for these 129*0fca6ea1SDimitry Andric bool vaEndIsNop() { return true; } 130*0fca6ea1SDimitry Andric bool vaCopyIsMemcpy() { return true; } 131*0fca6ea1SDimitry Andric 132*0fca6ea1SDimitry Andric virtual ~VariadicABIInfo() = default; 133*0fca6ea1SDimitry Andric }; 134*0fca6ea1SDimitry Andric 135*0fca6ea1SDimitry Andric // Module implements getFunction() which returns nullptr on missing declaration 136*0fca6ea1SDimitry Andric // and getOrInsertFunction which creates one when absent. Intrinsics.h only 137*0fca6ea1SDimitry Andric // implements getDeclaration which creates one when missing. Checking whether 138*0fca6ea1SDimitry Andric // an intrinsic exists thus inserts it in the module and it then needs to be 139*0fca6ea1SDimitry Andric // deleted again to clean up. 140*0fca6ea1SDimitry Andric // The right name for the two functions on intrinsics would match Module::, 141*0fca6ea1SDimitry Andric // but doing that in a single change would introduce nullptr dereferences 142*0fca6ea1SDimitry Andric // where currently there are none. The minimal collateral damage approach 143*0fca6ea1SDimitry Andric // would split the change over a release to help downstream branches. As it 144*0fca6ea1SDimitry Andric // is unclear what approach will be preferred, implementing the trivial 145*0fca6ea1SDimitry Andric // function here in the meantime to decouple from that discussion. 146*0fca6ea1SDimitry Andric Function *getPreexistingDeclaration(Module *M, Intrinsic::ID Id, 147*0fca6ea1SDimitry Andric ArrayRef<Type *> Tys = {}) { 148*0fca6ea1SDimitry Andric auto *FT = Intrinsic::getType(M->getContext(), Id, Tys); 149*0fca6ea1SDimitry Andric return M->getFunction(Tys.empty() ? Intrinsic::getName(Id) 150*0fca6ea1SDimitry Andric : Intrinsic::getName(Id, Tys, M, FT)); 151*0fca6ea1SDimitry Andric } 152*0fca6ea1SDimitry Andric 153*0fca6ea1SDimitry Andric class ExpandVariadics : public ModulePass { 154*0fca6ea1SDimitry Andric 155*0fca6ea1SDimitry Andric // The pass construction sets the default to optimize when called from middle 156*0fca6ea1SDimitry Andric // end and lowering when called from the backend. The command line variable 157*0fca6ea1SDimitry Andric // overrides that. This is useful for testing and debugging. It also allows 158*0fca6ea1SDimitry Andric // building an applications with variadic functions wholly removed if one 159*0fca6ea1SDimitry Andric // has sufficient control over the dependencies, e.g. a statically linked 160*0fca6ea1SDimitry Andric // clang that has no variadic function calls remaining in the binary. 161*0fca6ea1SDimitry Andric 162*0fca6ea1SDimitry Andric public: 163*0fca6ea1SDimitry Andric static char ID; 164*0fca6ea1SDimitry Andric const ExpandVariadicsMode Mode; 165*0fca6ea1SDimitry Andric std::unique_ptr<VariadicABIInfo> ABI; 166*0fca6ea1SDimitry Andric 167*0fca6ea1SDimitry Andric ExpandVariadics(ExpandVariadicsMode Mode) 168*0fca6ea1SDimitry Andric : ModulePass(ID), 169*0fca6ea1SDimitry Andric Mode(commandLineOverride() ? ExpandVariadicsModeOption : Mode) {} 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric StringRef getPassName() const override { return "Expand variadic functions"; } 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric bool rewriteABI() { return Mode == ExpandVariadicsMode::Lowering; } 174*0fca6ea1SDimitry Andric 175*0fca6ea1SDimitry Andric bool runOnModule(Module &M) override; 176*0fca6ea1SDimitry Andric 177*0fca6ea1SDimitry Andric bool runOnFunction(Module &M, IRBuilder<> &Builder, Function *F); 178*0fca6ea1SDimitry Andric 179*0fca6ea1SDimitry Andric Function *replaceAllUsesWithNewDeclaration(Module &M, 180*0fca6ea1SDimitry Andric Function *OriginalFunction); 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric Function *deriveFixedArityReplacement(Module &M, IRBuilder<> &Builder, 183*0fca6ea1SDimitry Andric Function *OriginalFunction); 184*0fca6ea1SDimitry Andric 185*0fca6ea1SDimitry Andric Function *defineVariadicWrapper(Module &M, IRBuilder<> &Builder, 186*0fca6ea1SDimitry Andric Function *VariadicWrapper, 187*0fca6ea1SDimitry Andric Function *FixedArityReplacement); 188*0fca6ea1SDimitry Andric 189*0fca6ea1SDimitry Andric bool expandCall(Module &M, IRBuilder<> &Builder, CallBase *CB, FunctionType *, 190*0fca6ea1SDimitry Andric Function *NF); 191*0fca6ea1SDimitry Andric 192*0fca6ea1SDimitry Andric // The intrinsic functions va_copy and va_end are removed unconditionally. 193*0fca6ea1SDimitry Andric // They correspond to a memcpy and a no-op on all implemented targets. 194*0fca6ea1SDimitry Andric // The va_start intrinsic is removed from basic blocks that were not created 195*0fca6ea1SDimitry Andric // by this pass, some may remain if needed to maintain the external ABI. 196*0fca6ea1SDimitry Andric 197*0fca6ea1SDimitry Andric template <Intrinsic::ID ID, typename InstructionType> 198*0fca6ea1SDimitry Andric bool expandIntrinsicUsers(Module &M, IRBuilder<> &Builder, 199*0fca6ea1SDimitry Andric PointerType *IntrinsicArgType) { 200*0fca6ea1SDimitry Andric bool Changed = false; 201*0fca6ea1SDimitry Andric const DataLayout &DL = M.getDataLayout(); 202*0fca6ea1SDimitry Andric if (Function *Intrinsic = 203*0fca6ea1SDimitry Andric getPreexistingDeclaration(&M, ID, {IntrinsicArgType})) { 204*0fca6ea1SDimitry Andric for (User *U : make_early_inc_range(Intrinsic->users())) 205*0fca6ea1SDimitry Andric if (auto *I = dyn_cast<InstructionType>(U)) 206*0fca6ea1SDimitry Andric Changed |= expandVAIntrinsicCall(Builder, DL, I); 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric if (Intrinsic->use_empty()) 209*0fca6ea1SDimitry Andric Intrinsic->eraseFromParent(); 210*0fca6ea1SDimitry Andric } 211*0fca6ea1SDimitry Andric return Changed; 212*0fca6ea1SDimitry Andric } 213*0fca6ea1SDimitry Andric 214*0fca6ea1SDimitry Andric bool expandVAIntrinsicUsersWithAddrspace(Module &M, IRBuilder<> &Builder, 215*0fca6ea1SDimitry Andric unsigned Addrspace) { 216*0fca6ea1SDimitry Andric auto &Ctx = M.getContext(); 217*0fca6ea1SDimitry Andric PointerType *IntrinsicArgType = PointerType::get(Ctx, Addrspace); 218*0fca6ea1SDimitry Andric bool Changed = false; 219*0fca6ea1SDimitry Andric 220*0fca6ea1SDimitry Andric // expand vastart before vacopy as vastart may introduce a vacopy 221*0fca6ea1SDimitry Andric Changed |= expandIntrinsicUsers<Intrinsic::vastart, VAStartInst>( 222*0fca6ea1SDimitry Andric M, Builder, IntrinsicArgType); 223*0fca6ea1SDimitry Andric Changed |= expandIntrinsicUsers<Intrinsic::vaend, VAEndInst>( 224*0fca6ea1SDimitry Andric M, Builder, IntrinsicArgType); 225*0fca6ea1SDimitry Andric Changed |= expandIntrinsicUsers<Intrinsic::vacopy, VACopyInst>( 226*0fca6ea1SDimitry Andric M, Builder, IntrinsicArgType); 227*0fca6ea1SDimitry Andric return Changed; 228*0fca6ea1SDimitry Andric } 229*0fca6ea1SDimitry Andric 230*0fca6ea1SDimitry Andric bool expandVAIntrinsicCall(IRBuilder<> &Builder, const DataLayout &DL, 231*0fca6ea1SDimitry Andric VAStartInst *Inst); 232*0fca6ea1SDimitry Andric 233*0fca6ea1SDimitry Andric bool expandVAIntrinsicCall(IRBuilder<> &, const DataLayout &, 234*0fca6ea1SDimitry Andric VAEndInst *Inst); 235*0fca6ea1SDimitry Andric 236*0fca6ea1SDimitry Andric bool expandVAIntrinsicCall(IRBuilder<> &Builder, const DataLayout &DL, 237*0fca6ea1SDimitry Andric VACopyInst *Inst); 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric FunctionType *inlinableVariadicFunctionType(Module &M, FunctionType *FTy) { 240*0fca6ea1SDimitry Andric // The type of "FTy" with the ... removed and a va_list appended 241*0fca6ea1SDimitry Andric SmallVector<Type *> ArgTypes(FTy->param_begin(), FTy->param_end()); 242*0fca6ea1SDimitry Andric ArgTypes.push_back(ABI->vaListParameterType(M)); 243*0fca6ea1SDimitry Andric return FunctionType::get(FTy->getReturnType(), ArgTypes, 244*0fca6ea1SDimitry Andric /*IsVarArgs=*/false); 245*0fca6ea1SDimitry Andric } 246*0fca6ea1SDimitry Andric 247*0fca6ea1SDimitry Andric static ConstantInt *sizeOfAlloca(LLVMContext &Ctx, const DataLayout &DL, 248*0fca6ea1SDimitry Andric AllocaInst *Alloced) { 249*0fca6ea1SDimitry Andric std::optional<TypeSize> AllocaTypeSize = Alloced->getAllocationSize(DL); 250*0fca6ea1SDimitry Andric uint64_t AsInt = AllocaTypeSize ? AllocaTypeSize->getFixedValue() : 0; 251*0fca6ea1SDimitry Andric return ConstantInt::get(Type::getInt64Ty(Ctx), AsInt); 252*0fca6ea1SDimitry Andric } 253*0fca6ea1SDimitry Andric 254*0fca6ea1SDimitry Andric bool expansionApplicableToFunction(Module &M, Function *F) { 255*0fca6ea1SDimitry Andric if (F->isIntrinsic() || !F->isVarArg() || 256*0fca6ea1SDimitry Andric F->hasFnAttribute(Attribute::Naked)) 257*0fca6ea1SDimitry Andric return false; 258*0fca6ea1SDimitry Andric 259*0fca6ea1SDimitry Andric if (F->getCallingConv() != CallingConv::C) 260*0fca6ea1SDimitry Andric return false; 261*0fca6ea1SDimitry Andric 262*0fca6ea1SDimitry Andric if (rewriteABI()) 263*0fca6ea1SDimitry Andric return true; 264*0fca6ea1SDimitry Andric 265*0fca6ea1SDimitry Andric if (!F->hasExactDefinition()) 266*0fca6ea1SDimitry Andric return false; 267*0fca6ea1SDimitry Andric 268*0fca6ea1SDimitry Andric return true; 269*0fca6ea1SDimitry Andric } 270*0fca6ea1SDimitry Andric 271*0fca6ea1SDimitry Andric bool expansionApplicableToFunctionCall(CallBase *CB) { 272*0fca6ea1SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(CB)) { 273*0fca6ea1SDimitry Andric if (CI->isMustTailCall()) { 274*0fca6ea1SDimitry Andric // Cannot expand musttail calls 275*0fca6ea1SDimitry Andric return false; 276*0fca6ea1SDimitry Andric } 277*0fca6ea1SDimitry Andric 278*0fca6ea1SDimitry Andric if (CI->getCallingConv() != CallingConv::C) 279*0fca6ea1SDimitry Andric return false; 280*0fca6ea1SDimitry Andric 281*0fca6ea1SDimitry Andric return true; 282*0fca6ea1SDimitry Andric } 283*0fca6ea1SDimitry Andric 284*0fca6ea1SDimitry Andric if (isa<InvokeInst>(CB)) { 285*0fca6ea1SDimitry Andric // Invoke not implemented in initial implementation of pass 286*0fca6ea1SDimitry Andric return false; 287*0fca6ea1SDimitry Andric } 288*0fca6ea1SDimitry Andric 289*0fca6ea1SDimitry Andric // Other unimplemented derivative of CallBase 290*0fca6ea1SDimitry Andric return false; 291*0fca6ea1SDimitry Andric } 292*0fca6ea1SDimitry Andric 293*0fca6ea1SDimitry Andric class ExpandedCallFrame { 294*0fca6ea1SDimitry Andric // Helper for constructing an alloca instance containing the arguments bound 295*0fca6ea1SDimitry Andric // to the variadic ... parameter, rearranged to allow indexing through a 296*0fca6ea1SDimitry Andric // va_list iterator 297*0fca6ea1SDimitry Andric enum { N = 4 }; 298*0fca6ea1SDimitry Andric SmallVector<Type *, N> FieldTypes; 299*0fca6ea1SDimitry Andric enum Tag { Store, Memcpy, Padding }; 300*0fca6ea1SDimitry Andric SmallVector<std::tuple<Value *, uint64_t, Tag>, N> Source; 301*0fca6ea1SDimitry Andric 302*0fca6ea1SDimitry Andric template <Tag tag> void append(Type *FieldType, Value *V, uint64_t Bytes) { 303*0fca6ea1SDimitry Andric FieldTypes.push_back(FieldType); 304*0fca6ea1SDimitry Andric Source.push_back({V, Bytes, tag}); 305*0fca6ea1SDimitry Andric } 306*0fca6ea1SDimitry Andric 307*0fca6ea1SDimitry Andric public: 308*0fca6ea1SDimitry Andric void store(LLVMContext &Ctx, Type *T, Value *V) { append<Store>(T, V, 0); } 309*0fca6ea1SDimitry Andric 310*0fca6ea1SDimitry Andric void memcpy(LLVMContext &Ctx, Type *T, Value *V, uint64_t Bytes) { 311*0fca6ea1SDimitry Andric append<Memcpy>(T, V, Bytes); 312*0fca6ea1SDimitry Andric } 313*0fca6ea1SDimitry Andric 314*0fca6ea1SDimitry Andric void padding(LLVMContext &Ctx, uint64_t By) { 315*0fca6ea1SDimitry Andric append<Padding>(ArrayType::get(Type::getInt8Ty(Ctx), By), nullptr, 0); 316*0fca6ea1SDimitry Andric } 317*0fca6ea1SDimitry Andric 318*0fca6ea1SDimitry Andric size_t size() const { return FieldTypes.size(); } 319*0fca6ea1SDimitry Andric bool empty() const { return FieldTypes.empty(); } 320*0fca6ea1SDimitry Andric 321*0fca6ea1SDimitry Andric StructType *asStruct(LLVMContext &Ctx, StringRef Name) { 322*0fca6ea1SDimitry Andric const bool IsPacked = true; 323*0fca6ea1SDimitry Andric return StructType::create(Ctx, FieldTypes, 324*0fca6ea1SDimitry Andric (Twine(Name) + ".vararg").str(), IsPacked); 325*0fca6ea1SDimitry Andric } 326*0fca6ea1SDimitry Andric 327*0fca6ea1SDimitry Andric void initializeStructAlloca(const DataLayout &DL, IRBuilder<> &Builder, 328*0fca6ea1SDimitry Andric AllocaInst *Alloced) { 329*0fca6ea1SDimitry Andric 330*0fca6ea1SDimitry Andric StructType *VarargsTy = cast<StructType>(Alloced->getAllocatedType()); 331*0fca6ea1SDimitry Andric 332*0fca6ea1SDimitry Andric for (size_t I = 0; I < size(); I++) { 333*0fca6ea1SDimitry Andric 334*0fca6ea1SDimitry Andric auto [V, bytes, tag] = Source[I]; 335*0fca6ea1SDimitry Andric 336*0fca6ea1SDimitry Andric if (tag == Padding) { 337*0fca6ea1SDimitry Andric assert(V == nullptr); 338*0fca6ea1SDimitry Andric continue; 339*0fca6ea1SDimitry Andric } 340*0fca6ea1SDimitry Andric 341*0fca6ea1SDimitry Andric auto Dst = Builder.CreateStructGEP(VarargsTy, Alloced, I); 342*0fca6ea1SDimitry Andric 343*0fca6ea1SDimitry Andric assert(V != nullptr); 344*0fca6ea1SDimitry Andric 345*0fca6ea1SDimitry Andric if (tag == Store) 346*0fca6ea1SDimitry Andric Builder.CreateStore(V, Dst); 347*0fca6ea1SDimitry Andric 348*0fca6ea1SDimitry Andric if (tag == Memcpy) 349*0fca6ea1SDimitry Andric Builder.CreateMemCpy(Dst, {}, V, {}, bytes); 350*0fca6ea1SDimitry Andric } 351*0fca6ea1SDimitry Andric } 352*0fca6ea1SDimitry Andric }; 353*0fca6ea1SDimitry Andric }; 354*0fca6ea1SDimitry Andric 355*0fca6ea1SDimitry Andric bool ExpandVariadics::runOnModule(Module &M) { 356*0fca6ea1SDimitry Andric bool Changed = false; 357*0fca6ea1SDimitry Andric if (Mode == ExpandVariadicsMode::Disable) 358*0fca6ea1SDimitry Andric return Changed; 359*0fca6ea1SDimitry Andric 360*0fca6ea1SDimitry Andric Triple TT(M.getTargetTriple()); 361*0fca6ea1SDimitry Andric ABI = VariadicABIInfo::create(TT); 362*0fca6ea1SDimitry Andric if (!ABI) 363*0fca6ea1SDimitry Andric return Changed; 364*0fca6ea1SDimitry Andric 365*0fca6ea1SDimitry Andric if (!ABI->enableForTarget()) 366*0fca6ea1SDimitry Andric return Changed; 367*0fca6ea1SDimitry Andric 368*0fca6ea1SDimitry Andric auto &Ctx = M.getContext(); 369*0fca6ea1SDimitry Andric const DataLayout &DL = M.getDataLayout(); 370*0fca6ea1SDimitry Andric IRBuilder<> Builder(Ctx); 371*0fca6ea1SDimitry Andric 372*0fca6ea1SDimitry Andric // Lowering needs to run on all functions exactly once. 373*0fca6ea1SDimitry Andric // Optimize could run on functions containing va_start exactly once. 374*0fca6ea1SDimitry Andric for (Function &F : make_early_inc_range(M)) 375*0fca6ea1SDimitry Andric Changed |= runOnFunction(M, Builder, &F); 376*0fca6ea1SDimitry Andric 377*0fca6ea1SDimitry Andric // After runOnFunction, all known calls to known variadic functions have been 378*0fca6ea1SDimitry Andric // replaced. va_start intrinsics are presently (and invalidly!) only present 379*0fca6ea1SDimitry Andric // in functions that used to be variadic and have now been replaced to take a 380*0fca6ea1SDimitry Andric // va_list instead. If lowering as opposed to optimising, calls to unknown 381*0fca6ea1SDimitry Andric // variadic functions have also been replaced. 382*0fca6ea1SDimitry Andric 383*0fca6ea1SDimitry Andric { 384*0fca6ea1SDimitry Andric // 0 and AllocaAddrSpace are sufficient for the targets implemented so far 385*0fca6ea1SDimitry Andric unsigned Addrspace = 0; 386*0fca6ea1SDimitry Andric Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace); 387*0fca6ea1SDimitry Andric 388*0fca6ea1SDimitry Andric Addrspace = DL.getAllocaAddrSpace(); 389*0fca6ea1SDimitry Andric if (Addrspace != 0) 390*0fca6ea1SDimitry Andric Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace); 391*0fca6ea1SDimitry Andric } 392*0fca6ea1SDimitry Andric 393*0fca6ea1SDimitry Andric if (Mode != ExpandVariadicsMode::Lowering) 394*0fca6ea1SDimitry Andric return Changed; 395*0fca6ea1SDimitry Andric 396*0fca6ea1SDimitry Andric for (Function &F : make_early_inc_range(M)) { 397*0fca6ea1SDimitry Andric if (F.isDeclaration()) 398*0fca6ea1SDimitry Andric continue; 399*0fca6ea1SDimitry Andric 400*0fca6ea1SDimitry Andric // Now need to track down indirect calls. Can't find those 401*0fca6ea1SDimitry Andric // by walking uses of variadic functions, need to crawl the instruction 402*0fca6ea1SDimitry Andric // stream. Fortunately this is only necessary for the ABI rewrite case. 403*0fca6ea1SDimitry Andric for (BasicBlock &BB : F) { 404*0fca6ea1SDimitry Andric for (Instruction &I : make_early_inc_range(BB)) { 405*0fca6ea1SDimitry Andric if (CallBase *CB = dyn_cast<CallBase>(&I)) { 406*0fca6ea1SDimitry Andric if (CB->isIndirectCall()) { 407*0fca6ea1SDimitry Andric FunctionType *FTy = CB->getFunctionType(); 408*0fca6ea1SDimitry Andric if (FTy->isVarArg()) 409*0fca6ea1SDimitry Andric Changed |= expandCall(M, Builder, CB, FTy, 0); 410*0fca6ea1SDimitry Andric } 411*0fca6ea1SDimitry Andric } 412*0fca6ea1SDimitry Andric } 413*0fca6ea1SDimitry Andric } 414*0fca6ea1SDimitry Andric } 415*0fca6ea1SDimitry Andric 416*0fca6ea1SDimitry Andric return Changed; 417*0fca6ea1SDimitry Andric } 418*0fca6ea1SDimitry Andric 419*0fca6ea1SDimitry Andric bool ExpandVariadics::runOnFunction(Module &M, IRBuilder<> &Builder, 420*0fca6ea1SDimitry Andric Function *OriginalFunction) { 421*0fca6ea1SDimitry Andric bool Changed = false; 422*0fca6ea1SDimitry Andric 423*0fca6ea1SDimitry Andric if (!expansionApplicableToFunction(M, OriginalFunction)) 424*0fca6ea1SDimitry Andric return Changed; 425*0fca6ea1SDimitry Andric 426*0fca6ea1SDimitry Andric [[maybe_unused]] const bool OriginalFunctionIsDeclaration = 427*0fca6ea1SDimitry Andric OriginalFunction->isDeclaration(); 428*0fca6ea1SDimitry Andric assert(rewriteABI() || !OriginalFunctionIsDeclaration); 429*0fca6ea1SDimitry Andric 430*0fca6ea1SDimitry Andric // Declare a new function and redirect every use to that new function 431*0fca6ea1SDimitry Andric Function *VariadicWrapper = 432*0fca6ea1SDimitry Andric replaceAllUsesWithNewDeclaration(M, OriginalFunction); 433*0fca6ea1SDimitry Andric assert(VariadicWrapper->isDeclaration()); 434*0fca6ea1SDimitry Andric assert(OriginalFunction->use_empty()); 435*0fca6ea1SDimitry Andric 436*0fca6ea1SDimitry Andric // Create a new function taking va_list containing the implementation of the 437*0fca6ea1SDimitry Andric // original 438*0fca6ea1SDimitry Andric Function *FixedArityReplacement = 439*0fca6ea1SDimitry Andric deriveFixedArityReplacement(M, Builder, OriginalFunction); 440*0fca6ea1SDimitry Andric assert(OriginalFunction->isDeclaration()); 441*0fca6ea1SDimitry Andric assert(FixedArityReplacement->isDeclaration() == 442*0fca6ea1SDimitry Andric OriginalFunctionIsDeclaration); 443*0fca6ea1SDimitry Andric assert(VariadicWrapper->isDeclaration()); 444*0fca6ea1SDimitry Andric 445*0fca6ea1SDimitry Andric // Create a single block forwarding wrapper that turns a ... into a va_list 446*0fca6ea1SDimitry Andric [[maybe_unused]] Function *VariadicWrapperDefine = 447*0fca6ea1SDimitry Andric defineVariadicWrapper(M, Builder, VariadicWrapper, FixedArityReplacement); 448*0fca6ea1SDimitry Andric assert(VariadicWrapperDefine == VariadicWrapper); 449*0fca6ea1SDimitry Andric assert(!VariadicWrapper->isDeclaration()); 450*0fca6ea1SDimitry Andric 451*0fca6ea1SDimitry Andric // We now have: 452*0fca6ea1SDimitry Andric // 1. the original function, now as a declaration with no uses 453*0fca6ea1SDimitry Andric // 2. a variadic function that unconditionally calls a fixed arity replacement 454*0fca6ea1SDimitry Andric // 3. a fixed arity function equivalent to the original function 455*0fca6ea1SDimitry Andric 456*0fca6ea1SDimitry Andric // Replace known calls to the variadic with calls to the va_list equivalent 457*0fca6ea1SDimitry Andric for (User *U : make_early_inc_range(VariadicWrapper->users())) { 458*0fca6ea1SDimitry Andric if (CallBase *CB = dyn_cast<CallBase>(U)) { 459*0fca6ea1SDimitry Andric Value *CalledOperand = CB->getCalledOperand(); 460*0fca6ea1SDimitry Andric if (VariadicWrapper == CalledOperand) 461*0fca6ea1SDimitry Andric Changed |= 462*0fca6ea1SDimitry Andric expandCall(M, Builder, CB, VariadicWrapper->getFunctionType(), 463*0fca6ea1SDimitry Andric FixedArityReplacement); 464*0fca6ea1SDimitry Andric } 465*0fca6ea1SDimitry Andric } 466*0fca6ea1SDimitry Andric 467*0fca6ea1SDimitry Andric // The original function will be erased. 468*0fca6ea1SDimitry Andric // One of the two new functions will become a replacement for the original. 469*0fca6ea1SDimitry Andric // When preserving the ABI, the other is an internal implementation detail. 470*0fca6ea1SDimitry Andric // When rewriting the ABI, RAUW then the variadic one. 471*0fca6ea1SDimitry Andric Function *const ExternallyAccessible = 472*0fca6ea1SDimitry Andric rewriteABI() ? FixedArityReplacement : VariadicWrapper; 473*0fca6ea1SDimitry Andric Function *const InternalOnly = 474*0fca6ea1SDimitry Andric rewriteABI() ? VariadicWrapper : FixedArityReplacement; 475*0fca6ea1SDimitry Andric 476*0fca6ea1SDimitry Andric // The external function is the replacement for the original 477*0fca6ea1SDimitry Andric ExternallyAccessible->setLinkage(OriginalFunction->getLinkage()); 478*0fca6ea1SDimitry Andric ExternallyAccessible->setVisibility(OriginalFunction->getVisibility()); 479*0fca6ea1SDimitry Andric ExternallyAccessible->setComdat(OriginalFunction->getComdat()); 480*0fca6ea1SDimitry Andric ExternallyAccessible->takeName(OriginalFunction); 481*0fca6ea1SDimitry Andric 482*0fca6ea1SDimitry Andric // Annotate the internal one as internal 483*0fca6ea1SDimitry Andric InternalOnly->setVisibility(GlobalValue::DefaultVisibility); 484*0fca6ea1SDimitry Andric InternalOnly->setLinkage(GlobalValue::InternalLinkage); 485*0fca6ea1SDimitry Andric 486*0fca6ea1SDimitry Andric // The original is unused and obsolete 487*0fca6ea1SDimitry Andric OriginalFunction->eraseFromParent(); 488*0fca6ea1SDimitry Andric 489*0fca6ea1SDimitry Andric InternalOnly->removeDeadConstantUsers(); 490*0fca6ea1SDimitry Andric 491*0fca6ea1SDimitry Andric if (rewriteABI()) { 492*0fca6ea1SDimitry Andric // All known calls to the function have been removed by expandCall 493*0fca6ea1SDimitry Andric // Resolve everything else by replaceAllUsesWith 494*0fca6ea1SDimitry Andric VariadicWrapper->replaceAllUsesWith(FixedArityReplacement); 495*0fca6ea1SDimitry Andric VariadicWrapper->eraseFromParent(); 496*0fca6ea1SDimitry Andric } 497*0fca6ea1SDimitry Andric 498*0fca6ea1SDimitry Andric return Changed; 499*0fca6ea1SDimitry Andric } 500*0fca6ea1SDimitry Andric 501*0fca6ea1SDimitry Andric Function * 502*0fca6ea1SDimitry Andric ExpandVariadics::replaceAllUsesWithNewDeclaration(Module &M, 503*0fca6ea1SDimitry Andric Function *OriginalFunction) { 504*0fca6ea1SDimitry Andric auto &Ctx = M.getContext(); 505*0fca6ea1SDimitry Andric Function &F = *OriginalFunction; 506*0fca6ea1SDimitry Andric FunctionType *FTy = F.getFunctionType(); 507*0fca6ea1SDimitry Andric Function *NF = Function::Create(FTy, F.getLinkage(), F.getAddressSpace()); 508*0fca6ea1SDimitry Andric 509*0fca6ea1SDimitry Andric NF->setName(F.getName() + ".varargs"); 510*0fca6ea1SDimitry Andric NF->IsNewDbgInfoFormat = F.IsNewDbgInfoFormat; 511*0fca6ea1SDimitry Andric 512*0fca6ea1SDimitry Andric F.getParent()->getFunctionList().insert(F.getIterator(), NF); 513*0fca6ea1SDimitry Andric 514*0fca6ea1SDimitry Andric AttrBuilder ParamAttrs(Ctx); 515*0fca6ea1SDimitry Andric AttributeList Attrs = NF->getAttributes(); 516*0fca6ea1SDimitry Andric Attrs = Attrs.addParamAttributes(Ctx, FTy->getNumParams(), ParamAttrs); 517*0fca6ea1SDimitry Andric NF->setAttributes(Attrs); 518*0fca6ea1SDimitry Andric 519*0fca6ea1SDimitry Andric OriginalFunction->replaceAllUsesWith(NF); 520*0fca6ea1SDimitry Andric return NF; 521*0fca6ea1SDimitry Andric } 522*0fca6ea1SDimitry Andric 523*0fca6ea1SDimitry Andric Function * 524*0fca6ea1SDimitry Andric ExpandVariadics::deriveFixedArityReplacement(Module &M, IRBuilder<> &Builder, 525*0fca6ea1SDimitry Andric Function *OriginalFunction) { 526*0fca6ea1SDimitry Andric Function &F = *OriginalFunction; 527*0fca6ea1SDimitry Andric // The purpose here is split the variadic function F into two functions 528*0fca6ea1SDimitry Andric // One is a variadic function that bundles the passed argument into a va_list 529*0fca6ea1SDimitry Andric // and passes it to the second function. The second function does whatever 530*0fca6ea1SDimitry Andric // the original F does, except that it takes a va_list instead of the ... 531*0fca6ea1SDimitry Andric 532*0fca6ea1SDimitry Andric assert(expansionApplicableToFunction(M, &F)); 533*0fca6ea1SDimitry Andric 534*0fca6ea1SDimitry Andric auto &Ctx = M.getContext(); 535*0fca6ea1SDimitry Andric 536*0fca6ea1SDimitry Andric // Returned value isDeclaration() is equal to F.isDeclaration() 537*0fca6ea1SDimitry Andric // but that property is not invariant throughout this function 538*0fca6ea1SDimitry Andric const bool FunctionIsDefinition = !F.isDeclaration(); 539*0fca6ea1SDimitry Andric 540*0fca6ea1SDimitry Andric FunctionType *FTy = F.getFunctionType(); 541*0fca6ea1SDimitry Andric SmallVector<Type *> ArgTypes(FTy->param_begin(), FTy->param_end()); 542*0fca6ea1SDimitry Andric ArgTypes.push_back(ABI->vaListParameterType(M)); 543*0fca6ea1SDimitry Andric 544*0fca6ea1SDimitry Andric FunctionType *NFTy = inlinableVariadicFunctionType(M, FTy); 545*0fca6ea1SDimitry Andric Function *NF = Function::Create(NFTy, F.getLinkage(), F.getAddressSpace()); 546*0fca6ea1SDimitry Andric 547*0fca6ea1SDimitry Andric // Note - same attribute handling as DeadArgumentElimination 548*0fca6ea1SDimitry Andric NF->copyAttributesFrom(&F); 549*0fca6ea1SDimitry Andric NF->setComdat(F.getComdat()); 550*0fca6ea1SDimitry Andric F.getParent()->getFunctionList().insert(F.getIterator(), NF); 551*0fca6ea1SDimitry Andric NF->setName(F.getName() + ".valist"); 552*0fca6ea1SDimitry Andric NF->IsNewDbgInfoFormat = F.IsNewDbgInfoFormat; 553*0fca6ea1SDimitry Andric 554*0fca6ea1SDimitry Andric AttrBuilder ParamAttrs(Ctx); 555*0fca6ea1SDimitry Andric 556*0fca6ea1SDimitry Andric AttributeList Attrs = NF->getAttributes(); 557*0fca6ea1SDimitry Andric Attrs = Attrs.addParamAttributes(Ctx, NFTy->getNumParams() - 1, ParamAttrs); 558*0fca6ea1SDimitry Andric NF->setAttributes(Attrs); 559*0fca6ea1SDimitry Andric 560*0fca6ea1SDimitry Andric // Splice the implementation into the new function with minimal changes 561*0fca6ea1SDimitry Andric if (FunctionIsDefinition) { 562*0fca6ea1SDimitry Andric NF->splice(NF->begin(), &F); 563*0fca6ea1SDimitry Andric 564*0fca6ea1SDimitry Andric auto NewArg = NF->arg_begin(); 565*0fca6ea1SDimitry Andric for (Argument &Arg : F.args()) { 566*0fca6ea1SDimitry Andric Arg.replaceAllUsesWith(NewArg); 567*0fca6ea1SDimitry Andric NewArg->setName(Arg.getName()); // takeName without killing the old one 568*0fca6ea1SDimitry Andric ++NewArg; 569*0fca6ea1SDimitry Andric } 570*0fca6ea1SDimitry Andric NewArg->setName("varargs"); 571*0fca6ea1SDimitry Andric } 572*0fca6ea1SDimitry Andric 573*0fca6ea1SDimitry Andric SmallVector<std::pair<unsigned, MDNode *>, 1> MDs; 574*0fca6ea1SDimitry Andric F.getAllMetadata(MDs); 575*0fca6ea1SDimitry Andric for (auto [KindID, Node] : MDs) 576*0fca6ea1SDimitry Andric NF->addMetadata(KindID, *Node); 577*0fca6ea1SDimitry Andric F.clearMetadata(); 578*0fca6ea1SDimitry Andric 579*0fca6ea1SDimitry Andric return NF; 580*0fca6ea1SDimitry Andric } 581*0fca6ea1SDimitry Andric 582*0fca6ea1SDimitry Andric Function * 583*0fca6ea1SDimitry Andric ExpandVariadics::defineVariadicWrapper(Module &M, IRBuilder<> &Builder, 584*0fca6ea1SDimitry Andric Function *VariadicWrapper, 585*0fca6ea1SDimitry Andric Function *FixedArityReplacement) { 586*0fca6ea1SDimitry Andric auto &Ctx = Builder.getContext(); 587*0fca6ea1SDimitry Andric const DataLayout &DL = M.getDataLayout(); 588*0fca6ea1SDimitry Andric assert(VariadicWrapper->isDeclaration()); 589*0fca6ea1SDimitry Andric Function &F = *VariadicWrapper; 590*0fca6ea1SDimitry Andric 591*0fca6ea1SDimitry Andric assert(F.isDeclaration()); 592*0fca6ea1SDimitry Andric Type *VaListTy = ABI->vaListType(Ctx); 593*0fca6ea1SDimitry Andric 594*0fca6ea1SDimitry Andric auto *BB = BasicBlock::Create(Ctx, "entry", &F); 595*0fca6ea1SDimitry Andric Builder.SetInsertPoint(BB); 596*0fca6ea1SDimitry Andric 597*0fca6ea1SDimitry Andric AllocaInst *VaListInstance = 598*0fca6ea1SDimitry Andric Builder.CreateAlloca(VaListTy, nullptr, "va_start"); 599*0fca6ea1SDimitry Andric 600*0fca6ea1SDimitry Andric Builder.CreateLifetimeStart(VaListInstance, 601*0fca6ea1SDimitry Andric sizeOfAlloca(Ctx, DL, VaListInstance)); 602*0fca6ea1SDimitry Andric 603*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Intrinsic::vastart, {DL.getAllocaPtrType(Ctx)}, 604*0fca6ea1SDimitry Andric {VaListInstance}); 605*0fca6ea1SDimitry Andric 606*0fca6ea1SDimitry Andric SmallVector<Value *> Args; 607*0fca6ea1SDimitry Andric for (Argument &A : F.args()) 608*0fca6ea1SDimitry Andric Args.push_back(&A); 609*0fca6ea1SDimitry Andric 610*0fca6ea1SDimitry Andric Type *ParameterType = ABI->vaListParameterType(M); 611*0fca6ea1SDimitry Andric if (ABI->vaListPassedInSSARegister()) 612*0fca6ea1SDimitry Andric Args.push_back(Builder.CreateLoad(ParameterType, VaListInstance)); 613*0fca6ea1SDimitry Andric else 614*0fca6ea1SDimitry Andric Args.push_back(Builder.CreateAddrSpaceCast(VaListInstance, ParameterType)); 615*0fca6ea1SDimitry Andric 616*0fca6ea1SDimitry Andric CallInst *Result = Builder.CreateCall(FixedArityReplacement, Args); 617*0fca6ea1SDimitry Andric 618*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Intrinsic::vaend, {DL.getAllocaPtrType(Ctx)}, 619*0fca6ea1SDimitry Andric {VaListInstance}); 620*0fca6ea1SDimitry Andric Builder.CreateLifetimeEnd(VaListInstance, 621*0fca6ea1SDimitry Andric sizeOfAlloca(Ctx, DL, VaListInstance)); 622*0fca6ea1SDimitry Andric 623*0fca6ea1SDimitry Andric if (Result->getType()->isVoidTy()) 624*0fca6ea1SDimitry Andric Builder.CreateRetVoid(); 625*0fca6ea1SDimitry Andric else 626*0fca6ea1SDimitry Andric Builder.CreateRet(Result); 627*0fca6ea1SDimitry Andric 628*0fca6ea1SDimitry Andric return VariadicWrapper; 629*0fca6ea1SDimitry Andric } 630*0fca6ea1SDimitry Andric 631*0fca6ea1SDimitry Andric bool ExpandVariadics::expandCall(Module &M, IRBuilder<> &Builder, CallBase *CB, 632*0fca6ea1SDimitry Andric FunctionType *VarargFunctionType, 633*0fca6ea1SDimitry Andric Function *NF) { 634*0fca6ea1SDimitry Andric bool Changed = false; 635*0fca6ea1SDimitry Andric const DataLayout &DL = M.getDataLayout(); 636*0fca6ea1SDimitry Andric 637*0fca6ea1SDimitry Andric if (!expansionApplicableToFunctionCall(CB)) { 638*0fca6ea1SDimitry Andric if (rewriteABI()) 639*0fca6ea1SDimitry Andric report_fatal_error("Cannot lower callbase instruction"); 640*0fca6ea1SDimitry Andric return Changed; 641*0fca6ea1SDimitry Andric } 642*0fca6ea1SDimitry Andric 643*0fca6ea1SDimitry Andric // This is tricky. The call instruction's function type might not match 644*0fca6ea1SDimitry Andric // the type of the caller. When optimising, can leave it unchanged. 645*0fca6ea1SDimitry Andric // Webassembly detects that inconsistency and repairs it. 646*0fca6ea1SDimitry Andric FunctionType *FuncType = CB->getFunctionType(); 647*0fca6ea1SDimitry Andric if (FuncType != VarargFunctionType) { 648*0fca6ea1SDimitry Andric if (!rewriteABI()) 649*0fca6ea1SDimitry Andric return Changed; 650*0fca6ea1SDimitry Andric FuncType = VarargFunctionType; 651*0fca6ea1SDimitry Andric } 652*0fca6ea1SDimitry Andric 653*0fca6ea1SDimitry Andric auto &Ctx = CB->getContext(); 654*0fca6ea1SDimitry Andric 655*0fca6ea1SDimitry Andric Align MaxFieldAlign(1); 656*0fca6ea1SDimitry Andric 657*0fca6ea1SDimitry Andric // The strategy is to allocate a call frame containing the variadic 658*0fca6ea1SDimitry Andric // arguments laid out such that a target specific va_list can be initialized 659*0fca6ea1SDimitry Andric // with it, such that target specific va_arg instructions will correctly 660*0fca6ea1SDimitry Andric // iterate over it. This means getting the alignment right and sometimes 661*0fca6ea1SDimitry Andric // embedding a pointer to the value instead of embedding the value itself. 662*0fca6ea1SDimitry Andric 663*0fca6ea1SDimitry Andric Function *CBF = CB->getParent()->getParent(); 664*0fca6ea1SDimitry Andric 665*0fca6ea1SDimitry Andric ExpandedCallFrame Frame; 666*0fca6ea1SDimitry Andric 667*0fca6ea1SDimitry Andric uint64_t CurrentOffset = 0; 668*0fca6ea1SDimitry Andric 669*0fca6ea1SDimitry Andric for (unsigned I = FuncType->getNumParams(), E = CB->arg_size(); I < E; ++I) { 670*0fca6ea1SDimitry Andric Value *ArgVal = CB->getArgOperand(I); 671*0fca6ea1SDimitry Andric const bool IsByVal = CB->paramHasAttr(I, Attribute::ByVal); 672*0fca6ea1SDimitry Andric const bool IsByRef = CB->paramHasAttr(I, Attribute::ByRef); 673*0fca6ea1SDimitry Andric 674*0fca6ea1SDimitry Andric // The type of the value being passed, decoded from byval/byref metadata if 675*0fca6ea1SDimitry Andric // required 676*0fca6ea1SDimitry Andric Type *const UnderlyingType = IsByVal ? CB->getParamByValType(I) 677*0fca6ea1SDimitry Andric : IsByRef ? CB->getParamByRefType(I) 678*0fca6ea1SDimitry Andric : ArgVal->getType(); 679*0fca6ea1SDimitry Andric const uint64_t UnderlyingSize = 680*0fca6ea1SDimitry Andric DL.getTypeAllocSize(UnderlyingType).getFixedValue(); 681*0fca6ea1SDimitry Andric 682*0fca6ea1SDimitry Andric // The type to be written into the call frame 683*0fca6ea1SDimitry Andric Type *FrameFieldType = UnderlyingType; 684*0fca6ea1SDimitry Andric 685*0fca6ea1SDimitry Andric // The value to copy from when initialising the frame alloca 686*0fca6ea1SDimitry Andric Value *SourceValue = ArgVal; 687*0fca6ea1SDimitry Andric 688*0fca6ea1SDimitry Andric VariadicABIInfo::VAArgSlotInfo SlotInfo = ABI->slotInfo(DL, UnderlyingType); 689*0fca6ea1SDimitry Andric 690*0fca6ea1SDimitry Andric if (SlotInfo.Indirect) { 691*0fca6ea1SDimitry Andric // The va_arg lowering loads through a pointer. Set up an alloca to aim 692*0fca6ea1SDimitry Andric // that pointer at. 693*0fca6ea1SDimitry Andric Builder.SetInsertPointPastAllocas(CBF); 694*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(CB->getStableDebugLoc()); 695*0fca6ea1SDimitry Andric Value *CallerCopy = 696*0fca6ea1SDimitry Andric Builder.CreateAlloca(UnderlyingType, nullptr, "IndirectAlloca"); 697*0fca6ea1SDimitry Andric 698*0fca6ea1SDimitry Andric Builder.SetInsertPoint(CB); 699*0fca6ea1SDimitry Andric if (IsByVal) 700*0fca6ea1SDimitry Andric Builder.CreateMemCpy(CallerCopy, {}, ArgVal, {}, UnderlyingSize); 701*0fca6ea1SDimitry Andric else 702*0fca6ea1SDimitry Andric Builder.CreateStore(ArgVal, CallerCopy); 703*0fca6ea1SDimitry Andric 704*0fca6ea1SDimitry Andric // Indirection now handled, pass the alloca ptr by value 705*0fca6ea1SDimitry Andric FrameFieldType = DL.getAllocaPtrType(Ctx); 706*0fca6ea1SDimitry Andric SourceValue = CallerCopy; 707*0fca6ea1SDimitry Andric } 708*0fca6ea1SDimitry Andric 709*0fca6ea1SDimitry Andric // Alignment of the value within the frame 710*0fca6ea1SDimitry Andric // This probably needs to be controllable as a function of type 711*0fca6ea1SDimitry Andric Align DataAlign = SlotInfo.DataAlign; 712*0fca6ea1SDimitry Andric 713*0fca6ea1SDimitry Andric MaxFieldAlign = std::max(MaxFieldAlign, DataAlign); 714*0fca6ea1SDimitry Andric 715*0fca6ea1SDimitry Andric uint64_t DataAlignV = DataAlign.value(); 716*0fca6ea1SDimitry Andric if (uint64_t Rem = CurrentOffset % DataAlignV) { 717*0fca6ea1SDimitry Andric // Inject explicit padding to deal with alignment requirements 718*0fca6ea1SDimitry Andric uint64_t Padding = DataAlignV - Rem; 719*0fca6ea1SDimitry Andric Frame.padding(Ctx, Padding); 720*0fca6ea1SDimitry Andric CurrentOffset += Padding; 721*0fca6ea1SDimitry Andric } 722*0fca6ea1SDimitry Andric 723*0fca6ea1SDimitry Andric if (SlotInfo.Indirect) { 724*0fca6ea1SDimitry Andric Frame.store(Ctx, FrameFieldType, SourceValue); 725*0fca6ea1SDimitry Andric } else { 726*0fca6ea1SDimitry Andric if (IsByVal) 727*0fca6ea1SDimitry Andric Frame.memcpy(Ctx, FrameFieldType, SourceValue, UnderlyingSize); 728*0fca6ea1SDimitry Andric else 729*0fca6ea1SDimitry Andric Frame.store(Ctx, FrameFieldType, SourceValue); 730*0fca6ea1SDimitry Andric } 731*0fca6ea1SDimitry Andric 732*0fca6ea1SDimitry Andric CurrentOffset += DL.getTypeAllocSize(FrameFieldType).getFixedValue(); 733*0fca6ea1SDimitry Andric } 734*0fca6ea1SDimitry Andric 735*0fca6ea1SDimitry Andric if (Frame.empty()) { 736*0fca6ea1SDimitry Andric // Not passing any arguments, hopefully va_arg won't try to read any 737*0fca6ea1SDimitry Andric // Creating a single byte frame containing nothing to point the va_list 738*0fca6ea1SDimitry Andric // instance as that is less special-casey in the compiler and probably 739*0fca6ea1SDimitry Andric // easier to interpret in a debugger. 740*0fca6ea1SDimitry Andric Frame.padding(Ctx, 1); 741*0fca6ea1SDimitry Andric } 742*0fca6ea1SDimitry Andric 743*0fca6ea1SDimitry Andric StructType *VarargsTy = Frame.asStruct(Ctx, CBF->getName()); 744*0fca6ea1SDimitry Andric 745*0fca6ea1SDimitry Andric // The struct instance needs to be at least MaxFieldAlign for the alignment of 746*0fca6ea1SDimitry Andric // the fields to be correct at runtime. Use the native stack alignment instead 747*0fca6ea1SDimitry Andric // if that's greater as that tends to give better codegen. 748*0fca6ea1SDimitry Andric // This is an awkward way to guess whether there is a known stack alignment 749*0fca6ea1SDimitry Andric // without hitting an assert in DL.getStackAlignment, 1024 is an arbitrary 750*0fca6ea1SDimitry Andric // number likely to be greater than the natural stack alignment. 751*0fca6ea1SDimitry Andric // TODO: DL.getStackAlignment could return a MaybeAlign instead of assert 752*0fca6ea1SDimitry Andric Align AllocaAlign = MaxFieldAlign; 753*0fca6ea1SDimitry Andric if (DL.exceedsNaturalStackAlignment(Align(1024))) 754*0fca6ea1SDimitry Andric AllocaAlign = std::max(AllocaAlign, DL.getStackAlignment()); 755*0fca6ea1SDimitry Andric 756*0fca6ea1SDimitry Andric // Put the alloca to hold the variadic args in the entry basic block. 757*0fca6ea1SDimitry Andric Builder.SetInsertPointPastAllocas(CBF); 758*0fca6ea1SDimitry Andric 759*0fca6ea1SDimitry Andric // SetCurrentDebugLocation when the builder SetInsertPoint method does not 760*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(CB->getStableDebugLoc()); 761*0fca6ea1SDimitry Andric 762*0fca6ea1SDimitry Andric // The awkward construction here is to set the alignment on the instance 763*0fca6ea1SDimitry Andric AllocaInst *Alloced = Builder.Insert( 764*0fca6ea1SDimitry Andric new AllocaInst(VarargsTy, DL.getAllocaAddrSpace(), nullptr, AllocaAlign), 765*0fca6ea1SDimitry Andric "vararg_buffer"); 766*0fca6ea1SDimitry Andric Changed = true; 767*0fca6ea1SDimitry Andric assert(Alloced->getAllocatedType() == VarargsTy); 768*0fca6ea1SDimitry Andric 769*0fca6ea1SDimitry Andric // Initialize the fields in the struct 770*0fca6ea1SDimitry Andric Builder.SetInsertPoint(CB); 771*0fca6ea1SDimitry Andric Builder.CreateLifetimeStart(Alloced, sizeOfAlloca(Ctx, DL, Alloced)); 772*0fca6ea1SDimitry Andric Frame.initializeStructAlloca(DL, Builder, Alloced); 773*0fca6ea1SDimitry Andric 774*0fca6ea1SDimitry Andric const unsigned NumArgs = FuncType->getNumParams(); 775*0fca6ea1SDimitry Andric SmallVector<Value *> Args(CB->arg_begin(), CB->arg_begin() + NumArgs); 776*0fca6ea1SDimitry Andric 777*0fca6ea1SDimitry Andric // Initialize a va_list pointing to that struct and pass it as the last 778*0fca6ea1SDimitry Andric // argument 779*0fca6ea1SDimitry Andric AllocaInst *VaList = nullptr; 780*0fca6ea1SDimitry Andric { 781*0fca6ea1SDimitry Andric if (!ABI->vaListPassedInSSARegister()) { 782*0fca6ea1SDimitry Andric Type *VaListTy = ABI->vaListType(Ctx); 783*0fca6ea1SDimitry Andric Builder.SetInsertPointPastAllocas(CBF); 784*0fca6ea1SDimitry Andric Builder.SetCurrentDebugLocation(CB->getStableDebugLoc()); 785*0fca6ea1SDimitry Andric VaList = Builder.CreateAlloca(VaListTy, nullptr, "va_argument"); 786*0fca6ea1SDimitry Andric Builder.SetInsertPoint(CB); 787*0fca6ea1SDimitry Andric Builder.CreateLifetimeStart(VaList, sizeOfAlloca(Ctx, DL, VaList)); 788*0fca6ea1SDimitry Andric } 789*0fca6ea1SDimitry Andric Builder.SetInsertPoint(CB); 790*0fca6ea1SDimitry Andric Args.push_back(ABI->initializeVaList(M, Ctx, Builder, VaList, Alloced)); 791*0fca6ea1SDimitry Andric } 792*0fca6ea1SDimitry Andric 793*0fca6ea1SDimitry Andric // Attributes excluding any on the vararg arguments 794*0fca6ea1SDimitry Andric AttributeList PAL = CB->getAttributes(); 795*0fca6ea1SDimitry Andric if (!PAL.isEmpty()) { 796*0fca6ea1SDimitry Andric SmallVector<AttributeSet, 8> ArgAttrs; 797*0fca6ea1SDimitry Andric for (unsigned ArgNo = 0; ArgNo < NumArgs; ArgNo++) 798*0fca6ea1SDimitry Andric ArgAttrs.push_back(PAL.getParamAttrs(ArgNo)); 799*0fca6ea1SDimitry Andric PAL = 800*0fca6ea1SDimitry Andric AttributeList::get(Ctx, PAL.getFnAttrs(), PAL.getRetAttrs(), ArgAttrs); 801*0fca6ea1SDimitry Andric } 802*0fca6ea1SDimitry Andric 803*0fca6ea1SDimitry Andric SmallVector<OperandBundleDef, 1> OpBundles; 804*0fca6ea1SDimitry Andric CB->getOperandBundlesAsDefs(OpBundles); 805*0fca6ea1SDimitry Andric 806*0fca6ea1SDimitry Andric CallBase *NewCB = nullptr; 807*0fca6ea1SDimitry Andric 808*0fca6ea1SDimitry Andric if (CallInst *CI = dyn_cast<CallInst>(CB)) { 809*0fca6ea1SDimitry Andric Value *Dst = NF ? NF : CI->getCalledOperand(); 810*0fca6ea1SDimitry Andric FunctionType *NFTy = inlinableVariadicFunctionType(M, VarargFunctionType); 811*0fca6ea1SDimitry Andric 812*0fca6ea1SDimitry Andric NewCB = CallInst::Create(NFTy, Dst, Args, OpBundles, "", CI); 813*0fca6ea1SDimitry Andric 814*0fca6ea1SDimitry Andric CallInst::TailCallKind TCK = CI->getTailCallKind(); 815*0fca6ea1SDimitry Andric assert(TCK != CallInst::TCK_MustTail); 816*0fca6ea1SDimitry Andric 817*0fca6ea1SDimitry Andric // Can't tail call a function that is being passed a pointer to an alloca 818*0fca6ea1SDimitry Andric if (TCK == CallInst::TCK_Tail) 819*0fca6ea1SDimitry Andric TCK = CallInst::TCK_None; 820*0fca6ea1SDimitry Andric CI->setTailCallKind(TCK); 821*0fca6ea1SDimitry Andric 822*0fca6ea1SDimitry Andric } else { 823*0fca6ea1SDimitry Andric llvm_unreachable("Unreachable when !expansionApplicableToFunctionCall()"); 824*0fca6ea1SDimitry Andric } 825*0fca6ea1SDimitry Andric 826*0fca6ea1SDimitry Andric if (VaList) 827*0fca6ea1SDimitry Andric Builder.CreateLifetimeEnd(VaList, sizeOfAlloca(Ctx, DL, VaList)); 828*0fca6ea1SDimitry Andric 829*0fca6ea1SDimitry Andric Builder.CreateLifetimeEnd(Alloced, sizeOfAlloca(Ctx, DL, Alloced)); 830*0fca6ea1SDimitry Andric 831*0fca6ea1SDimitry Andric NewCB->setAttributes(PAL); 832*0fca6ea1SDimitry Andric NewCB->takeName(CB); 833*0fca6ea1SDimitry Andric NewCB->setCallingConv(CB->getCallingConv()); 834*0fca6ea1SDimitry Andric NewCB->setDebugLoc(DebugLoc()); 835*0fca6ea1SDimitry Andric 836*0fca6ea1SDimitry Andric // DeadArgElim and ArgPromotion copy exactly this metadata 837*0fca6ea1SDimitry Andric NewCB->copyMetadata(*CB, {LLVMContext::MD_prof, LLVMContext::MD_dbg}); 838*0fca6ea1SDimitry Andric 839*0fca6ea1SDimitry Andric CB->replaceAllUsesWith(NewCB); 840*0fca6ea1SDimitry Andric CB->eraseFromParent(); 841*0fca6ea1SDimitry Andric return Changed; 842*0fca6ea1SDimitry Andric } 843*0fca6ea1SDimitry Andric 844*0fca6ea1SDimitry Andric bool ExpandVariadics::expandVAIntrinsicCall(IRBuilder<> &Builder, 845*0fca6ea1SDimitry Andric const DataLayout &DL, 846*0fca6ea1SDimitry Andric VAStartInst *Inst) { 847*0fca6ea1SDimitry Andric // Only removing va_start instructions that are not in variadic functions. 848*0fca6ea1SDimitry Andric // Those would be rejected by the IR verifier before this pass. 849*0fca6ea1SDimitry Andric // After splicing basic blocks from a variadic function into a fixed arity 850*0fca6ea1SDimitry Andric // one the va_start that used to refer to the ... parameter still exist. 851*0fca6ea1SDimitry Andric // There are also variadic functions that this pass did not change and 852*0fca6ea1SDimitry Andric // va_start instances in the created single block wrapper functions. 853*0fca6ea1SDimitry Andric // Replace exactly the instances in non-variadic functions as those are 854*0fca6ea1SDimitry Andric // the ones to be fixed up to use the va_list passed as the final argument. 855*0fca6ea1SDimitry Andric 856*0fca6ea1SDimitry Andric Function *ContainingFunction = Inst->getFunction(); 857*0fca6ea1SDimitry Andric if (ContainingFunction->isVarArg()) { 858*0fca6ea1SDimitry Andric return false; 859*0fca6ea1SDimitry Andric } 860*0fca6ea1SDimitry Andric 861*0fca6ea1SDimitry Andric // The last argument is a vaListParameterType, either a va_list 862*0fca6ea1SDimitry Andric // or a pointer to one depending on the target. 863*0fca6ea1SDimitry Andric bool PassedByValue = ABI->vaListPassedInSSARegister(); 864*0fca6ea1SDimitry Andric Argument *PassedVaList = 865*0fca6ea1SDimitry Andric ContainingFunction->getArg(ContainingFunction->arg_size() - 1); 866*0fca6ea1SDimitry Andric 867*0fca6ea1SDimitry Andric // va_start takes a pointer to a va_list, e.g. one on the stack 868*0fca6ea1SDimitry Andric Value *VaStartArg = Inst->getArgList(); 869*0fca6ea1SDimitry Andric 870*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Inst); 871*0fca6ea1SDimitry Andric 872*0fca6ea1SDimitry Andric if (PassedByValue) { 873*0fca6ea1SDimitry Andric // The general thing to do is create an alloca, store the va_list argument 874*0fca6ea1SDimitry Andric // to it, then create a va_copy. When vaCopyIsMemcpy(), this optimises to a 875*0fca6ea1SDimitry Andric // store to the VaStartArg. 876*0fca6ea1SDimitry Andric assert(ABI->vaCopyIsMemcpy()); 877*0fca6ea1SDimitry Andric Builder.CreateStore(PassedVaList, VaStartArg); 878*0fca6ea1SDimitry Andric } else { 879*0fca6ea1SDimitry Andric 880*0fca6ea1SDimitry Andric // Otherwise emit a vacopy to pick up target-specific handling if any 881*0fca6ea1SDimitry Andric auto &Ctx = Builder.getContext(); 882*0fca6ea1SDimitry Andric 883*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Intrinsic::vacopy, {DL.getAllocaPtrType(Ctx)}, 884*0fca6ea1SDimitry Andric {VaStartArg, PassedVaList}); 885*0fca6ea1SDimitry Andric } 886*0fca6ea1SDimitry Andric 887*0fca6ea1SDimitry Andric Inst->eraseFromParent(); 888*0fca6ea1SDimitry Andric return true; 889*0fca6ea1SDimitry Andric } 890*0fca6ea1SDimitry Andric 891*0fca6ea1SDimitry Andric bool ExpandVariadics::expandVAIntrinsicCall(IRBuilder<> &, const DataLayout &, 892*0fca6ea1SDimitry Andric VAEndInst *Inst) { 893*0fca6ea1SDimitry Andric assert(ABI->vaEndIsNop()); 894*0fca6ea1SDimitry Andric Inst->eraseFromParent(); 895*0fca6ea1SDimitry Andric return true; 896*0fca6ea1SDimitry Andric } 897*0fca6ea1SDimitry Andric 898*0fca6ea1SDimitry Andric bool ExpandVariadics::expandVAIntrinsicCall(IRBuilder<> &Builder, 899*0fca6ea1SDimitry Andric const DataLayout &DL, 900*0fca6ea1SDimitry Andric VACopyInst *Inst) { 901*0fca6ea1SDimitry Andric assert(ABI->vaCopyIsMemcpy()); 902*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Inst); 903*0fca6ea1SDimitry Andric 904*0fca6ea1SDimitry Andric auto &Ctx = Builder.getContext(); 905*0fca6ea1SDimitry Andric Type *VaListTy = ABI->vaListType(Ctx); 906*0fca6ea1SDimitry Andric uint64_t Size = DL.getTypeAllocSize(VaListTy).getFixedValue(); 907*0fca6ea1SDimitry Andric 908*0fca6ea1SDimitry Andric Builder.CreateMemCpy(Inst->getDest(), {}, Inst->getSrc(), {}, 909*0fca6ea1SDimitry Andric Builder.getInt32(Size)); 910*0fca6ea1SDimitry Andric 911*0fca6ea1SDimitry Andric Inst->eraseFromParent(); 912*0fca6ea1SDimitry Andric return true; 913*0fca6ea1SDimitry Andric } 914*0fca6ea1SDimitry Andric 915*0fca6ea1SDimitry Andric struct Amdgpu final : public VariadicABIInfo { 916*0fca6ea1SDimitry Andric 917*0fca6ea1SDimitry Andric bool enableForTarget() override { return true; } 918*0fca6ea1SDimitry Andric 919*0fca6ea1SDimitry Andric bool vaListPassedInSSARegister() override { return true; } 920*0fca6ea1SDimitry Andric 921*0fca6ea1SDimitry Andric Type *vaListType(LLVMContext &Ctx) override { 922*0fca6ea1SDimitry Andric return PointerType::getUnqual(Ctx); 923*0fca6ea1SDimitry Andric } 924*0fca6ea1SDimitry Andric 925*0fca6ea1SDimitry Andric Type *vaListParameterType(Module &M) override { 926*0fca6ea1SDimitry Andric return PointerType::getUnqual(M.getContext()); 927*0fca6ea1SDimitry Andric } 928*0fca6ea1SDimitry Andric 929*0fca6ea1SDimitry Andric Value *initializeVaList(Module &M, LLVMContext &Ctx, IRBuilder<> &Builder, 930*0fca6ea1SDimitry Andric AllocaInst * /*va_list*/, Value *Buffer) override { 931*0fca6ea1SDimitry Andric // Given Buffer, which is an AllocInst of vararg_buffer 932*0fca6ea1SDimitry Andric // need to return something usable as parameter type 933*0fca6ea1SDimitry Andric return Builder.CreateAddrSpaceCast(Buffer, vaListParameterType(M)); 934*0fca6ea1SDimitry Andric } 935*0fca6ea1SDimitry Andric 936*0fca6ea1SDimitry Andric VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) override { 937*0fca6ea1SDimitry Andric return {Align(4), false}; 938*0fca6ea1SDimitry Andric } 939*0fca6ea1SDimitry Andric }; 940*0fca6ea1SDimitry Andric 941*0fca6ea1SDimitry Andric struct NVPTX final : public VariadicABIInfo { 942*0fca6ea1SDimitry Andric 943*0fca6ea1SDimitry Andric bool enableForTarget() override { return true; } 944*0fca6ea1SDimitry Andric 945*0fca6ea1SDimitry Andric bool vaListPassedInSSARegister() override { return true; } 946*0fca6ea1SDimitry Andric 947*0fca6ea1SDimitry Andric Type *vaListType(LLVMContext &Ctx) override { 948*0fca6ea1SDimitry Andric return PointerType::getUnqual(Ctx); 949*0fca6ea1SDimitry Andric } 950*0fca6ea1SDimitry Andric 951*0fca6ea1SDimitry Andric Type *vaListParameterType(Module &M) override { 952*0fca6ea1SDimitry Andric return PointerType::getUnqual(M.getContext()); 953*0fca6ea1SDimitry Andric } 954*0fca6ea1SDimitry Andric 955*0fca6ea1SDimitry Andric Value *initializeVaList(Module &M, LLVMContext &Ctx, IRBuilder<> &Builder, 956*0fca6ea1SDimitry Andric AllocaInst *, Value *Buffer) override { 957*0fca6ea1SDimitry Andric return Builder.CreateAddrSpaceCast(Buffer, vaListParameterType(M)); 958*0fca6ea1SDimitry Andric } 959*0fca6ea1SDimitry Andric 960*0fca6ea1SDimitry Andric VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) override { 961*0fca6ea1SDimitry Andric // NVPTX expects natural alignment in all cases. The variadic call ABI will 962*0fca6ea1SDimitry Andric // handle promoting types to their appropriate size and alignment. 963*0fca6ea1SDimitry Andric Align A = DL.getABITypeAlign(Parameter); 964*0fca6ea1SDimitry Andric return {A, false}; 965*0fca6ea1SDimitry Andric } 966*0fca6ea1SDimitry Andric }; 967*0fca6ea1SDimitry Andric 968*0fca6ea1SDimitry Andric struct Wasm final : public VariadicABIInfo { 969*0fca6ea1SDimitry Andric 970*0fca6ea1SDimitry Andric bool enableForTarget() override { 971*0fca6ea1SDimitry Andric // Currently wasm is only used for testing. 972*0fca6ea1SDimitry Andric return commandLineOverride(); 973*0fca6ea1SDimitry Andric } 974*0fca6ea1SDimitry Andric 975*0fca6ea1SDimitry Andric bool vaListPassedInSSARegister() override { return true; } 976*0fca6ea1SDimitry Andric 977*0fca6ea1SDimitry Andric Type *vaListType(LLVMContext &Ctx) override { 978*0fca6ea1SDimitry Andric return PointerType::getUnqual(Ctx); 979*0fca6ea1SDimitry Andric } 980*0fca6ea1SDimitry Andric 981*0fca6ea1SDimitry Andric Type *vaListParameterType(Module &M) override { 982*0fca6ea1SDimitry Andric return PointerType::getUnqual(M.getContext()); 983*0fca6ea1SDimitry Andric } 984*0fca6ea1SDimitry Andric 985*0fca6ea1SDimitry Andric Value *initializeVaList(Module &M, LLVMContext &Ctx, IRBuilder<> &Builder, 986*0fca6ea1SDimitry Andric AllocaInst * /*va_list*/, Value *Buffer) override { 987*0fca6ea1SDimitry Andric return Buffer; 988*0fca6ea1SDimitry Andric } 989*0fca6ea1SDimitry Andric 990*0fca6ea1SDimitry Andric VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) override { 991*0fca6ea1SDimitry Andric LLVMContext &Ctx = Parameter->getContext(); 992*0fca6ea1SDimitry Andric const unsigned MinAlign = 4; 993*0fca6ea1SDimitry Andric Align A = DL.getABITypeAlign(Parameter); 994*0fca6ea1SDimitry Andric if (A < MinAlign) 995*0fca6ea1SDimitry Andric A = Align(MinAlign); 996*0fca6ea1SDimitry Andric 997*0fca6ea1SDimitry Andric if (auto *S = dyn_cast<StructType>(Parameter)) { 998*0fca6ea1SDimitry Andric if (S->getNumElements() > 1) { 999*0fca6ea1SDimitry Andric return {DL.getABITypeAlign(PointerType::getUnqual(Ctx)), true}; 1000*0fca6ea1SDimitry Andric } 1001*0fca6ea1SDimitry Andric } 1002*0fca6ea1SDimitry Andric 1003*0fca6ea1SDimitry Andric return {A, false}; 1004*0fca6ea1SDimitry Andric } 1005*0fca6ea1SDimitry Andric }; 1006*0fca6ea1SDimitry Andric 1007*0fca6ea1SDimitry Andric std::unique_ptr<VariadicABIInfo> VariadicABIInfo::create(const Triple &T) { 1008*0fca6ea1SDimitry Andric switch (T.getArch()) { 1009*0fca6ea1SDimitry Andric case Triple::r600: 1010*0fca6ea1SDimitry Andric case Triple::amdgcn: { 1011*0fca6ea1SDimitry Andric return std::make_unique<Amdgpu>(); 1012*0fca6ea1SDimitry Andric } 1013*0fca6ea1SDimitry Andric 1014*0fca6ea1SDimitry Andric case Triple::wasm32: { 1015*0fca6ea1SDimitry Andric return std::make_unique<Wasm>(); 1016*0fca6ea1SDimitry Andric } 1017*0fca6ea1SDimitry Andric 1018*0fca6ea1SDimitry Andric case Triple::nvptx: 1019*0fca6ea1SDimitry Andric case Triple::nvptx64: { 1020*0fca6ea1SDimitry Andric return std::make_unique<NVPTX>(); 1021*0fca6ea1SDimitry Andric } 1022*0fca6ea1SDimitry Andric 1023*0fca6ea1SDimitry Andric default: 1024*0fca6ea1SDimitry Andric return {}; 1025*0fca6ea1SDimitry Andric } 1026*0fca6ea1SDimitry Andric } 1027*0fca6ea1SDimitry Andric 1028*0fca6ea1SDimitry Andric } // namespace 1029*0fca6ea1SDimitry Andric 1030*0fca6ea1SDimitry Andric char ExpandVariadics::ID = 0; 1031*0fca6ea1SDimitry Andric 1032*0fca6ea1SDimitry Andric INITIALIZE_PASS(ExpandVariadics, DEBUG_TYPE, "Expand variadic functions", false, 1033*0fca6ea1SDimitry Andric false) 1034*0fca6ea1SDimitry Andric 1035*0fca6ea1SDimitry Andric ModulePass *llvm::createExpandVariadicsPass(ExpandVariadicsMode M) { 1036*0fca6ea1SDimitry Andric return new ExpandVariadics(M); 1037*0fca6ea1SDimitry Andric } 1038*0fca6ea1SDimitry Andric 1039*0fca6ea1SDimitry Andric PreservedAnalyses ExpandVariadicsPass::run(Module &M, ModuleAnalysisManager &) { 1040*0fca6ea1SDimitry Andric return ExpandVariadics(Mode).runOnModule(M) ? PreservedAnalyses::none() 1041*0fca6ea1SDimitry Andric : PreservedAnalyses::all(); 1042*0fca6ea1SDimitry Andric } 1043*0fca6ea1SDimitry Andric 1044*0fca6ea1SDimitry Andric ExpandVariadicsPass::ExpandVariadicsPass(ExpandVariadicsMode M) : Mode(M) {} 1045