Pass a struct on windows

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

struct_by_value…txt (1.85 KB)

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.

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

Hi Wei,

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?

yes, I think that would work fine.

Ciao, Duncan.