xref: /llvm-project/llvm/lib/Transforms/IPO/ExpandVariadics.cpp (revision 6924fc03260370876f7091ba06cdc350989ac3c5)
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