Ramkumar Ramachandra
2014-Aug-26 19:37 UTC
[LLVMdev] [BUG] Varargs example in LangRef segfaults
Hi, So the Variable Argument Handling Intrinsics section of the LangRef (http://llvm.org/docs/LangRef.html#variable-argument-handling-intrinsics) lists an example that segfaults. Try the following on x86_64: -- 8< -- define i32 @test(i32 %X, ...) { ; Initialize variable argument processing %ap = alloca i8* %ap2 = bitcast i8** %ap to i8* call void @llvm.va_start(i8* %ap2) ; Read a single integer argument %tmp = va_arg i8** %ap, i32 ; Demonstrate usage of llvm.va_copy and llvm.va_end %aq = alloca i8* %aq2 = bitcast i8** %aq to i8* call void @llvm.va_copy(i8* %aq2, i8* %ap2) call void @llvm.va_end(i8* %aq2) ; Stop processing of arguments. call void @llvm.va_end(i8* %ap2) ret i32 %tmp } 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< -- It happens because va_arg is apparently not implemented properly on X86 (I saw tests/Codegen/X86/vaargs.ll). What should be done about the situation? 1. Update the LangRef. 2. Fix va_arg for x86. If (2) is the way to go, I'll take a stab at it. Thanks. Ram
The problem is that the type of the va_list is platform-specific. No IR example will work on all platforms, unless you overallocate. The LangRef should probably be updated to use the SysV x86_64 va_list as that is the most common and mention in an IR comment that the type depends on the platform. On Tue, Aug 26, 2014 at 12:37 PM, Ramkumar Ramachandra <artagnon at gmail.com> wrote:> Hi, > > So the Variable Argument Handling Intrinsics section of the LangRef > (http://llvm.org/docs/LangRef.html#variable-argument-handling-intrinsics) > lists an example that segfaults. Try the following on x86_64: > > -- 8< -- > define i32 @test(i32 %X, ...) { > ; Initialize variable argument processing > %ap = alloca i8* > %ap2 = bitcast i8** %ap to i8* > call void @llvm.va_start(i8* %ap2) > > ; Read a single integer argument > %tmp = va_arg i8** %ap, i32 > > ; Demonstrate usage of llvm.va_copy and llvm.va_end > %aq = alloca i8* > %aq2 = bitcast i8** %aq to i8* > call void @llvm.va_copy(i8* %aq2, i8* %ap2) > call void @llvm.va_end(i8* %aq2) > > ; Stop processing of arguments. > call void @llvm.va_end(i8* %ap2) > ret i32 %tmp > } > > 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< -- > > It happens because va_arg is apparently not implemented properly on > X86 (I saw tests/Codegen/X86/vaargs.ll). What should be done about the > situation? > 1. Update the LangRef. > 2. Fix va_arg for x86. > > If (2) is the way to go, I'll take a stab at it. > > Thanks. > > Ram > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140826/3e6271e3/attachment.html>
Ramkumar Ramachandra
2014-Aug-26 21:36 UTC
[LLVMdev] [BUG] Varargs example in LangRef segfaults
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?