# The future of the va_arg instruction
LLVM IR currently defines a va_arg instruction, which can be used to access
a vararg. Few Clang targets make use of it, and it has a number of
limitations. This RFC hopes to promote discussion on its future - how 'smart'
should va_arg be? Should we be aiming to transition all targets and LLVM
frontends to using it?
## Background on va_arg
The va_arg instruction is described in the language reference here
<http://llvm.org/docs/LangRef.html#int-varargs> and here
<http://llvm.org/docs/LangRef.html#i-va-arg>\. When it's possible to use
va_arg, it frees the frontend from worrying about manipulation of the
target-specific va_list struct. This also has the potential to make analysis
of the IR more straight-forward. However, va_arg can't currently be used
with an aggregate type (such as a struct). The difficulty of adding support
for aggregates is discussed later in this email.
Which Clang targets generate va_arg?
* PNaCl always uses va_arg, even for aggregates. Their ExpandVarArgs pass
replaces it with appropriate loads and stors.
* AArch64/Darwin generates va_arg if possible. When not possible, as for
aggregates or illegal vector types, it generates the usual va_list
manipulation code. It is not used for other AARch64 platforms.
* A few other targets such as MSP430, Lanai and AVR seem to use it due to
Which in-tree backends support va_arg?
* AArch64, ARM, Hexagon, Lanai, MSP430, Mips, PPC, Sparc, WebAssembly, X86,
It's worth nothing there has been some relevant prior discussion, see these
messages from Will Dietz and Renato Golin
## Options for the future of va_arg
Option 1: Discourage use of va_arg and aim to remove it in the future
* Most targets frontends have to directly manipulate va_list in at least
some cases. You could argue we'd be better off by having varargs
handled in a uniform manner, even if va_list manipulation is more explicit
and target specific?
Option 2: Status quo
* va_arg is there. Most backends can at least expand it, though it's not
clear how heavily tested this is.
* There's still a question of what the reccomendation should be for
frontends. If we keep va_arg as-is, would it be beneficial to
modify Clang to use it when possible, while falling back to explicit
manipulation if necessary like on Darwin/AArch64? Alternatively, casting may
allow va_arg to be used for a wider variety of types.
Option 3: Teach va_arg to handle aggregates
* In this option, va_arg might reasonably be expected to handle a struct,
but would not be expected to have detailed ABI-specific knowledge. e.g. it
won't automagically know whether a value of a certain size/type is passed
indirectly or not. In a sense, this would put support for aggregates passed
as varargs on par with aggregates passed in named arguments.
* Casting would be necessary in the same cases casting is required
for named args
* Support for aggregates could be implemented via a new module-level
pass, much like PNaCl.
* Alternatively, the conversion from the va_arg instruction to
SelectionDAG could be modified. It might be desirable to convert the vaarg
instruction to a number of loads and a new node that is responsible only for
manipulating the va_list struct.
Option 4: Expect va_arg to handle all ABI details
* In this more extreme option, va_arg with any type would expected to
generate ABI-compliant code. e.g. a va_arg with i128 would "do the right
thing", regardless of whether an i128 is passed indirectly or not for the
* This would be nice, but probably only makes sense as part of a larger
effort to reduce the ABI lowering burden on frontends. This sort of effort
has been discussed many times, and is not a small project.
## Next steps
I'd really appreciate any input on the issues here. Do people have strong
feelings about the future direction of va_arg? Will GlobalISel have any effect
on the relative difficulty or desirability of these options?