18516f54eSJon Chesterfield //===-- ExpandVariadicsPass.cpp --------------------------------*- C++ -*-=// 28516f54eSJon Chesterfield // 38516f54eSJon Chesterfield // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48516f54eSJon Chesterfield // See https://llvm.org/LICENSE.txt for license information. 58516f54eSJon Chesterfield // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68516f54eSJon Chesterfield // 78516f54eSJon Chesterfield //===----------------------------------------------------------------------===// 88516f54eSJon Chesterfield // 98516f54eSJon Chesterfield // This is an optimization pass for variadic functions. If called from codegen, 108516f54eSJon Chesterfield // it can serve as the implementation of variadic functions for a given target. 118516f54eSJon Chesterfield // 128516f54eSJon Chesterfield // The strategy is to turn the ... part of a variadic function into a va_list 138516f54eSJon Chesterfield // and fix up the call sites. The majority of the pass is target independent. 148516f54eSJon Chesterfield // The exceptions are the va_list type itself and the rules for where to store 158516f54eSJon Chesterfield // variables in memory such that va_arg can iterate over them given a va_list. 168516f54eSJon Chesterfield // 178516f54eSJon Chesterfield // The majority of the plumbing is splitting the variadic function into a 188516f54eSJon Chesterfield // single basic block that packs the variadic arguments into a va_list and 198516f54eSJon Chesterfield // a second function that does the work of the original. That packing is 208516f54eSJon Chesterfield // exactly what is done by va_start. Further, the transform from ... to va_list 218516f54eSJon Chesterfield // replaced va_start with an operation to copy a va_list from the new argument, 228516f54eSJon Chesterfield // which is exactly a va_copy. This is useful for reducing target-dependence. 238516f54eSJon Chesterfield // 248516f54eSJon Chesterfield // A va_list instance is a forward iterator, where the primary operation va_arg 258516f54eSJon Chesterfield // is dereference-then-increment. This interface forces significant convergent 268516f54eSJon Chesterfield // evolution between target specific implementations. The variation in runtime 278516f54eSJon Chesterfield // data layout is limited to that representable by the iterator, parameterised 288516f54eSJon Chesterfield // by the type passed to the va_arg instruction. 298516f54eSJon Chesterfield // 308516f54eSJon Chesterfield // Therefore the majority of the target specific subtlety is packing arguments 318516f54eSJon Chesterfield // into a stack allocated buffer such that a va_list can be initialised with it 328516f54eSJon Chesterfield // and the va_arg expansion for the target will find the arguments at runtime. 338516f54eSJon Chesterfield // 348516f54eSJon Chesterfield // The aggregate effect is to unblock other transforms, most critically the 358516f54eSJon Chesterfield // general purpose inliner. Known calls to variadic functions become zero cost. 368516f54eSJon Chesterfield // 378516f54eSJon Chesterfield // Consistency with clang is primarily tested by emitting va_arg using clang 388516f54eSJon Chesterfield // then expanding the variadic functions using this pass, followed by trying 398516f54eSJon Chesterfield // to constant fold the functions to no-ops. 408516f54eSJon Chesterfield // 418516f54eSJon Chesterfield // Target specific behaviour is tested in IR - mainly checking that values are 428516f54eSJon Chesterfield // put into positions in call frames that make sense for that particular target. 438516f54eSJon Chesterfield // 448516f54eSJon Chesterfield // There is one "clever" invariant in use. va_start intrinsics that are not 458516f54eSJon Chesterfield // within a varidic functions are an error in the IR verifier. When this 468516f54eSJon Chesterfield // transform moves blocks from a variadic function into a fixed arity one, it 478516f54eSJon Chesterfield // moves va_start intrinsics along with everything else. That means that the 488516f54eSJon Chesterfield // va_start intrinsics that need to be rewritten to use the trailing argument 498516f54eSJon Chesterfield // are exactly those that are in non-variadic functions so no further state 508516f54eSJon Chesterfield // is needed to distinguish those that need to be rewritten. 518516f54eSJon Chesterfield // 528516f54eSJon Chesterfield //===----------------------------------------------------------------------===// 538516f54eSJon Chesterfield 548516f54eSJon Chesterfield #include "llvm/Transforms/IPO/ExpandVariadics.h" 558516f54eSJon Chesterfield #include "llvm/ADT/SmallVector.h" 568516f54eSJon Chesterfield #include "llvm/IR/Constants.h" 578516f54eSJon Chesterfield #include "llvm/IR/IRBuilder.h" 588516f54eSJon Chesterfield #include "llvm/IR/IntrinsicInst.h" 598516f54eSJon Chesterfield #include "llvm/IR/Module.h" 608516f54eSJon Chesterfield #include "llvm/IR/PassManager.h" 618516f54eSJon Chesterfield #include "llvm/InitializePasses.h" 628516f54eSJon Chesterfield #include "llvm/Pass.h" 638516f54eSJon Chesterfield #include "llvm/Support/CommandLine.h" 648516f54eSJon Chesterfield #include "llvm/TargetParser/Triple.h" 658516f54eSJon Chesterfield #include "llvm/Transforms/Utils/ModuleUtils.h" 668516f54eSJon Chesterfield 678516f54eSJon Chesterfield #define DEBUG_TYPE "expand-variadics" 688516f54eSJon Chesterfield 698516f54eSJon Chesterfield using namespace llvm; 708516f54eSJon Chesterfield 718516f54eSJon Chesterfield namespace { 728516f54eSJon Chesterfield 738516f54eSJon Chesterfield cl::opt<ExpandVariadicsMode> ExpandVariadicsModeOption( 748516f54eSJon Chesterfield DEBUG_TYPE "-override", cl::desc("Override the behaviour of " DEBUG_TYPE), 758516f54eSJon Chesterfield cl::init(ExpandVariadicsMode::Unspecified), 768516f54eSJon Chesterfield cl::values(clEnumValN(ExpandVariadicsMode::Unspecified, "unspecified", 778516f54eSJon Chesterfield "Use the implementation defaults"), 788516f54eSJon Chesterfield clEnumValN(ExpandVariadicsMode::Disable, "disable", 798516f54eSJon Chesterfield "Disable the pass entirely"), 808516f54eSJon Chesterfield clEnumValN(ExpandVariadicsMode::Optimize, "optimize", 818516f54eSJon Chesterfield "Optimise without changing ABI"), 828516f54eSJon Chesterfield clEnumValN(ExpandVariadicsMode::Lowering, "lowering", 838516f54eSJon Chesterfield "Change variadic calling convention"))); 848516f54eSJon Chesterfield 858516f54eSJon Chesterfield bool commandLineOverride() { 868516f54eSJon Chesterfield return ExpandVariadicsModeOption != ExpandVariadicsMode::Unspecified; 878516f54eSJon Chesterfield } 888516f54eSJon Chesterfield 898516f54eSJon Chesterfield // Instances of this class encapsulate the target-dependant behaviour as a 908516f54eSJon Chesterfield // function of triple. Implementing a new ABI is adding a case to the switch 918516f54eSJon Chesterfield // in create(llvm::Triple) at the end of this file. 928516f54eSJon Chesterfield // This class may end up instantiated in TargetMachine instances, keeping it 938516f54eSJon Chesterfield // here for now until enough targets are implemented for the API to evolve. 948516f54eSJon Chesterfield class VariadicABIInfo { 958516f54eSJon Chesterfield protected: 968516f54eSJon Chesterfield VariadicABIInfo() = default; 978516f54eSJon Chesterfield 988516f54eSJon Chesterfield public: 998516f54eSJon Chesterfield static std::unique_ptr<VariadicABIInfo> create(const Triple &T); 1008516f54eSJon Chesterfield 1018516f54eSJon Chesterfield // Allow overriding whether the pass runs on a per-target basis 1028516f54eSJon Chesterfield virtual bool enableForTarget() = 0; 1038516f54eSJon Chesterfield 1048516f54eSJon Chesterfield // Whether a valist instance is passed by value or by address 1058516f54eSJon Chesterfield // I.e. does it need to be alloca'ed and stored into, or can 1068516f54eSJon Chesterfield // it be passed directly in a SSA register 1078516f54eSJon Chesterfield virtual bool vaListPassedInSSARegister() = 0; 1088516f54eSJon Chesterfield 1098516f54eSJon Chesterfield // The type of a va_list iterator object 1108516f54eSJon Chesterfield virtual Type *vaListType(LLVMContext &Ctx) = 0; 1118516f54eSJon Chesterfield 1128516f54eSJon Chesterfield // The type of a va_list as a function argument as lowered by C 1138516f54eSJon Chesterfield virtual Type *vaListParameterType(Module &M) = 0; 1148516f54eSJon Chesterfield 1158516f54eSJon Chesterfield // Initialize an allocated va_list object to point to an already 1168516f54eSJon Chesterfield // initialized contiguous memory region. 1178516f54eSJon Chesterfield // Return the value to pass as the va_list argument 1188516f54eSJon Chesterfield virtual Value *initializeVaList(Module &M, LLVMContext &Ctx, 1198516f54eSJon Chesterfield IRBuilder<> &Builder, AllocaInst *VaList, 1208516f54eSJon Chesterfield Value *Buffer) = 0; 1218516f54eSJon Chesterfield 1228516f54eSJon Chesterfield struct VAArgSlotInfo { 1238516f54eSJon Chesterfield Align DataAlign; // With respect to the call frame 1248516f54eSJon Chesterfield bool Indirect; // Passed via a pointer 1258516f54eSJon Chesterfield }; 1268516f54eSJon Chesterfield virtual VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) = 0; 1278516f54eSJon Chesterfield 1288516f54eSJon Chesterfield // Targets implemented so far all have the same trivial lowering for these 1298516f54eSJon Chesterfield bool vaEndIsNop() { return true; } 1308516f54eSJon Chesterfield bool vaCopyIsMemcpy() { return true; } 1318516f54eSJon Chesterfield 1328516f54eSJon Chesterfield virtual ~VariadicABIInfo() = default; 1338516f54eSJon Chesterfield }; 1348516f54eSJon Chesterfield 1358516f54eSJon Chesterfield // Module implements getFunction() which returns nullptr on missing declaration 1368516f54eSJon Chesterfield // and getOrInsertFunction which creates one when absent. Intrinsics.h only 1378516f54eSJon Chesterfield // implements getDeclaration which creates one when missing. Checking whether 1388516f54eSJon Chesterfield // an intrinsic exists thus inserts it in the module and it then needs to be 1398516f54eSJon Chesterfield // deleted again to clean up. 1408516f54eSJon Chesterfield // The right name for the two functions on intrinsics would match Module::, 1418516f54eSJon Chesterfield // but doing that in a single change would introduce nullptr dereferences 1428516f54eSJon Chesterfield // where currently there are none. The minimal collateral damage approach 1438516f54eSJon Chesterfield // would split the change over a release to help downstream branches. As it 1448516f54eSJon Chesterfield // is unclear what approach will be preferred, implementing the trivial 1458516f54eSJon Chesterfield // function here in the meantime to decouple from that discussion. 1468516f54eSJon Chesterfield Function *getPreexistingDeclaration(Module *M, Intrinsic::ID Id, 1478516f54eSJon Chesterfield ArrayRef<Type *> Tys = {}) { 148*6924fc03SRahul Joshi if (Tys.empty()) 149*6924fc03SRahul Joshi return Intrinsic::getDeclarationIfExists(M, Id); 1508516f54eSJon Chesterfield auto *FT = Intrinsic::getType(M->getContext(), Id, Tys); 151*6924fc03SRahul Joshi return Intrinsic::getDeclarationIfExists(M, Id, Tys, FT); 1528516f54eSJon Chesterfield } 1538516f54eSJon Chesterfield 1548516f54eSJon Chesterfield class ExpandVariadics : public ModulePass { 1558516f54eSJon Chesterfield 1568516f54eSJon Chesterfield // The pass construction sets the default to optimize when called from middle 1578516f54eSJon Chesterfield // end and lowering when called from the backend. The command line variable 1588516f54eSJon Chesterfield // overrides that. This is useful for testing and debugging. It also allows 1598516f54eSJon Chesterfield // building an applications with variadic functions wholly removed if one 1608516f54eSJon Chesterfield // has sufficient control over the dependencies, e.g. a statically linked 1618516f54eSJon Chesterfield // clang that has no variadic function calls remaining in the binary. 1628516f54eSJon Chesterfield 1638516f54eSJon Chesterfield public: 1648516f54eSJon Chesterfield static char ID; 1658516f54eSJon Chesterfield const ExpandVariadicsMode Mode; 1668516f54eSJon Chesterfield std::unique_ptr<VariadicABIInfo> ABI; 1678516f54eSJon Chesterfield 1688516f54eSJon Chesterfield ExpandVariadics(ExpandVariadicsMode Mode) 1698516f54eSJon Chesterfield : ModulePass(ID), 1708516f54eSJon Chesterfield Mode(commandLineOverride() ? ExpandVariadicsModeOption : Mode) {} 1718516f54eSJon Chesterfield 1728516f54eSJon Chesterfield StringRef getPassName() const override { return "Expand variadic functions"; } 1738516f54eSJon Chesterfield 1748516f54eSJon Chesterfield bool rewriteABI() { return Mode == ExpandVariadicsMode::Lowering; } 1758516f54eSJon Chesterfield 1768516f54eSJon Chesterfield bool runOnModule(Module &M) override; 1778516f54eSJon Chesterfield 1788516f54eSJon Chesterfield bool runOnFunction(Module &M, IRBuilder<> &Builder, Function *F); 1798516f54eSJon Chesterfield 1808516f54eSJon Chesterfield Function *replaceAllUsesWithNewDeclaration(Module &M, 1818516f54eSJon Chesterfield Function *OriginalFunction); 1828516f54eSJon Chesterfield 1838516f54eSJon Chesterfield Function *deriveFixedArityReplacement(Module &M, IRBuilder<> &Builder, 1848516f54eSJon Chesterfield Function *OriginalFunction); 1858516f54eSJon Chesterfield 1868516f54eSJon Chesterfield Function *defineVariadicWrapper(Module &M, IRBuilder<> &Builder, 1878516f54eSJon Chesterfield Function *VariadicWrapper, 1888516f54eSJon Chesterfield Function *FixedArityReplacement); 1898516f54eSJon Chesterfield 1908516f54eSJon Chesterfield bool expandCall(Module &M, IRBuilder<> &Builder, CallBase *CB, FunctionType *, 1918516f54eSJon Chesterfield Function *NF); 1928516f54eSJon Chesterfield 1938516f54eSJon Chesterfield // The intrinsic functions va_copy and va_end are removed unconditionally. 1948516f54eSJon Chesterfield // They correspond to a memcpy and a no-op on all implemented targets. 1958516f54eSJon Chesterfield // The va_start intrinsic is removed from basic blocks that were not created 1968516f54eSJon Chesterfield // by this pass, some may remain if needed to maintain the external ABI. 1978516f54eSJon Chesterfield 1988516f54eSJon Chesterfield template <Intrinsic::ID ID, typename InstructionType> 1998516f54eSJon Chesterfield bool expandIntrinsicUsers(Module &M, IRBuilder<> &Builder, 2008516f54eSJon Chesterfield PointerType *IntrinsicArgType) { 2018516f54eSJon Chesterfield bool Changed = false; 2028516f54eSJon Chesterfield const DataLayout &DL = M.getDataLayout(); 2038516f54eSJon Chesterfield if (Function *Intrinsic = 2048516f54eSJon Chesterfield getPreexistingDeclaration(&M, ID, {IntrinsicArgType})) { 2058516f54eSJon Chesterfield for (User *U : make_early_inc_range(Intrinsic->users())) 2068516f54eSJon Chesterfield if (auto *I = dyn_cast<InstructionType>(U)) 2078516f54eSJon Chesterfield Changed |= expandVAIntrinsicCall(Builder, DL, I); 2088516f54eSJon Chesterfield 2098516f54eSJon Chesterfield if (Intrinsic->use_empty()) 2108516f54eSJon Chesterfield Intrinsic->eraseFromParent(); 2118516f54eSJon Chesterfield } 2128516f54eSJon Chesterfield return Changed; 2138516f54eSJon Chesterfield } 2148516f54eSJon Chesterfield 2158516f54eSJon Chesterfield bool expandVAIntrinsicUsersWithAddrspace(Module &M, IRBuilder<> &Builder, 2168516f54eSJon Chesterfield unsigned Addrspace) { 2178516f54eSJon Chesterfield auto &Ctx = M.getContext(); 2188516f54eSJon Chesterfield PointerType *IntrinsicArgType = PointerType::get(Ctx, Addrspace); 2198516f54eSJon Chesterfield bool Changed = false; 2208516f54eSJon Chesterfield 2218516f54eSJon Chesterfield // expand vastart before vacopy as vastart may introduce a vacopy 2228516f54eSJon Chesterfield Changed |= expandIntrinsicUsers<Intrinsic::vastart, VAStartInst>( 2238516f54eSJon Chesterfield M, Builder, IntrinsicArgType); 2248516f54eSJon Chesterfield Changed |= expandIntrinsicUsers<Intrinsic::vaend, VAEndInst>( 2258516f54eSJon Chesterfield M, Builder, IntrinsicArgType); 2268516f54eSJon Chesterfield Changed |= expandIntrinsicUsers<Intrinsic::vacopy, VACopyInst>( 2278516f54eSJon Chesterfield M, Builder, IntrinsicArgType); 2288516f54eSJon Chesterfield return Changed; 2298516f54eSJon Chesterfield } 2308516f54eSJon Chesterfield 2318516f54eSJon Chesterfield bool expandVAIntrinsicCall(IRBuilder<> &Builder, const DataLayout &DL, 2328516f54eSJon Chesterfield VAStartInst *Inst); 2338516f54eSJon Chesterfield 2348516f54eSJon Chesterfield bool expandVAIntrinsicCall(IRBuilder<> &, const DataLayout &, 2358516f54eSJon Chesterfield VAEndInst *Inst); 2368516f54eSJon Chesterfield 2378516f54eSJon Chesterfield bool expandVAIntrinsicCall(IRBuilder<> &Builder, const DataLayout &DL, 2388516f54eSJon Chesterfield VACopyInst *Inst); 2398516f54eSJon Chesterfield 2408516f54eSJon Chesterfield FunctionType *inlinableVariadicFunctionType(Module &M, FunctionType *FTy) { 2418516f54eSJon Chesterfield // The type of "FTy" with the ... removed and a va_list appended 24294e6786bSKazu Hirata SmallVector<Type *> ArgTypes(FTy->params()); 2438516f54eSJon Chesterfield ArgTypes.push_back(ABI->vaListParameterType(M)); 2448516f54eSJon Chesterfield return FunctionType::get(FTy->getReturnType(), ArgTypes, 2458516f54eSJon Chesterfield /*IsVarArgs=*/false); 2468516f54eSJon Chesterfield } 2478516f54eSJon Chesterfield 2488516f54eSJon Chesterfield static ConstantInt *sizeOfAlloca(LLVMContext &Ctx, const DataLayout &DL, 2498516f54eSJon Chesterfield AllocaInst *Alloced) { 2508516f54eSJon Chesterfield std::optional<TypeSize> AllocaTypeSize = Alloced->getAllocationSize(DL); 2518516f54eSJon Chesterfield uint64_t AsInt = AllocaTypeSize ? AllocaTypeSize->getFixedValue() : 0; 2528516f54eSJon Chesterfield return ConstantInt::get(Type::getInt64Ty(Ctx), AsInt); 2538516f54eSJon Chesterfield } 2548516f54eSJon Chesterfield 2558516f54eSJon Chesterfield bool expansionApplicableToFunction(Module &M, Function *F) { 2568516f54eSJon Chesterfield if (F->isIntrinsic() || !F->isVarArg() || 2578516f54eSJon Chesterfield F->hasFnAttribute(Attribute::Naked)) 2588516f54eSJon Chesterfield return false; 2598516f54eSJon Chesterfield 2608516f54eSJon Chesterfield if (F->getCallingConv() != CallingConv::C) 2618516f54eSJon Chesterfield return false; 2628516f54eSJon Chesterfield 2638516f54eSJon Chesterfield if (rewriteABI()) 2648516f54eSJon Chesterfield return true; 2658516f54eSJon Chesterfield 2668516f54eSJon Chesterfield if (!F->hasExactDefinition()) 2678516f54eSJon Chesterfield return false; 2688516f54eSJon Chesterfield 2698516f54eSJon Chesterfield return true; 2708516f54eSJon Chesterfield } 2718516f54eSJon Chesterfield 2728516f54eSJon Chesterfield bool expansionApplicableToFunctionCall(CallBase *CB) { 2738516f54eSJon Chesterfield if (CallInst *CI = dyn_cast<CallInst>(CB)) { 2748516f54eSJon Chesterfield if (CI->isMustTailCall()) { 2758516f54eSJon Chesterfield // Cannot expand musttail calls 2768516f54eSJon Chesterfield return false; 2778516f54eSJon Chesterfield } 2788516f54eSJon Chesterfield 2798516f54eSJon Chesterfield if (CI->getCallingConv() != CallingConv::C) 2808516f54eSJon Chesterfield return false; 2818516f54eSJon Chesterfield 2828516f54eSJon Chesterfield return true; 2838516f54eSJon Chesterfield } 2848516f54eSJon Chesterfield 2858516f54eSJon Chesterfield if (isa<InvokeInst>(CB)) { 2868516f54eSJon Chesterfield // Invoke not implemented in initial implementation of pass 2878516f54eSJon Chesterfield return false; 2888516f54eSJon Chesterfield } 2898516f54eSJon Chesterfield 2908516f54eSJon Chesterfield // Other unimplemented derivative of CallBase 2918516f54eSJon Chesterfield return false; 2928516f54eSJon Chesterfield } 2938516f54eSJon Chesterfield 2948516f54eSJon Chesterfield class ExpandedCallFrame { 2958516f54eSJon Chesterfield // Helper for constructing an alloca instance containing the arguments bound 2968516f54eSJon Chesterfield // to the variadic ... parameter, rearranged to allow indexing through a 2978516f54eSJon Chesterfield // va_list iterator 2988516f54eSJon Chesterfield enum { N = 4 }; 2998516f54eSJon Chesterfield SmallVector<Type *, N> FieldTypes; 3008516f54eSJon Chesterfield enum Tag { Store, Memcpy, Padding }; 3018516f54eSJon Chesterfield SmallVector<std::tuple<Value *, uint64_t, Tag>, N> Source; 3028516f54eSJon Chesterfield 3038516f54eSJon Chesterfield template <Tag tag> void append(Type *FieldType, Value *V, uint64_t Bytes) { 3048516f54eSJon Chesterfield FieldTypes.push_back(FieldType); 3058516f54eSJon Chesterfield Source.push_back({V, Bytes, tag}); 3068516f54eSJon Chesterfield } 3078516f54eSJon Chesterfield 3088516f54eSJon Chesterfield public: 3098516f54eSJon Chesterfield void store(LLVMContext &Ctx, Type *T, Value *V) { append<Store>(T, V, 0); } 3108516f54eSJon Chesterfield 3118516f54eSJon Chesterfield void memcpy(LLVMContext &Ctx, Type *T, Value *V, uint64_t Bytes) { 3128516f54eSJon Chesterfield append<Memcpy>(T, V, Bytes); 3138516f54eSJon Chesterfield } 3148516f54eSJon Chesterfield 3158516f54eSJon Chesterfield void padding(LLVMContext &Ctx, uint64_t By) { 3168516f54eSJon Chesterfield append<Padding>(ArrayType::get(Type::getInt8Ty(Ctx), By), nullptr, 0); 3178516f54eSJon Chesterfield } 3188516f54eSJon Chesterfield 3198516f54eSJon Chesterfield size_t size() const { return FieldTypes.size(); } 3208516f54eSJon Chesterfield bool empty() const { return FieldTypes.empty(); } 3218516f54eSJon Chesterfield 3228516f54eSJon Chesterfield StructType *asStruct(LLVMContext &Ctx, StringRef Name) { 3238516f54eSJon Chesterfield const bool IsPacked = true; 3248516f54eSJon Chesterfield return StructType::create(Ctx, FieldTypes, 3258516f54eSJon Chesterfield (Twine(Name) + ".vararg").str(), IsPacked); 3268516f54eSJon Chesterfield } 3278516f54eSJon Chesterfield 3288516f54eSJon Chesterfield void initializeStructAlloca(const DataLayout &DL, IRBuilder<> &Builder, 3298516f54eSJon Chesterfield AllocaInst *Alloced) { 3308516f54eSJon Chesterfield 3318516f54eSJon Chesterfield StructType *VarargsTy = cast<StructType>(Alloced->getAllocatedType()); 3328516f54eSJon Chesterfield 3338516f54eSJon Chesterfield for (size_t I = 0; I < size(); I++) { 3348516f54eSJon Chesterfield 3358516f54eSJon Chesterfield auto [V, bytes, tag] = Source[I]; 3368516f54eSJon Chesterfield 3378516f54eSJon Chesterfield if (tag == Padding) { 3388516f54eSJon Chesterfield assert(V == nullptr); 3398516f54eSJon Chesterfield continue; 3408516f54eSJon Chesterfield } 3418516f54eSJon Chesterfield 3428516f54eSJon Chesterfield auto Dst = Builder.CreateStructGEP(VarargsTy, Alloced, I); 3438516f54eSJon Chesterfield 3448516f54eSJon Chesterfield assert(V != nullptr); 3458516f54eSJon Chesterfield 3468516f54eSJon Chesterfield if (tag == Store) 3478516f54eSJon Chesterfield Builder.CreateStore(V, Dst); 3488516f54eSJon Chesterfield 3498516f54eSJon Chesterfield if (tag == Memcpy) 3508516f54eSJon Chesterfield Builder.CreateMemCpy(Dst, {}, V, {}, bytes); 3518516f54eSJon Chesterfield } 3528516f54eSJon Chesterfield } 3538516f54eSJon Chesterfield }; 3548516f54eSJon Chesterfield }; 3558516f54eSJon Chesterfield 3568516f54eSJon Chesterfield bool ExpandVariadics::runOnModule(Module &M) { 3578516f54eSJon Chesterfield bool Changed = false; 3588516f54eSJon Chesterfield if (Mode == ExpandVariadicsMode::Disable) 3598516f54eSJon Chesterfield return Changed; 3608516f54eSJon Chesterfield 3618516f54eSJon Chesterfield Triple TT(M.getTargetTriple()); 3628516f54eSJon Chesterfield ABI = VariadicABIInfo::create(TT); 3638516f54eSJon Chesterfield if (!ABI) 3648516f54eSJon Chesterfield return Changed; 3658516f54eSJon Chesterfield 3668516f54eSJon Chesterfield if (!ABI->enableForTarget()) 3678516f54eSJon Chesterfield return Changed; 3688516f54eSJon Chesterfield 3698516f54eSJon Chesterfield auto &Ctx = M.getContext(); 3708516f54eSJon Chesterfield const DataLayout &DL = M.getDataLayout(); 3718516f54eSJon Chesterfield IRBuilder<> Builder(Ctx); 3728516f54eSJon Chesterfield 3738516f54eSJon Chesterfield // Lowering needs to run on all functions exactly once. 3748516f54eSJon Chesterfield // Optimize could run on functions containing va_start exactly once. 3758516f54eSJon Chesterfield for (Function &F : make_early_inc_range(M)) 3768516f54eSJon Chesterfield Changed |= runOnFunction(M, Builder, &F); 3778516f54eSJon Chesterfield 3788516f54eSJon Chesterfield // After runOnFunction, all known calls to known variadic functions have been 3798516f54eSJon Chesterfield // replaced. va_start intrinsics are presently (and invalidly!) only present 3808516f54eSJon Chesterfield // in functions that used to be variadic and have now been replaced to take a 3818516f54eSJon Chesterfield // va_list instead. If lowering as opposed to optimising, calls to unknown 3828516f54eSJon Chesterfield // variadic functions have also been replaced. 3838516f54eSJon Chesterfield 3848516f54eSJon Chesterfield { 3858516f54eSJon Chesterfield // 0 and AllocaAddrSpace are sufficient for the targets implemented so far 3868516f54eSJon Chesterfield unsigned Addrspace = 0; 3878516f54eSJon Chesterfield Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace); 3888516f54eSJon Chesterfield 3898516f54eSJon Chesterfield Addrspace = DL.getAllocaAddrSpace(); 3908516f54eSJon Chesterfield if (Addrspace != 0) 3918516f54eSJon Chesterfield Changed |= expandVAIntrinsicUsersWithAddrspace(M, Builder, Addrspace); 3928516f54eSJon Chesterfield } 3938516f54eSJon Chesterfield 3948516f54eSJon Chesterfield if (Mode != ExpandVariadicsMode::Lowering) 3958516f54eSJon Chesterfield return Changed; 3968516f54eSJon Chesterfield 3978516f54eSJon Chesterfield for (Function &F : make_early_inc_range(M)) { 3988516f54eSJon Chesterfield if (F.isDeclaration()) 3998516f54eSJon Chesterfield continue; 4008516f54eSJon Chesterfield 4018516f54eSJon Chesterfield // Now need to track down indirect calls. Can't find those 4028516f54eSJon Chesterfield // by walking uses of variadic functions, need to crawl the instruction 4038516f54eSJon Chesterfield // stream. Fortunately this is only necessary for the ABI rewrite case. 4048516f54eSJon Chesterfield for (BasicBlock &BB : F) { 4058516f54eSJon Chesterfield for (Instruction &I : make_early_inc_range(BB)) { 4068516f54eSJon Chesterfield if (CallBase *CB = dyn_cast<CallBase>(&I)) { 4078516f54eSJon Chesterfield if (CB->isIndirectCall()) { 4088516f54eSJon Chesterfield FunctionType *FTy = CB->getFunctionType(); 4098516f54eSJon Chesterfield if (FTy->isVarArg()) 4108516f54eSJon Chesterfield Changed |= expandCall(M, Builder, CB, FTy, 0); 4118516f54eSJon Chesterfield } 4128516f54eSJon Chesterfield } 4138516f54eSJon Chesterfield } 4148516f54eSJon Chesterfield } 4158516f54eSJon Chesterfield } 4168516f54eSJon Chesterfield 4178516f54eSJon Chesterfield return Changed; 4188516f54eSJon Chesterfield } 4198516f54eSJon Chesterfield 4208516f54eSJon Chesterfield bool ExpandVariadics::runOnFunction(Module &M, IRBuilder<> &Builder, 4218516f54eSJon Chesterfield Function *OriginalFunction) { 4228516f54eSJon Chesterfield bool Changed = false; 4238516f54eSJon Chesterfield 4248516f54eSJon Chesterfield if (!expansionApplicableToFunction(M, OriginalFunction)) 4258516f54eSJon Chesterfield return Changed; 4268516f54eSJon Chesterfield 427b3b9f8ddSJie Fu [[maybe_unused]] const bool OriginalFunctionIsDeclaration = 428b3b9f8ddSJie Fu OriginalFunction->isDeclaration(); 4298516f54eSJon Chesterfield assert(rewriteABI() || !OriginalFunctionIsDeclaration); 4308516f54eSJon Chesterfield 4318516f54eSJon Chesterfield // Declare a new function and redirect every use to that new function 4328516f54eSJon Chesterfield Function *VariadicWrapper = 4338516f54eSJon Chesterfield replaceAllUsesWithNewDeclaration(M, OriginalFunction); 4348516f54eSJon Chesterfield assert(VariadicWrapper->isDeclaration()); 4358516f54eSJon Chesterfield assert(OriginalFunction->use_empty()); 4368516f54eSJon Chesterfield 4378516f54eSJon Chesterfield // Create a new function taking va_list containing the implementation of the 4388516f54eSJon Chesterfield // original 4398516f54eSJon Chesterfield Function *FixedArityReplacement = 4408516f54eSJon Chesterfield deriveFixedArityReplacement(M, Builder, OriginalFunction); 4418516f54eSJon Chesterfield assert(OriginalFunction->isDeclaration()); 4428516f54eSJon Chesterfield assert(FixedArityReplacement->isDeclaration() == 4438516f54eSJon Chesterfield OriginalFunctionIsDeclaration); 4448516f54eSJon Chesterfield assert(VariadicWrapper->isDeclaration()); 4458516f54eSJon Chesterfield 4468516f54eSJon Chesterfield // Create a single block forwarding wrapper that turns a ... into a va_list 447b3b9f8ddSJie Fu [[maybe_unused]] Function *VariadicWrapperDefine = 4488516f54eSJon Chesterfield defineVariadicWrapper(M, Builder, VariadicWrapper, FixedArityReplacement); 4498516f54eSJon Chesterfield assert(VariadicWrapperDefine == VariadicWrapper); 4508516f54eSJon Chesterfield assert(!VariadicWrapper->isDeclaration()); 4518516f54eSJon Chesterfield 4528516f54eSJon Chesterfield // We now have: 4538516f54eSJon Chesterfield // 1. the original function, now as a declaration with no uses 4548516f54eSJon Chesterfield // 2. a variadic function that unconditionally calls a fixed arity replacement 4558516f54eSJon Chesterfield // 3. a fixed arity function equivalent to the original function 4568516f54eSJon Chesterfield 4578516f54eSJon Chesterfield // Replace known calls to the variadic with calls to the va_list equivalent 4588516f54eSJon Chesterfield for (User *U : make_early_inc_range(VariadicWrapper->users())) { 4598516f54eSJon Chesterfield if (CallBase *CB = dyn_cast<CallBase>(U)) { 460486d00ecSJoseph Huber Value *CalledOperand = CB->getCalledOperand(); 461486d00ecSJoseph Huber if (VariadicWrapper == CalledOperand) 4628516f54eSJon Chesterfield Changed |= 4638516f54eSJon Chesterfield expandCall(M, Builder, CB, VariadicWrapper->getFunctionType(), 4648516f54eSJon Chesterfield FixedArityReplacement); 4658516f54eSJon Chesterfield } 4668516f54eSJon Chesterfield } 4678516f54eSJon Chesterfield 4688516f54eSJon Chesterfield // The original function will be erased. 4698516f54eSJon Chesterfield // One of the two new functions will become a replacement for the original. 4708516f54eSJon Chesterfield // When preserving the ABI, the other is an internal implementation detail. 4718516f54eSJon Chesterfield // When rewriting the ABI, RAUW then the variadic one. 4728516f54eSJon Chesterfield Function *const ExternallyAccessible = 4738516f54eSJon Chesterfield rewriteABI() ? FixedArityReplacement : VariadicWrapper; 4748516f54eSJon Chesterfield Function *const InternalOnly = 4758516f54eSJon Chesterfield rewriteABI() ? VariadicWrapper : FixedArityReplacement; 4768516f54eSJon Chesterfield 4778516f54eSJon Chesterfield // The external function is the replacement for the original 4788516f54eSJon Chesterfield ExternallyAccessible->setLinkage(OriginalFunction->getLinkage()); 4798516f54eSJon Chesterfield ExternallyAccessible->setVisibility(OriginalFunction->getVisibility()); 4808516f54eSJon Chesterfield ExternallyAccessible->setComdat(OriginalFunction->getComdat()); 4818516f54eSJon Chesterfield ExternallyAccessible->takeName(OriginalFunction); 4828516f54eSJon Chesterfield 4838516f54eSJon Chesterfield // Annotate the internal one as internal 4848516f54eSJon Chesterfield InternalOnly->setVisibility(GlobalValue::DefaultVisibility); 4858516f54eSJon Chesterfield InternalOnly->setLinkage(GlobalValue::InternalLinkage); 4868516f54eSJon Chesterfield 4878516f54eSJon Chesterfield // The original is unused and obsolete 4888516f54eSJon Chesterfield OriginalFunction->eraseFromParent(); 4898516f54eSJon Chesterfield 4908516f54eSJon Chesterfield InternalOnly->removeDeadConstantUsers(); 4918516f54eSJon Chesterfield 4928516f54eSJon Chesterfield if (rewriteABI()) { 4938516f54eSJon Chesterfield // All known calls to the function have been removed by expandCall 4948516f54eSJon Chesterfield // Resolve everything else by replaceAllUsesWith 4958516f54eSJon Chesterfield VariadicWrapper->replaceAllUsesWith(FixedArityReplacement); 4968516f54eSJon Chesterfield VariadicWrapper->eraseFromParent(); 4978516f54eSJon Chesterfield } 4988516f54eSJon Chesterfield 4998516f54eSJon Chesterfield return Changed; 5008516f54eSJon Chesterfield } 5018516f54eSJon Chesterfield 5028516f54eSJon Chesterfield Function * 5038516f54eSJon Chesterfield ExpandVariadics::replaceAllUsesWithNewDeclaration(Module &M, 5048516f54eSJon Chesterfield Function *OriginalFunction) { 5058516f54eSJon Chesterfield auto &Ctx = M.getContext(); 5068516f54eSJon Chesterfield Function &F = *OriginalFunction; 5078516f54eSJon Chesterfield FunctionType *FTy = F.getFunctionType(); 5088516f54eSJon Chesterfield Function *NF = Function::Create(FTy, F.getLinkage(), F.getAddressSpace()); 5098516f54eSJon Chesterfield 5108516f54eSJon Chesterfield NF->setName(F.getName() + ".varargs"); 5118516f54eSJon Chesterfield NF->IsNewDbgInfoFormat = F.IsNewDbgInfoFormat; 5128516f54eSJon Chesterfield 5138516f54eSJon Chesterfield F.getParent()->getFunctionList().insert(F.getIterator(), NF); 5148516f54eSJon Chesterfield 5158516f54eSJon Chesterfield AttrBuilder ParamAttrs(Ctx); 5168516f54eSJon Chesterfield AttributeList Attrs = NF->getAttributes(); 5178516f54eSJon Chesterfield Attrs = Attrs.addParamAttributes(Ctx, FTy->getNumParams(), ParamAttrs); 5188516f54eSJon Chesterfield NF->setAttributes(Attrs); 5198516f54eSJon Chesterfield 5208516f54eSJon Chesterfield OriginalFunction->replaceAllUsesWith(NF); 5218516f54eSJon Chesterfield return NF; 5228516f54eSJon Chesterfield } 5238516f54eSJon Chesterfield 5248516f54eSJon Chesterfield Function * 5258516f54eSJon Chesterfield ExpandVariadics::deriveFixedArityReplacement(Module &M, IRBuilder<> &Builder, 5268516f54eSJon Chesterfield Function *OriginalFunction) { 5278516f54eSJon Chesterfield Function &F = *OriginalFunction; 5288516f54eSJon Chesterfield // The purpose here is split the variadic function F into two functions 5298516f54eSJon Chesterfield // One is a variadic function that bundles the passed argument into a va_list 5308516f54eSJon Chesterfield // and passes it to the second function. The second function does whatever 5318516f54eSJon Chesterfield // the original F does, except that it takes a va_list instead of the ... 5328516f54eSJon Chesterfield 5338516f54eSJon Chesterfield assert(expansionApplicableToFunction(M, &F)); 5348516f54eSJon Chesterfield 5358516f54eSJon Chesterfield auto &Ctx = M.getContext(); 5368516f54eSJon Chesterfield 5378516f54eSJon Chesterfield // Returned value isDeclaration() is equal to F.isDeclaration() 5388516f54eSJon Chesterfield // but that property is not invariant throughout this function 5398516f54eSJon Chesterfield const bool FunctionIsDefinition = !F.isDeclaration(); 5408516f54eSJon Chesterfield 5418516f54eSJon Chesterfield FunctionType *FTy = F.getFunctionType(); 54294e6786bSKazu Hirata SmallVector<Type *> ArgTypes(FTy->params()); 5438516f54eSJon Chesterfield ArgTypes.push_back(ABI->vaListParameterType(M)); 5448516f54eSJon Chesterfield 5458516f54eSJon Chesterfield FunctionType *NFTy = inlinableVariadicFunctionType(M, FTy); 5468516f54eSJon Chesterfield Function *NF = Function::Create(NFTy, F.getLinkage(), F.getAddressSpace()); 5478516f54eSJon Chesterfield 5488516f54eSJon Chesterfield // Note - same attribute handling as DeadArgumentElimination 5498516f54eSJon Chesterfield NF->copyAttributesFrom(&F); 5508516f54eSJon Chesterfield NF->setComdat(F.getComdat()); 5518516f54eSJon Chesterfield F.getParent()->getFunctionList().insert(F.getIterator(), NF); 5528516f54eSJon Chesterfield NF->setName(F.getName() + ".valist"); 5538516f54eSJon Chesterfield NF->IsNewDbgInfoFormat = F.IsNewDbgInfoFormat; 5548516f54eSJon Chesterfield 5558516f54eSJon Chesterfield AttrBuilder ParamAttrs(Ctx); 5568516f54eSJon Chesterfield 5578516f54eSJon Chesterfield AttributeList Attrs = NF->getAttributes(); 5588516f54eSJon Chesterfield Attrs = Attrs.addParamAttributes(Ctx, NFTy->getNumParams() - 1, ParamAttrs); 5598516f54eSJon Chesterfield NF->setAttributes(Attrs); 5608516f54eSJon Chesterfield 5618516f54eSJon Chesterfield // Splice the implementation into the new function with minimal changes 5628516f54eSJon Chesterfield if (FunctionIsDefinition) { 5638516f54eSJon Chesterfield NF->splice(NF->begin(), &F); 5648516f54eSJon Chesterfield 5658516f54eSJon Chesterfield auto NewArg = NF->arg_begin(); 5668516f54eSJon Chesterfield for (Argument &Arg : F.args()) { 5678516f54eSJon Chesterfield Arg.replaceAllUsesWith(NewArg); 5688516f54eSJon Chesterfield NewArg->setName(Arg.getName()); // takeName without killing the old one 5698516f54eSJon Chesterfield ++NewArg; 5708516f54eSJon Chesterfield } 5718516f54eSJon Chesterfield NewArg->setName("varargs"); 5728516f54eSJon Chesterfield } 5738516f54eSJon Chesterfield 5748516f54eSJon Chesterfield SmallVector<std::pair<unsigned, MDNode *>, 1> MDs; 5758516f54eSJon Chesterfield F.getAllMetadata(MDs); 5768516f54eSJon Chesterfield for (auto [KindID, Node] : MDs) 5778516f54eSJon Chesterfield NF->addMetadata(KindID, *Node); 5788516f54eSJon Chesterfield F.clearMetadata(); 5798516f54eSJon Chesterfield 5808516f54eSJon Chesterfield return NF; 5818516f54eSJon Chesterfield } 5828516f54eSJon Chesterfield 5838516f54eSJon Chesterfield Function * 5848516f54eSJon Chesterfield ExpandVariadics::defineVariadicWrapper(Module &M, IRBuilder<> &Builder, 5858516f54eSJon Chesterfield Function *VariadicWrapper, 5868516f54eSJon Chesterfield Function *FixedArityReplacement) { 5878516f54eSJon Chesterfield auto &Ctx = Builder.getContext(); 5888516f54eSJon Chesterfield const DataLayout &DL = M.getDataLayout(); 5898516f54eSJon Chesterfield assert(VariadicWrapper->isDeclaration()); 5908516f54eSJon Chesterfield Function &F = *VariadicWrapper; 5918516f54eSJon Chesterfield 5928516f54eSJon Chesterfield assert(F.isDeclaration()); 5938516f54eSJon Chesterfield Type *VaListTy = ABI->vaListType(Ctx); 5948516f54eSJon Chesterfield 5958516f54eSJon Chesterfield auto *BB = BasicBlock::Create(Ctx, "entry", &F); 5968516f54eSJon Chesterfield Builder.SetInsertPoint(BB); 5978516f54eSJon Chesterfield 5988516f54eSJon Chesterfield AllocaInst *VaListInstance = 5998516f54eSJon Chesterfield Builder.CreateAlloca(VaListTy, nullptr, "va_start"); 6008516f54eSJon Chesterfield 6018516f54eSJon Chesterfield Builder.CreateLifetimeStart(VaListInstance, 6028516f54eSJon Chesterfield sizeOfAlloca(Ctx, DL, VaListInstance)); 6038516f54eSJon Chesterfield 6048516f54eSJon Chesterfield Builder.CreateIntrinsic(Intrinsic::vastart, {DL.getAllocaPtrType(Ctx)}, 6058516f54eSJon Chesterfield {VaListInstance}); 6068516f54eSJon Chesterfield 6078516f54eSJon Chesterfield SmallVector<Value *> Args; 6088516f54eSJon Chesterfield for (Argument &A : F.args()) 6098516f54eSJon Chesterfield Args.push_back(&A); 6108516f54eSJon Chesterfield 6118516f54eSJon Chesterfield Type *ParameterType = ABI->vaListParameterType(M); 6128516f54eSJon Chesterfield if (ABI->vaListPassedInSSARegister()) 6138516f54eSJon Chesterfield Args.push_back(Builder.CreateLoad(ParameterType, VaListInstance)); 6148516f54eSJon Chesterfield else 6158516f54eSJon Chesterfield Args.push_back(Builder.CreateAddrSpaceCast(VaListInstance, ParameterType)); 6168516f54eSJon Chesterfield 6178516f54eSJon Chesterfield CallInst *Result = Builder.CreateCall(FixedArityReplacement, Args); 6188516f54eSJon Chesterfield 6198516f54eSJon Chesterfield Builder.CreateIntrinsic(Intrinsic::vaend, {DL.getAllocaPtrType(Ctx)}, 6208516f54eSJon Chesterfield {VaListInstance}); 6218516f54eSJon Chesterfield Builder.CreateLifetimeEnd(VaListInstance, 6228516f54eSJon Chesterfield sizeOfAlloca(Ctx, DL, VaListInstance)); 6238516f54eSJon Chesterfield 6248516f54eSJon Chesterfield if (Result->getType()->isVoidTy()) 6258516f54eSJon Chesterfield Builder.CreateRetVoid(); 6268516f54eSJon Chesterfield else 6278516f54eSJon Chesterfield Builder.CreateRet(Result); 6288516f54eSJon Chesterfield 6298516f54eSJon Chesterfield return VariadicWrapper; 6308516f54eSJon Chesterfield } 6318516f54eSJon Chesterfield 6328516f54eSJon Chesterfield bool ExpandVariadics::expandCall(Module &M, IRBuilder<> &Builder, CallBase *CB, 6338516f54eSJon Chesterfield FunctionType *VarargFunctionType, 6348516f54eSJon Chesterfield Function *NF) { 6358516f54eSJon Chesterfield bool Changed = false; 6368516f54eSJon Chesterfield const DataLayout &DL = M.getDataLayout(); 6378516f54eSJon Chesterfield 6388516f54eSJon Chesterfield if (!expansionApplicableToFunctionCall(CB)) { 6398516f54eSJon Chesterfield if (rewriteABI()) 6408516f54eSJon Chesterfield report_fatal_error("Cannot lower callbase instruction"); 6418516f54eSJon Chesterfield return Changed; 6428516f54eSJon Chesterfield } 6438516f54eSJon Chesterfield 6448516f54eSJon Chesterfield // This is tricky. The call instruction's function type might not match 6458516f54eSJon Chesterfield // the type of the caller. When optimising, can leave it unchanged. 6468516f54eSJon Chesterfield // Webassembly detects that inconsistency and repairs it. 6478516f54eSJon Chesterfield FunctionType *FuncType = CB->getFunctionType(); 6488516f54eSJon Chesterfield if (FuncType != VarargFunctionType) { 6498516f54eSJon Chesterfield if (!rewriteABI()) 6508516f54eSJon Chesterfield return Changed; 6518516f54eSJon Chesterfield FuncType = VarargFunctionType; 6528516f54eSJon Chesterfield } 6538516f54eSJon Chesterfield 6548516f54eSJon Chesterfield auto &Ctx = CB->getContext(); 6558516f54eSJon Chesterfield 6568516f54eSJon Chesterfield Align MaxFieldAlign(1); 6578516f54eSJon Chesterfield 6588516f54eSJon Chesterfield // The strategy is to allocate a call frame containing the variadic 6598516f54eSJon Chesterfield // arguments laid out such that a target specific va_list can be initialized 6608516f54eSJon Chesterfield // with it, such that target specific va_arg instructions will correctly 6618516f54eSJon Chesterfield // iterate over it. This means getting the alignment right and sometimes 6628516f54eSJon Chesterfield // embedding a pointer to the value instead of embedding the value itself. 6638516f54eSJon Chesterfield 6648516f54eSJon Chesterfield Function *CBF = CB->getParent()->getParent(); 6658516f54eSJon Chesterfield 6668516f54eSJon Chesterfield ExpandedCallFrame Frame; 6678516f54eSJon Chesterfield 6688516f54eSJon Chesterfield uint64_t CurrentOffset = 0; 6698516f54eSJon Chesterfield 6708516f54eSJon Chesterfield for (unsigned I = FuncType->getNumParams(), E = CB->arg_size(); I < E; ++I) { 6718516f54eSJon Chesterfield Value *ArgVal = CB->getArgOperand(I); 6728516f54eSJon Chesterfield const bool IsByVal = CB->paramHasAttr(I, Attribute::ByVal); 6738516f54eSJon Chesterfield const bool IsByRef = CB->paramHasAttr(I, Attribute::ByRef); 6748516f54eSJon Chesterfield 6758516f54eSJon Chesterfield // The type of the value being passed, decoded from byval/byref metadata if 6768516f54eSJon Chesterfield // required 6778516f54eSJon Chesterfield Type *const UnderlyingType = IsByVal ? CB->getParamByValType(I) 6788516f54eSJon Chesterfield : IsByRef ? CB->getParamByRefType(I) 6798516f54eSJon Chesterfield : ArgVal->getType(); 6808516f54eSJon Chesterfield const uint64_t UnderlyingSize = 6818516f54eSJon Chesterfield DL.getTypeAllocSize(UnderlyingType).getFixedValue(); 6828516f54eSJon Chesterfield 6838516f54eSJon Chesterfield // The type to be written into the call frame 6848516f54eSJon Chesterfield Type *FrameFieldType = UnderlyingType; 6858516f54eSJon Chesterfield 6868516f54eSJon Chesterfield // The value to copy from when initialising the frame alloca 6878516f54eSJon Chesterfield Value *SourceValue = ArgVal; 6888516f54eSJon Chesterfield 6898516f54eSJon Chesterfield VariadicABIInfo::VAArgSlotInfo SlotInfo = ABI->slotInfo(DL, UnderlyingType); 6908516f54eSJon Chesterfield 6918516f54eSJon Chesterfield if (SlotInfo.Indirect) { 6928516f54eSJon Chesterfield // The va_arg lowering loads through a pointer. Set up an alloca to aim 6938516f54eSJon Chesterfield // that pointer at. 6948516f54eSJon Chesterfield Builder.SetInsertPointPastAllocas(CBF); 6958516f54eSJon Chesterfield Builder.SetCurrentDebugLocation(CB->getStableDebugLoc()); 6968516f54eSJon Chesterfield Value *CallerCopy = 6978516f54eSJon Chesterfield Builder.CreateAlloca(UnderlyingType, nullptr, "IndirectAlloca"); 6988516f54eSJon Chesterfield 6998516f54eSJon Chesterfield Builder.SetInsertPoint(CB); 7008516f54eSJon Chesterfield if (IsByVal) 7018516f54eSJon Chesterfield Builder.CreateMemCpy(CallerCopy, {}, ArgVal, {}, UnderlyingSize); 7028516f54eSJon Chesterfield else 7038516f54eSJon Chesterfield Builder.CreateStore(ArgVal, CallerCopy); 7048516f54eSJon Chesterfield 7058516f54eSJon Chesterfield // Indirection now handled, pass the alloca ptr by value 7068516f54eSJon Chesterfield FrameFieldType = DL.getAllocaPtrType(Ctx); 7078516f54eSJon Chesterfield SourceValue = CallerCopy; 7088516f54eSJon Chesterfield } 7098516f54eSJon Chesterfield 7108516f54eSJon Chesterfield // Alignment of the value within the frame 7118516f54eSJon Chesterfield // This probably needs to be controllable as a function of type 7128516f54eSJon Chesterfield Align DataAlign = SlotInfo.DataAlign; 7138516f54eSJon Chesterfield 7148516f54eSJon Chesterfield MaxFieldAlign = std::max(MaxFieldAlign, DataAlign); 7158516f54eSJon Chesterfield 7168516f54eSJon Chesterfield uint64_t DataAlignV = DataAlign.value(); 7178516f54eSJon Chesterfield if (uint64_t Rem = CurrentOffset % DataAlignV) { 7188516f54eSJon Chesterfield // Inject explicit padding to deal with alignment requirements 7198516f54eSJon Chesterfield uint64_t Padding = DataAlignV - Rem; 7208516f54eSJon Chesterfield Frame.padding(Ctx, Padding); 7218516f54eSJon Chesterfield CurrentOffset += Padding; 7228516f54eSJon Chesterfield } 7238516f54eSJon Chesterfield 7248516f54eSJon Chesterfield if (SlotInfo.Indirect) { 7258516f54eSJon Chesterfield Frame.store(Ctx, FrameFieldType, SourceValue); 7268516f54eSJon Chesterfield } else { 7278516f54eSJon Chesterfield if (IsByVal) 7288516f54eSJon Chesterfield Frame.memcpy(Ctx, FrameFieldType, SourceValue, UnderlyingSize); 7298516f54eSJon Chesterfield else 7308516f54eSJon Chesterfield Frame.store(Ctx, FrameFieldType, SourceValue); 7318516f54eSJon Chesterfield } 7328516f54eSJon Chesterfield 7338516f54eSJon Chesterfield CurrentOffset += DL.getTypeAllocSize(FrameFieldType).getFixedValue(); 7348516f54eSJon Chesterfield } 7358516f54eSJon Chesterfield 7368516f54eSJon Chesterfield if (Frame.empty()) { 7378516f54eSJon Chesterfield // Not passing any arguments, hopefully va_arg won't try to read any 7388516f54eSJon Chesterfield // Creating a single byte frame containing nothing to point the va_list 7398516f54eSJon Chesterfield // instance as that is less special-casey in the compiler and probably 7408516f54eSJon Chesterfield // easier to interpret in a debugger. 7418516f54eSJon Chesterfield Frame.padding(Ctx, 1); 7428516f54eSJon Chesterfield } 7438516f54eSJon Chesterfield 7448516f54eSJon Chesterfield StructType *VarargsTy = Frame.asStruct(Ctx, CBF->getName()); 7458516f54eSJon Chesterfield 7468516f54eSJon Chesterfield // The struct instance needs to be at least MaxFieldAlign for the alignment of 7478516f54eSJon Chesterfield // the fields to be correct at runtime. Use the native stack alignment instead 7488516f54eSJon Chesterfield // if that's greater as that tends to give better codegen. 7498516f54eSJon Chesterfield // This is an awkward way to guess whether there is a known stack alignment 7508516f54eSJon Chesterfield // without hitting an assert in DL.getStackAlignment, 1024 is an arbitrary 7518516f54eSJon Chesterfield // number likely to be greater than the natural stack alignment. 7528516f54eSJon Chesterfield Align AllocaAlign = MaxFieldAlign; 7534d7a0abaSSergei Barannikov if (MaybeAlign StackAlign = DL.getStackAlignment(); 7544d7a0abaSSergei Barannikov StackAlign && *StackAlign > AllocaAlign) 7554d7a0abaSSergei Barannikov AllocaAlign = *StackAlign; 7568516f54eSJon Chesterfield 7578516f54eSJon Chesterfield // Put the alloca to hold the variadic args in the entry basic block. 7588516f54eSJon Chesterfield Builder.SetInsertPointPastAllocas(CBF); 7598516f54eSJon Chesterfield 7608516f54eSJon Chesterfield // SetCurrentDebugLocation when the builder SetInsertPoint method does not 7618516f54eSJon Chesterfield Builder.SetCurrentDebugLocation(CB->getStableDebugLoc()); 7628516f54eSJon Chesterfield 7638516f54eSJon Chesterfield // The awkward construction here is to set the alignment on the instance 7648516f54eSJon Chesterfield AllocaInst *Alloced = Builder.Insert( 7658516f54eSJon Chesterfield new AllocaInst(VarargsTy, DL.getAllocaAddrSpace(), nullptr, AllocaAlign), 7668516f54eSJon Chesterfield "vararg_buffer"); 7678516f54eSJon Chesterfield Changed = true; 7688516f54eSJon Chesterfield assert(Alloced->getAllocatedType() == VarargsTy); 7698516f54eSJon Chesterfield 7708516f54eSJon Chesterfield // Initialize the fields in the struct 7718516f54eSJon Chesterfield Builder.SetInsertPoint(CB); 7728516f54eSJon Chesterfield Builder.CreateLifetimeStart(Alloced, sizeOfAlloca(Ctx, DL, Alloced)); 7738516f54eSJon Chesterfield Frame.initializeStructAlloca(DL, Builder, Alloced); 7748516f54eSJon Chesterfield 7758516f54eSJon Chesterfield const unsigned NumArgs = FuncType->getNumParams(); 7768516f54eSJon Chesterfield SmallVector<Value *> Args(CB->arg_begin(), CB->arg_begin() + NumArgs); 7778516f54eSJon Chesterfield 7788516f54eSJon Chesterfield // Initialize a va_list pointing to that struct and pass it as the last 7798516f54eSJon Chesterfield // argument 7808516f54eSJon Chesterfield AllocaInst *VaList = nullptr; 7818516f54eSJon Chesterfield { 7828516f54eSJon Chesterfield if (!ABI->vaListPassedInSSARegister()) { 7838516f54eSJon Chesterfield Type *VaListTy = ABI->vaListType(Ctx); 7848516f54eSJon Chesterfield Builder.SetInsertPointPastAllocas(CBF); 7858516f54eSJon Chesterfield Builder.SetCurrentDebugLocation(CB->getStableDebugLoc()); 7868516f54eSJon Chesterfield VaList = Builder.CreateAlloca(VaListTy, nullptr, "va_argument"); 7878516f54eSJon Chesterfield Builder.SetInsertPoint(CB); 7888516f54eSJon Chesterfield Builder.CreateLifetimeStart(VaList, sizeOfAlloca(Ctx, DL, VaList)); 7898516f54eSJon Chesterfield } 7908516f54eSJon Chesterfield Builder.SetInsertPoint(CB); 7918516f54eSJon Chesterfield Args.push_back(ABI->initializeVaList(M, Ctx, Builder, VaList, Alloced)); 7928516f54eSJon Chesterfield } 7938516f54eSJon Chesterfield 7948516f54eSJon Chesterfield // Attributes excluding any on the vararg arguments 7958516f54eSJon Chesterfield AttributeList PAL = CB->getAttributes(); 7968516f54eSJon Chesterfield if (!PAL.isEmpty()) { 7978516f54eSJon Chesterfield SmallVector<AttributeSet, 8> ArgAttrs; 7988516f54eSJon Chesterfield for (unsigned ArgNo = 0; ArgNo < NumArgs; ArgNo++) 7998516f54eSJon Chesterfield ArgAttrs.push_back(PAL.getParamAttrs(ArgNo)); 8008516f54eSJon Chesterfield PAL = 8018516f54eSJon Chesterfield AttributeList::get(Ctx, PAL.getFnAttrs(), PAL.getRetAttrs(), ArgAttrs); 8028516f54eSJon Chesterfield } 8038516f54eSJon Chesterfield 8048516f54eSJon Chesterfield SmallVector<OperandBundleDef, 1> OpBundles; 8058516f54eSJon Chesterfield CB->getOperandBundlesAsDefs(OpBundles); 8068516f54eSJon Chesterfield 8078516f54eSJon Chesterfield CallBase *NewCB = nullptr; 8088516f54eSJon Chesterfield 8098516f54eSJon Chesterfield if (CallInst *CI = dyn_cast<CallInst>(CB)) { 8108516f54eSJon Chesterfield Value *Dst = NF ? NF : CI->getCalledOperand(); 8118516f54eSJon Chesterfield FunctionType *NFTy = inlinableVariadicFunctionType(M, VarargFunctionType); 8128516f54eSJon Chesterfield 813fd7d7882SJeremy Morse NewCB = CallInst::Create(NFTy, Dst, Args, OpBundles, "", CI->getIterator()); 8148516f54eSJon Chesterfield 8158516f54eSJon Chesterfield CallInst::TailCallKind TCK = CI->getTailCallKind(); 8168516f54eSJon Chesterfield assert(TCK != CallInst::TCK_MustTail); 8178516f54eSJon Chesterfield 8188516f54eSJon Chesterfield // Can't tail call a function that is being passed a pointer to an alloca 8198516f54eSJon Chesterfield if (TCK == CallInst::TCK_Tail) 8208516f54eSJon Chesterfield TCK = CallInst::TCK_None; 8218516f54eSJon Chesterfield CI->setTailCallKind(TCK); 8228516f54eSJon Chesterfield 8238516f54eSJon Chesterfield } else { 8248516f54eSJon Chesterfield llvm_unreachable("Unreachable when !expansionApplicableToFunctionCall()"); 8258516f54eSJon Chesterfield } 8268516f54eSJon Chesterfield 8278516f54eSJon Chesterfield if (VaList) 8288516f54eSJon Chesterfield Builder.CreateLifetimeEnd(VaList, sizeOfAlloca(Ctx, DL, VaList)); 8298516f54eSJon Chesterfield 8308516f54eSJon Chesterfield Builder.CreateLifetimeEnd(Alloced, sizeOfAlloca(Ctx, DL, Alloced)); 8318516f54eSJon Chesterfield 8328516f54eSJon Chesterfield NewCB->setAttributes(PAL); 8338516f54eSJon Chesterfield NewCB->takeName(CB); 8348516f54eSJon Chesterfield NewCB->setCallingConv(CB->getCallingConv()); 8358516f54eSJon Chesterfield NewCB->setDebugLoc(DebugLoc()); 8368516f54eSJon Chesterfield 8378516f54eSJon Chesterfield // DeadArgElim and ArgPromotion copy exactly this metadata 8388516f54eSJon Chesterfield NewCB->copyMetadata(*CB, {LLVMContext::MD_prof, LLVMContext::MD_dbg}); 8398516f54eSJon Chesterfield 8408516f54eSJon Chesterfield CB->replaceAllUsesWith(NewCB); 8418516f54eSJon Chesterfield CB->eraseFromParent(); 8428516f54eSJon Chesterfield return Changed; 8438516f54eSJon Chesterfield } 8448516f54eSJon Chesterfield 8458516f54eSJon Chesterfield bool ExpandVariadics::expandVAIntrinsicCall(IRBuilder<> &Builder, 8468516f54eSJon Chesterfield const DataLayout &DL, 8478516f54eSJon Chesterfield VAStartInst *Inst) { 8488516f54eSJon Chesterfield // Only removing va_start instructions that are not in variadic functions. 8498516f54eSJon Chesterfield // Those would be rejected by the IR verifier before this pass. 8508516f54eSJon Chesterfield // After splicing basic blocks from a variadic function into a fixed arity 8518516f54eSJon Chesterfield // one the va_start that used to refer to the ... parameter still exist. 8528516f54eSJon Chesterfield // There are also variadic functions that this pass did not change and 8538516f54eSJon Chesterfield // va_start instances in the created single block wrapper functions. 8548516f54eSJon Chesterfield // Replace exactly the instances in non-variadic functions as those are 8558516f54eSJon Chesterfield // the ones to be fixed up to use the va_list passed as the final argument. 8568516f54eSJon Chesterfield 8578516f54eSJon Chesterfield Function *ContainingFunction = Inst->getFunction(); 8588516f54eSJon Chesterfield if (ContainingFunction->isVarArg()) { 8598516f54eSJon Chesterfield return false; 8608516f54eSJon Chesterfield } 8618516f54eSJon Chesterfield 8628516f54eSJon Chesterfield // The last argument is a vaListParameterType, either a va_list 8638516f54eSJon Chesterfield // or a pointer to one depending on the target. 8648516f54eSJon Chesterfield bool PassedByValue = ABI->vaListPassedInSSARegister(); 8658516f54eSJon Chesterfield Argument *PassedVaList = 8668516f54eSJon Chesterfield ContainingFunction->getArg(ContainingFunction->arg_size() - 1); 8678516f54eSJon Chesterfield 8688516f54eSJon Chesterfield // va_start takes a pointer to a va_list, e.g. one on the stack 8698516f54eSJon Chesterfield Value *VaStartArg = Inst->getArgList(); 8708516f54eSJon Chesterfield 8718516f54eSJon Chesterfield Builder.SetInsertPoint(Inst); 8728516f54eSJon Chesterfield 8738516f54eSJon Chesterfield if (PassedByValue) { 8748516f54eSJon Chesterfield // The general thing to do is create an alloca, store the va_list argument 8758516f54eSJon Chesterfield // to it, then create a va_copy. When vaCopyIsMemcpy(), this optimises to a 8768516f54eSJon Chesterfield // store to the VaStartArg. 8778516f54eSJon Chesterfield assert(ABI->vaCopyIsMemcpy()); 8788516f54eSJon Chesterfield Builder.CreateStore(PassedVaList, VaStartArg); 8798516f54eSJon Chesterfield } else { 8808516f54eSJon Chesterfield 8818516f54eSJon Chesterfield // Otherwise emit a vacopy to pick up target-specific handling if any 8828516f54eSJon Chesterfield auto &Ctx = Builder.getContext(); 8838516f54eSJon Chesterfield 8848516f54eSJon Chesterfield Builder.CreateIntrinsic(Intrinsic::vacopy, {DL.getAllocaPtrType(Ctx)}, 8858516f54eSJon Chesterfield {VaStartArg, PassedVaList}); 8868516f54eSJon Chesterfield } 8878516f54eSJon Chesterfield 8888516f54eSJon Chesterfield Inst->eraseFromParent(); 8898516f54eSJon Chesterfield return true; 8908516f54eSJon Chesterfield } 8918516f54eSJon Chesterfield 8928516f54eSJon Chesterfield bool ExpandVariadics::expandVAIntrinsicCall(IRBuilder<> &, const DataLayout &, 8938516f54eSJon Chesterfield VAEndInst *Inst) { 8948516f54eSJon Chesterfield assert(ABI->vaEndIsNop()); 8958516f54eSJon Chesterfield Inst->eraseFromParent(); 8968516f54eSJon Chesterfield return true; 8978516f54eSJon Chesterfield } 8988516f54eSJon Chesterfield 8998516f54eSJon Chesterfield bool ExpandVariadics::expandVAIntrinsicCall(IRBuilder<> &Builder, 9008516f54eSJon Chesterfield const DataLayout &DL, 9018516f54eSJon Chesterfield VACopyInst *Inst) { 9028516f54eSJon Chesterfield assert(ABI->vaCopyIsMemcpy()); 9038516f54eSJon Chesterfield Builder.SetInsertPoint(Inst); 9048516f54eSJon Chesterfield 9058516f54eSJon Chesterfield auto &Ctx = Builder.getContext(); 9068516f54eSJon Chesterfield Type *VaListTy = ABI->vaListType(Ctx); 9078516f54eSJon Chesterfield uint64_t Size = DL.getTypeAllocSize(VaListTy).getFixedValue(); 9088516f54eSJon Chesterfield 9098516f54eSJon Chesterfield Builder.CreateMemCpy(Inst->getDest(), {}, Inst->getSrc(), {}, 9108516f54eSJon Chesterfield Builder.getInt32(Size)); 9118516f54eSJon Chesterfield 9128516f54eSJon Chesterfield Inst->eraseFromParent(); 9138516f54eSJon Chesterfield return true; 9148516f54eSJon Chesterfield } 9158516f54eSJon Chesterfield 9168516f54eSJon Chesterfield struct Amdgpu final : public VariadicABIInfo { 9178516f54eSJon Chesterfield 9188516f54eSJon Chesterfield bool enableForTarget() override { return true; } 9198516f54eSJon Chesterfield 9208516f54eSJon Chesterfield bool vaListPassedInSSARegister() override { return true; } 9218516f54eSJon Chesterfield 9228516f54eSJon Chesterfield Type *vaListType(LLVMContext &Ctx) override { 9238516f54eSJon Chesterfield return PointerType::getUnqual(Ctx); 9248516f54eSJon Chesterfield } 9258516f54eSJon Chesterfield 9268516f54eSJon Chesterfield Type *vaListParameterType(Module &M) override { 9278516f54eSJon Chesterfield return PointerType::getUnqual(M.getContext()); 9288516f54eSJon Chesterfield } 9298516f54eSJon Chesterfield 9308516f54eSJon Chesterfield Value *initializeVaList(Module &M, LLVMContext &Ctx, IRBuilder<> &Builder, 9318516f54eSJon Chesterfield AllocaInst * /*va_list*/, Value *Buffer) override { 9328516f54eSJon Chesterfield // Given Buffer, which is an AllocInst of vararg_buffer 9338516f54eSJon Chesterfield // need to return something usable as parameter type 9348516f54eSJon Chesterfield return Builder.CreateAddrSpaceCast(Buffer, vaListParameterType(M)); 9358516f54eSJon Chesterfield } 9368516f54eSJon Chesterfield 9378516f54eSJon Chesterfield VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) override { 9388516f54eSJon Chesterfield return {Align(4), false}; 9398516f54eSJon Chesterfield } 9408516f54eSJon Chesterfield }; 9418516f54eSJon Chesterfield 942486d00ecSJoseph Huber struct NVPTX final : public VariadicABIInfo { 943486d00ecSJoseph Huber 944486d00ecSJoseph Huber bool enableForTarget() override { return true; } 945486d00ecSJoseph Huber 946486d00ecSJoseph Huber bool vaListPassedInSSARegister() override { return true; } 947486d00ecSJoseph Huber 948486d00ecSJoseph Huber Type *vaListType(LLVMContext &Ctx) override { 949486d00ecSJoseph Huber return PointerType::getUnqual(Ctx); 950486d00ecSJoseph Huber } 951486d00ecSJoseph Huber 952486d00ecSJoseph Huber Type *vaListParameterType(Module &M) override { 953486d00ecSJoseph Huber return PointerType::getUnqual(M.getContext()); 954486d00ecSJoseph Huber } 955486d00ecSJoseph Huber 956486d00ecSJoseph Huber Value *initializeVaList(Module &M, LLVMContext &Ctx, IRBuilder<> &Builder, 957486d00ecSJoseph Huber AllocaInst *, Value *Buffer) override { 958486d00ecSJoseph Huber return Builder.CreateAddrSpaceCast(Buffer, vaListParameterType(M)); 959486d00ecSJoseph Huber } 960486d00ecSJoseph Huber 961486d00ecSJoseph Huber VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) override { 962486d00ecSJoseph Huber // NVPTX expects natural alignment in all cases. The variadic call ABI will 963486d00ecSJoseph Huber // handle promoting types to their appropriate size and alignment. 964486d00ecSJoseph Huber Align A = DL.getABITypeAlign(Parameter); 965486d00ecSJoseph Huber return {A, false}; 966486d00ecSJoseph Huber } 967486d00ecSJoseph Huber }; 968486d00ecSJoseph Huber 9698516f54eSJon Chesterfield struct Wasm final : public VariadicABIInfo { 9708516f54eSJon Chesterfield 9718516f54eSJon Chesterfield bool enableForTarget() override { 9728516f54eSJon Chesterfield // Currently wasm is only used for testing. 9738516f54eSJon Chesterfield return commandLineOverride(); 9748516f54eSJon Chesterfield } 9758516f54eSJon Chesterfield 9768516f54eSJon Chesterfield bool vaListPassedInSSARegister() override { return true; } 9778516f54eSJon Chesterfield 9788516f54eSJon Chesterfield Type *vaListType(LLVMContext &Ctx) override { 9798516f54eSJon Chesterfield return PointerType::getUnqual(Ctx); 9808516f54eSJon Chesterfield } 9818516f54eSJon Chesterfield 9828516f54eSJon Chesterfield Type *vaListParameterType(Module &M) override { 9838516f54eSJon Chesterfield return PointerType::getUnqual(M.getContext()); 9848516f54eSJon Chesterfield } 9858516f54eSJon Chesterfield 9868516f54eSJon Chesterfield Value *initializeVaList(Module &M, LLVMContext &Ctx, IRBuilder<> &Builder, 9878516f54eSJon Chesterfield AllocaInst * /*va_list*/, Value *Buffer) override { 9888516f54eSJon Chesterfield return Buffer; 9898516f54eSJon Chesterfield } 9908516f54eSJon Chesterfield 9918516f54eSJon Chesterfield VAArgSlotInfo slotInfo(const DataLayout &DL, Type *Parameter) override { 9928516f54eSJon Chesterfield LLVMContext &Ctx = Parameter->getContext(); 9938516f54eSJon Chesterfield const unsigned MinAlign = 4; 9948516f54eSJon Chesterfield Align A = DL.getABITypeAlign(Parameter); 9958516f54eSJon Chesterfield if (A < MinAlign) 9968516f54eSJon Chesterfield A = Align(MinAlign); 9978516f54eSJon Chesterfield 998486d00ecSJoseph Huber if (auto *S = dyn_cast<StructType>(Parameter)) { 999486d00ecSJoseph Huber if (S->getNumElements() > 1) { 10008516f54eSJon Chesterfield return {DL.getABITypeAlign(PointerType::getUnqual(Ctx)), true}; 10018516f54eSJon Chesterfield } 10028516f54eSJon Chesterfield } 10038516f54eSJon Chesterfield 10048516f54eSJon Chesterfield return {A, false}; 10058516f54eSJon Chesterfield } 10068516f54eSJon Chesterfield }; 10078516f54eSJon Chesterfield 10088516f54eSJon Chesterfield std::unique_ptr<VariadicABIInfo> VariadicABIInfo::create(const Triple &T) { 10098516f54eSJon Chesterfield switch (T.getArch()) { 10108516f54eSJon Chesterfield case Triple::r600: 10118516f54eSJon Chesterfield case Triple::amdgcn: { 10128516f54eSJon Chesterfield return std::make_unique<Amdgpu>(); 10138516f54eSJon Chesterfield } 10148516f54eSJon Chesterfield 10158516f54eSJon Chesterfield case Triple::wasm32: { 10168516f54eSJon Chesterfield return std::make_unique<Wasm>(); 10178516f54eSJon Chesterfield } 10188516f54eSJon Chesterfield 1019486d00ecSJoseph Huber case Triple::nvptx: 1020486d00ecSJoseph Huber case Triple::nvptx64: { 1021486d00ecSJoseph Huber return std::make_unique<NVPTX>(); 1022486d00ecSJoseph Huber } 1023486d00ecSJoseph Huber 10248516f54eSJon Chesterfield default: 10258516f54eSJon Chesterfield return {}; 10268516f54eSJon Chesterfield } 10278516f54eSJon Chesterfield } 10288516f54eSJon Chesterfield 10298516f54eSJon Chesterfield } // namespace 10308516f54eSJon Chesterfield 10318516f54eSJon Chesterfield char ExpandVariadics::ID = 0; 10328516f54eSJon Chesterfield 10338516f54eSJon Chesterfield INITIALIZE_PASS(ExpandVariadics, DEBUG_TYPE, "Expand variadic functions", false, 10348516f54eSJon Chesterfield false) 10358516f54eSJon Chesterfield 10368516f54eSJon Chesterfield ModulePass *llvm::createExpandVariadicsPass(ExpandVariadicsMode M) { 10378516f54eSJon Chesterfield return new ExpandVariadics(M); 10388516f54eSJon Chesterfield } 10398516f54eSJon Chesterfield 10408516f54eSJon Chesterfield PreservedAnalyses ExpandVariadicsPass::run(Module &M, ModuleAnalysisManager &) { 10418516f54eSJon Chesterfield return ExpandVariadics(Mode).runOnModule(M) ? PreservedAnalyses::none() 10428516f54eSJon Chesterfield : PreservedAnalyses::all(); 10438516f54eSJon Chesterfield } 10448516f54eSJon Chesterfield 10458516f54eSJon Chesterfield ExpandVariadicsPass::ExpandVariadicsPass(ExpandVariadicsMode M) : Mode(M) {} 1046