Is va_arg deprecated?

Hi folk,

I’m writing a set of small C code to verify whether my pass handle some instruction correctly. One of the instruction I want to test is “va_arg”, but compiling my variadic function does not generate any va_arg instruction. Is va_arg deprecated? Will va_arg instruction ever be generated by any front-end? The source code and llvm instructions are appended as follows.

the c code

void printValue(char * fmt, …) {
va_list args;
va_start(args, fmt);
int i;
double d;
i = va_arg(args, int);
d = va_arg(args, double);

the generated llvm instructions:
; ModuleID = ‘i.bc’
target datalayout = “e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32”
target triple = “i386-pc-linux-gnu”

define void @printValue(i8* %fmt, …) nounwind {
%fmt_addr = alloca i8* ; <i8**> [#uses=1]
%args.2 = alloca i8* ; <i8**> [#uses=3]
%args.0 = alloca i8* ; <i8**> [#uses=3]
%args = alloca i8* ; <i8**> [#uses=6]
%i = alloca i32 ; <i32*> [#uses=1]
%d = alloca double, align 8 ; <double*> [#uses=1]
%“alloca point” = bitcast i32 0 to i32 ; [#uses=0]
store i8* %fmt, i8** %fmt_addr
%args1 = bitcast i8** %args to i8* ; <i8*> [#uses=1]
call void @llvm.va_start(i8* %args1)
%0 = load i8** %args, align 4 ; <i8*> [#uses=1]
store i8* %0, i8** %args.0, align 4
%1 = load i8** %args.0, align 4 ; <i8*> [#uses=1]
%2 = getelementptr inbounds i8* %1, i64 4 ; <i8*> [#uses=1]
store i8* %2, i8** %args, align 4
%3 = load i8** %args.0, align 4 ; <i8*> [#uses=1]
%4 = bitcast i8* %3 to i32* ; <i32*> [#uses=1]
%5 = load i32* %4, align 4 ; [#uses=1]
store i32 %5, i32* %i, align 4
%6 = load i8** %args, align 4 ; <i8*> [#uses=1]
store i8* %6, i8** %args.2, align 4
%7 = load i8** %args.2, align 4 ; <i8*> [#uses=1]
%8 = getelementptr inbounds i8* %7, i64 8 ; <i8*> [#uses=1]
store i8* %8, i8** %args, align 4
%9 = load i8** %args.2, align 4 ; <i8*> [#uses=1]
%10 = bitcast i8* %9 to double* ; <double*> [#uses=1]
%11 = load double* %10, align 4 ; [#uses=1]
store double %11, double* %d, align 8
%args2 = bitcast i8** %args to i8* ; <i8*> [#uses=1]
call void @llvm.va_end(i8* %args2)
br label %return

return: ; preds = %entry
ret void

declare void @llvm.va_start(i8*) nounwind

declare void @llvm.va_end(i8*) nounwind


FYI, my group has added a flag to llvm-gcc for emitting the va_arg
instruction (instead of lowering in the front-end),
and we also have an implementation of the VAARG instruction for
X86-64. (which is currently not implemented in the LLVM backend).

Both of these things will be sent upstream to LLVM soon, pending some
more testing and review.

If you are dire need of these features now, I can point you to the
(public) repository where we have the beta versions.

- David M

Currently both clang and llvm-gcc lower va_arg. As David mentioned, we
are experimenting with va_arg. Some bits were pushed upstream, some
are in our public svn repo waiting for more testing/cleanup or just
time to send it upstream. With those patches it is possible to use
va_arg, but they are not as tested and the code is not as good (we
load and store the va_list every time for example).

It should be possible to improve the code generated by va_arg and some
optimizations might also be easier to implement with it, but it is not
done yet.

So, there is hope that va_arg will be used, but currently it isn't.


Thanks David, I don’t want my pass to get any surprise when some front-ends emit va_arg. Can you please point out the link of your beta versions? Thanks, Neal.

Hi David,

I'm working on source to source transformations and instrumentation.
A flag to disable 'va_arg' lowering in LLVM FEs will be very useful.

Have you sent your modifications upstream to LLVM?
If not, could you please share link to your public repository.

Sergey Yakoushkin


For the sake of simplicity, if types are simple, we emit va_arg
directly, otherwise we do like Clang and lower it in the front-end.

Would be nice to keep va_arg for the simple cases...



Here’s a patch on llvm-gcc which adds a flag “-fuse-llvm-va-arg”.

(Note that this patch won’t ever be part of llvm-gcc upstream. It will most likely be deprecated by later changes.)

  • pdox

llvm-gcc-va-arg-2.patch (5.62 KB)

Have these changes made it to mainline? Is there a way to get a patch for the
backend, which does the actual lowering?


FWIW, attached is a similar patch that adds a -falways-use-llvm-vaarg
flag to Clang.

Applies against mainline.

(As discussed, va_arg isn't really supported well so this probably
doesn't work well on anything other than simple code, YMMV, etc)


0001-Add-option-to-force-emitting-va_arg-instruction.patch (6.01 KB)

So, what's the point of this one?


To get clang to emit va_arg instructions for va_arg() calls, as
opposed to manually lowering it in the frontend, same as the llvm-gcc
patch sent earlier does.


I should have been more specific:

"Why do we want this as an option? Do we want it on all the time? Why or why not?"


Oh, sorry about that, and thanks for the clarification as to what you
were looking for.

Here you go:

** Why do we want this option? **

Presently clang will manually lower va_arg() in the frontend to the
equivalent (relatively complicated!) IR, as opposed to making use of
the LLVM va_arg instruction directly. IR that contains the va_arg
instruction is much easier to analyze because it is concise and clear
in its semantics. The lowered version IR is target-specific pointer
manipulation from a magic struct, that can expand to multiple BB's and
introduce conditional branches. Therefore, this option helps make the
IR significantly easier to analyze and is probably also rather useful
for source-to-source transformations.

** Do we want it on all the time? Why or why not? **

No, certainly not. Not until the various backends fully support the
va_arg instruction*, and even then there might be ABI issues**.
Furthermore, the existing clang code seems to suggest emitting va_arg
instructions for complex and aggregate values doesn't work***, and my
limited testing agrees with this. It's also possible that lowering it
later rather than earlier has an effect on optimizations and the like,
but I don't know how significant that is.

For those reasons I'd say this option should default to off (as done
in the patch), as va_arg doesn't seem suitable for general use at this

0001-Add-option-to-force-emitting-va_arg-instruction.patch (5.89 KB)

Hi Will,

I think that was a great summary. There is, however, one question that
is hovering this issue:

If not all back-ends support, and we don't want it all the time, is it
worth to keep it half-way through just for the sake of simplicity in
some analysis?

Other features (like union types) got removed for the same reason, and
as much as I liked the idea of having them, I didn't have a strong
case to keep them in the trunk.

To have a flag that will enable it only in special cases is the
quickest way to decommission in the near future, especially near major
releases (like 3.0).

There is a way to work around it that was touched last year when we
were discussing about union types, bitfields and C++ ABI: to have an
IR lowering pass.

The idea is that front-ends can create a reasonably simple IR by using
special constructs (va_arg, bitfield semantics, union types) but not
all back-ends can understand them and, most importantly, those that
do, do it at different levels. So, this pass could be run after all
the passes that need the extra semantics, (lowering all constructs
into simpler, messier IR), and before the other passes that need the
lower IR. Specific targets could have special lowering passes, if
there is a feature they don't support.

For example, at that time, the ARM back-end couldn't deal with struct
by-val, but it could with array by-val. So Clang had to cast all
structures being returned to arrays to pass it by-val. Now that is a
complication that Clang didn't have to know! So, to completely
de-couple front-ends from back-ends, we need those smart passes in the

But that's a long road...