[LLVMdev] [BUG] Varargs example in LangRef segfaults

Reid Kleckner rnk at google.com
Tue Aug 26 14:51:11 PDT 2014


va_arg of struct types is not implemented in the x86_64 backend:

  // Decide which area this value should be read from.
  // TODO: Implement the AMD64 ABI in its entirety. This simple
  // selection mechanism works only for the basic types.
  if (ArgVT == MVT::f80) {
    llvm_unreachable("va_arg for f80 not yet implemented");
  } else if (ArgVT.isFloatingPoint() && ArgSize <= 16 /*bytes*/) {
    ArgMode = 2;  // Argument passed in XMM register. Use fp_offset.
  } else if (ArgVT.isInteger() && ArgSize <= 32 /*bytes*/) {
    ArgMode = 1;  // Argument passed in GPR64 register(s). Use gp_offset.
  } else {
    llvm_unreachable("Unhandled argument type in LowerVAARG");
  }

So Clang lowers it manually.

If you only use builtin types such as integers, pointers, floats, and
doubles, then va_arg works.


On Tue, Aug 26, 2014 at 2:36 PM, Ramkumar Ramachandra <artagnon at gmail.com>
wrote:

> So I've written out this sample based on what Clang emitted:
>
> -- 8< --
> %struct.__va_list_tag = type { i32, i32, i8*, i8* }
>
> define i32 @test(i32 %X, ...) {
>   ; Initialize variable argument processing
>   %ap = alloca %struct.__va_list_tag
>   %ap2 = bitcast %struct.__va_list_tag* %ap to i8*
>   %retptr = alloca i32
>   call void @llvm.va_start(i8* %ap2)
>
>   ; Read a single integer argument
>   %idxptr = getelementptr inbounds %struct.__va_list_tag* %ap, i32 0, i32 0
>   %idx = load i32* %idxptr
>   %tmp = getelementptr inbounds %struct.__va_list_tag* %ap, i32 0, i32 3
>   %extract = load i8** %tmp
>   %rawel = getelementptr i8* %extract, i32 %idx
>   %elptr = bitcast i8* %rawel to i32*
>   %newidx = add i32 %idx, 8
>   store i32 %idx, i32* %idxptr
>
>   ; Store that argument in el
>   %el = load i32* %elptr
>   store i32 %el, i32* %retptr
>   %ret = load i32* %retptr
>
>   ; Stop processing of arguments.
>   call void @llvm.va_end(i8* %ap2)
>   ret i32 %ret
> }
>
> define i32 @main() {
>   %call = call i32 (i32, ...)* @test(i32 1, i32 3)
>   ret i32 %call
> }
>
> declare void @llvm.va_start(i8*)
> declare void @llvm.va_copy(i8*, i8*)
> declare void @llvm.va_end(i8*)
> -- 8< --
>
> Can we include (a neater version of) this in the LangRef? Can it not
> be simplified?
>
> I understand that %struct.__va_list_tag will be different for each
> platform, so the user can't gep into the structure in a
> platform-independent manner, but what's the problem with this?
>
> %ap = alloca_va_list
> %ap2 = bitcast %struct.__va_list_tag* %ap to i8*
> call void @llvm.va_start(i8* %ap2)
> va_arg %ap i32
> call void @llvm.va_end(i8* %ap2)
>
> All we need is a sort of global %struct.__va_list_tag, right?
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140826/5d0b3e44/attachment.html>


More information about the llvm-dev mailing list