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