[LLVMdev] structured types as function arguments

Du Toit, Stefanus stefanus.du.toit at intel.com
Mon Aug 15 13:09:52 PDT 2011


This was asked and answered a few days ago (Re: [LLVMdev] Pass a struct on windows):

===
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.

>
> Thanks,
>
> Wei
>
> On Thu, Aug 11, 2011 at 7:55 AM, Duncan Sands <baldrick at free.fr
> <mailto: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 <mailto: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 <mailto:LLVMdev at cs.uiuc.edu> http://llvm.cs.uiuc.edu
>     http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
===

--
Stefanus Du Toit stefanus.du.toit at intel.com
  Intel Array Building Blocks - http://intel.com/go/arbb
  Intel Embedded Computing, Debuggers & Libraries
  Intel Waterloo
  phone: +1 519 772 2576 -- fax: +1 519 772 2586


> -----Original Message-----
> From: llvmdev-bounces at cs.uiuc.edu [mailto:llvmdev-bounces at cs.uiuc.edu] On
> Behalf Of Nicolas Ojeda Bar
> Sent: Monday, August 15, 2011 12:02 PM
> To: llvmdev at cs.uiuc.edu
> Subject: [LLVMdev] structured types as function arguments
> 
> Hi,
> 
> When calling a function, does the llvm code generator support passing
> structured types (arrays, structs, etc.) by _value_? I wrote some small examples,
> and it seemed
> to work, but I was wondering if anything can go wrong if the structured types
> are very large...
> 
> Thanks,
> N
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev




More information about the llvm-dev mailing list