<div dir="ltr">va_arg of struct types is not implemented in the x86_64 backend:<div><br></div><div><div> // Decide which area this value should be read from.</div><div> // TODO: Implement the AMD64 ABI in its entirety. This simple</div>
<div> // selection mechanism works only for the basic types.</div><div> if (ArgVT == MVT::f80) {</div><div> llvm_unreachable("va_arg for f80 not yet implemented");</div><div> } else if (ArgVT.isFloatingPoint() && ArgSize <= 16 /*bytes*/) {</div>
<div> ArgMode = 2; // Argument passed in XMM register. Use fp_offset.</div><div> } else if (ArgVT.isInteger() && ArgSize <= 32 /*bytes*/) {</div><div> ArgMode = 1; // Argument passed in GPR64 register(s). Use gp_offset.</div>
<div> } else {</div><div> llvm_unreachable("Unhandled argument type in LowerVAARG");</div><div> }</div><div><br></div></div><div>So Clang lowers it manually.</div><div><br></div><div>If you only use builtin types such as integers, pointers, floats, and doubles, then va_arg works.</div>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Aug 26, 2014 at 2:36 PM, Ramkumar Ramachandra <span dir="ltr"><<a href="mailto:artagnon@gmail.com" target="_blank">artagnon@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">So I've written out this sample based on what Clang emitted:<br>
<br>
-- 8< --<br>
%struct.__va_list_tag = type { i32, i32, i8*, i8* }<br>
<div class=""><br>
define i32 @test(i32 %X, ...) {<br>
; Initialize variable argument processing<br>
</div> %ap = alloca %struct.__va_list_tag<br>
%ap2 = bitcast %struct.__va_list_tag* %ap to i8*<br>
%retptr = alloca i32<br>
<div class=""> call void @llvm.va_start(i8* %ap2)<br>
<br>
; Read a single integer argument<br>
</div> %idxptr = getelementptr inbounds %struct.__va_list_tag* %ap, i32 0, i32 0<br>
%idx = load i32* %idxptr<br>
%tmp = getelementptr inbounds %struct.__va_list_tag* %ap, i32 0, i32 3<br>
%extract = load i8** %tmp<br>
%rawel = getelementptr i8* %extract, i32 %idx<br>
%elptr = bitcast i8* %rawel to i32*<br>
%newidx = add i32 %idx, 8<br>
store i32 %idx, i32* %idxptr<br>
<br>
; Store that argument in el<br>
%el = load i32* %elptr<br>
store i32 %el, i32* %retptr<br>
%ret = load i32* %retptr<br>
<div class=""><br>
; Stop processing of arguments.<br>
call void @llvm.va_end(i8* %ap2)<br>
</div> ret i32 %ret<br>
<div class="">}<br>
<br>
define i32 @main() {<br>
%call = call i32 (i32, ...)* @test(i32 1, i32 3)<br>
ret i32 %call<br>
}<br>
<br>
declare void @llvm.va_start(i8*)<br>
declare void @llvm.va_copy(i8*, i8*)<br>
declare void @llvm.va_end(i8*)<br>
-- 8< --<br>
<br>
</div>Can we include (a neater version of) this in the LangRef? Can it not<br>
be simplified?<br>
<br>
I understand that %struct.__va_list_tag will be different for each<br>
platform, so the user can't gep into the structure in a<br>
platform-independent manner, but what's the problem with this?<br>
<br>
%ap = alloca_va_list<br>
%ap2 = bitcast %struct.__va_list_tag* %ap to i8*<br>
call void @llvm.va_start(i8* %ap2)<br>
va_arg %ap i32<br>
call void @llvm.va_end(i8* %ap2)<br>
<br>
All we need is a sort of global %struct.__va_list_tag, right?<br>
</blockquote></div><br></div>