[LLVMdev] comments on Bug 1521 (Revamp LLVM by-value structure passing)

Rafael EspĂ­ndola rafael.espindola at gmail.com
Tue Jun 26 06:30:33 PDT 2007


This is my current understanding of the current situation and the
proposed solution.

Currently llvm-gcc compiles
-----------------------
struct cpp_num
{
  unsigned long high;
  unsigned long low;
  char unsignedp;
};

void g(unsigned long);
void f(struct cpp_num num) {
  g(num.high + 1);
}
----------------------

into
---------------------------------------------------------------------------
define void @f(i64 %num.0.0, i64 %num.0.1, i64 %num.0.2) {
...
--------------------------------------------------------------------------

For some architectures (x86_64) this is wrong since the struct should
be passed on the stack, not on registers.

llvm should be compiling into something like
-----------------------------------------------------
define void @f(%struct.cpp_num* %num) {
entry:
        %tmp1 = getelementptr %struct.cpp_num* %num, i32 0, i32 0
        %tmp2 = load i64* %tmp1
        %tmp3 = add i64 %tmp2, 1
        tail call void @g( i64 %tmp3 )
        ret void
}
---------------------------------------------
This generates correct and quiet acceptable assembly code. The problem
is that the code generator is not going to create a copy when
compiling a call to "f".

Some solutions:
1 ) add support structures as argument in LLVM and tell the various
codegen how to handle it. Chris says that LLVM should not go this way
2) add a "byref" mark in the pointer argument. The codegen should now
copy the struct on the stack or copy it to registers when generating a
call. The function codegen stays the same. This is the proposed
solution.
3) Have llvm-gcc create a copy before calling the function.  That is, compile
----------------------------------------------------
void g(struct cpp_num a);
void f(struct cpp_num b) {
 g(b);
}
----------------------------------------------------
into
----------------------------------------------------
define void @f(%struct.cpp_num* %b) {
entry:
        %x = alloca %struct.cpp_num, align 16
        %x1 = bitcast %struct.cpp_num* %x to i8*
        %tmp2 = bitcast %struct.cpp_num* %b to i8*
        call void @llvm.memcpy.i64( i8* %x1, i8* %tmp2, i64 24, i32 8 )
        call void @g( %struct.cpp_num* %x )
        ret void
}
----------------------------------------------------

What I like about option 3 is that llvm continues to be unaware about
the C struct passing convention. This is good since another FE (D,
ADA) might want to have a different way of passing
structs/objects/whatever. If we specialize on the C way of doing
things I thing that other FE will have to come up with their own
solutions and might not get as good code.

Thoughts, comments, another solution?

Cheers,
Rafael



More information about the llvm-dev mailing list