Hi, I made a simple test about aggregates in llvm IR. My simple LLVM code is running as expected under linux 32/64, but not under windows 32. After searched on the web on multiple return values, I'm still not sure if this test case can be flagged as the ABI issue. Or this would be a llvm code generator bug on window 32. The complete IR is attached as a text file and I checked the test with lli. (1) Pass a struct of type {void*, uint64_t} by pointer (in fact this is generated from Clang 3.0). The returned value of @call_by_pointer is 4 as expected, on both windows XP ia32 and linux ubuntu x64 I tested. %0 = type { i8*, i64 } define void @foo_by_pointer(%0* %agg_addr, i8*, i64) nounwind { entry: %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 store i8* %0, i8** %agg_addr.0, align 8 %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 store i64 %1, i64* %agg_addr.1, align 8 ret void } define i64 @call_by_pointer() { %a_ptr = alloca float, align 4 %a_opq = bitcast float* %a_ptr to i8* %agg_addr = alloca %0, align 8 call void @foo_by_pointer(%0* %agg_addr, i8* %a_opq, i64 4) %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 %result.1 = load i64* %agg_addr.1, align 8 ret i64 %result.1 } (2) Pass the struct by value (minor modifications on above code). The only difference is that we build the structure inside callee @foo_by_value and pass it by value to the caller @call_by_value. The returned value of @call_by_value is a random number on windows XP ia32. But on linux ubuntu x64 it is correct, 4. define %0 @foo_by_value(i8*, i64) nounwind { entry: %agg_addr = alloca %0, align 8 %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 store i8* %0, i8** %agg_addr.0, align 8 %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 store i64 %1, i64* %agg_addr.1, align 8 %result = load %0* %agg_addr, align 8 ret %0 %result } define i64 @call_by_value() { %a_ptr = alloca float, align 4 %a_opq = bitcast float* %a_ptr to i8* %result = call %0 @foo_by_value(i8* %a_opq, i64 4) %agg_addr = alloca %0, align 8 store %0 %result, %0* %agg_addr, align 8 %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 %result.1 = load i64* %agg_addr.1, align 8 ret i64 %result.1 } Is this a LLVM bug? Or call_by_value with foo_by_valye is invalid LLVM code? Thanks, Wei -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20110811/ef7b6805/attachment.html> -------------- next part -------------- ; ModuleID = 'Test' target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32" target triple = "i686-pc-win32" %0 = type { i8*, i64 } define %0 @foo_by_value(i8*, i64) nounwind { entry: %agg_addr = alloca %0, align 8 %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 store i8* %0, i8** %agg_addr.0, align 8 %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 store i64 %1, i64* %agg_addr.1, align 8 %result = load %0* %agg_addr, align 8 ret %0 %result } define i64 @call_by_value() { %a_ptr = alloca float, align 4 %a_opq = bitcast float* %a_ptr to i8* %result = call %0 @foo_by_value(i8* %a_opq, i64 4) %agg_addr = alloca %0, align 8 store %0 %result, %0* %agg_addr, align 8 %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 %result.1 = load i64* %agg_addr.1, align 8 ret i64 %result.1 } define void @foo_by_pointer(%0* %agg_addr, i8*, i64) nounwind { entry: %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 store i8* %0, i8** %agg_addr.0, align 8 %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 store i64 %1, i64* %agg_addr.1, align 8 ret void } define i64 @call_by_pointer() { %a_ptr = alloca float, align 4 %a_opq = bitcast float* %a_ptr to i8* %agg_addr = alloca %0, align 8 call void @foo_by_pointer(%0* %agg_addr, i8* %a_opq, i64 4) %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 %result.1 = load i64* %agg_addr.1, align 8 ret i64 %result.1 } define i32 @main() { %r1 = call i64 @call_by_value() %lower = trunc i64 %r1 to i32 ret i32 %lower ; higher 32 bits %r2 = lshr i64 %r1, 32 %higher = trunc i64 %r2 to i32 ret i32 %higher }
Hi Wei, this is a FAQ. The LLVM code generators do *not* try to produce ABI conformant code. Instead, your front-end must produce LLVM IR which is already ABI conformant. For example, on a platform where a function returning a struct should return it via a hidden pointer, the IR function should be declared with an explicit pointer argument for returning it; while on platforms for which it should be returned in registers, the IR function should be declared to return a struct. Yes, this is very annoying. Ciao, Duncan.> I made a simple test about aggregates in llvm IR. My simple LLVM code > is running as expected under linux 32/64, but not under windows 32. > After searched on the web on multiple return values, I'm still not sure if > this test case can be flagged as the ABI issue. Or this would be a llvm > code generator bug on window 32. The complete IR is attached as a text file > and I checked the test with lli. > > (1) Pass a struct of type {void*, uint64_t} by pointer (in fact this is > generated from Clang 3.0). > The returned value of @call_by_pointer is 4 as expected, on both windows XP ia32 > and linux ubuntu x64 I tested. > > %0 = type { i8*, i64 } > > define void @foo_by_pointer(%0* %agg_addr, i8*, i64) nounwind { > entry: > %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 > store i8* %0, i8** %agg_addr.0, align 8 > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > store i64 %1, i64* %agg_addr.1, align 8 > ret void > } > > define i64 @call_by_pointer() { > %a_ptr = alloca float, align 4 > %a_opq = bitcast float* %a_ptr to i8* > %agg_addr = alloca %0, align 8 > call void @foo_by_pointer(%0* %agg_addr, i8* %a_opq, i64 4) > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > %result.1 = load i64* %agg_addr.1, align 8 > ret i64 %result.1 > } > > (2) Pass the struct by value (minor modifications on above code). > The only difference is that we build the structure inside callee @foo_by_value > and pass it by value to the caller @call_by_value. The returned value of > @call_by_value is a random number on windows XP ia32. But on linux > ubuntu x64 it is correct, 4. > > define %0 @foo_by_value(i8*, i64) nounwind { > entry: > %agg_addr = alloca %0, align 8 > %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 > store i8* %0, i8** %agg_addr.0, align 8 > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > store i64 %1, i64* %agg_addr.1, align 8 > %result = load %0* %agg_addr, align 8 > ret %0 %result > } > > define i64 @call_by_value() { > %a_ptr = alloca float, align 4 > %a_opq = bitcast float* %a_ptr to i8* > %result = call %0 @foo_by_value(i8* %a_opq, i64 4) > %agg_addr = alloca %0, align 8 > store %0 %result, %0* %agg_addr, align 8 > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > %result.1 = load i64* %agg_addr.1, align 8 > ret i64 %result.1 > } > > Is this a LLVM bug? Or call_by_value with foo_by_valye is invalid LLVM code? > > Thanks, > > Wei > > > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Thanks for reply! This is indeed annoying. I suspect that passing an pointer to the struct and using GEP instructions to access and modify the struct would work on all platforms. Is this true? Thanks, Wei On Thu, Aug 11, 2011 at 7:55 AM, Duncan Sands <baldrick at free.fr> wrote:> Hi Wei, this is a FAQ. The LLVM code generators do *not* try to produce > ABI > conformant code. Instead, your front-end must produce LLVM IR which is > already > ABI conformant. For example, on a platform where a function returning a > struct > should return it via a hidden pointer, the IR function should be declared > with > an explicit pointer argument for returning it; while on platforms for which > it > should be returned in registers, the IR function should be declared to > return > a struct. Yes, this is very annoying. > > Ciao, Duncan. > > > I made a simple test about aggregates in llvm IR. My simple LLVM code > > is running as expected under linux 32/64, but not under windows 32. > > After searched on the web on multiple return values, I'm still not sure > if > > this test case can be flagged as the ABI issue. Or this would be a llvm > > code generator bug on window 32. The complete IR is attached as a text > file > > and I checked the test with lli. > > > > (1) Pass a struct of type {void*, uint64_t} by pointer (in fact this is > > generated from Clang 3.0). > > The returned value of @call_by_pointer is 4 as expected, on both windows > XP ia32 > > and linux ubuntu x64 I tested. > > > > %0 = type { i8*, i64 } > > > > define void @foo_by_pointer(%0* %agg_addr, i8*, i64) nounwind { > > entry: > > %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 > > store i8* %0, i8** %agg_addr.0, align 8 > > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > > store i64 %1, i64* %agg_addr.1, align 8 > > ret void > > } > > > > define i64 @call_by_pointer() { > > %a_ptr = alloca float, align 4 > > %a_opq = bitcast float* %a_ptr to i8* > > %agg_addr = alloca %0, align 8 > > call void @foo_by_pointer(%0* %agg_addr, i8* %a_opq, i64 4) > > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > > %result.1 = load i64* %agg_addr.1, align 8 > > ret i64 %result.1 > > } > > > > (2) Pass the struct by value (minor modifications on above code). > > The only difference is that we build the structure inside callee > @foo_by_value > > and pass it by value to the caller @call_by_value. The returned value of > > @call_by_value is a random number on windows XP ia32. But on linux > > ubuntu x64 it is correct, 4. > > > > define %0 @foo_by_value(i8*, i64) nounwind { > > entry: > > %agg_addr = alloca %0, align 8 > > %agg_addr.0 = getelementptr inbounds %0* %agg_addr, i32 0, i32 0 > > store i8* %0, i8** %agg_addr.0, align 8 > > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > > store i64 %1, i64* %agg_addr.1, align 8 > > %result = load %0* %agg_addr, align 8 > > ret %0 %result > > } > > > > define i64 @call_by_value() { > > %a_ptr = alloca float, align 4 > > %a_opq = bitcast float* %a_ptr to i8* > > %result = call %0 @foo_by_value(i8* %a_opq, i64 4) > > %agg_addr = alloca %0, align 8 > > store %0 %result, %0* %agg_addr, align 8 > > %agg_addr.1 = getelementptr inbounds %0* %agg_addr, i32 0, i32 1 > > %result.1 = load i64* %agg_addr.1, align 8 > > ret i64 %result.1 > > } > > > > Is this a LLVM bug? Or call_by_value with foo_by_valye is invalid LLVM > code? > > > > Thanks, > > > > Wei > > > > > > > > _______________________________________________ > > LLVM Developers mailing list > > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > _______________________________________________ > 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/20110811/5b0bf2aa/attachment.html>
Possibly Parallel Threads
- [LLVMdev] Pass a struct on windows
- [LLVMdev] Pass a struct on windows
- [LLVMdev] structured types as function arguments
- [RFC][InlineCost] Modeling JumpThreading (or similar) in inline cost model
- [RFC][InlineCost] Modeling JumpThreading (or similar) in inline cost model