[LLVMdev] Pass a struct on windows

Wei Pan wpan9 at uwo.ca
Thu Aug 11 04:24:51 PDT 2011


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
}


More information about the llvm-dev mailing list