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