Rafael Espíndola
2007-Jun-26 13:30 UTC
[LLVMdev] comments on Bug 1521 (Revamp LLVM by-value structure passing)
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
Jonas Maebe
2007-Jun-26 13:59 UTC
[LLVMdev] comments on Bug 1521 (Revamp LLVM by-value structure passing)
On 26 jun 2007, at 15:30, Rafael Espíndola wrote:> 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.What you described is not "the C way" of doing things, but the ABI way. How arguments are passed should not be source language dependent, but calling convention dependent. I think that if other source languages require other calling conventions, either new calling conventions should be added to LLVM, or the frontends for those languages should emulate their particular requirements using tricks like your third proposal (and e.g. by turning parameter types implicitly into pointer types). Jonas
Duncan Sands
2007-Jun-26 14:13 UTC
[LLVMdev] comments on Bug 1521 (Revamp LLVM by-value structure passing)
Hi Rafael,> 2) add a "byref" mark in the pointer argument.I think you mean "bycopy" or "byval" here.> 3) Have llvm-gcc create a copy before calling the function.Don't forget that the function may be called by code that was not compiled by LLVM. That's why we have to pay attention to the ABI! Solution (3) supposes we have control over both callers and callees, but we need to handle the situation in which we are calling code compiled by a different compiler, or code compiled by a different compiler is calling us. Ciao, Duncan.
Rafael Espíndola
2007-Jun-26 16:57 UTC
[LLVMdev] comments on Bug 1521 (Revamp LLVM by-value structure passing)
> > 2) add a "byref" mark in the pointer argument. > > I think you mean "bycopy" or "byval" here.Yes, good catch.> > 3) Have llvm-gcc create a copy before calling the function. > > Don't forget that the function may be called by code that > was not compiled by LLVM. That's why we have to pay attention > to the ABI! Solution (3) supposes we have control over both > callers and callees, but we need to handle the situation in > which we are calling code compiled by a different compiler, > or code compiled by a different compiler is calling us.I now noticed that I done a similar mistake as the current implementation. I have assumed that passing a structure with an implicit pointer is equivalent as passing it with an explicit one. That is not the case. In x86_64 for example, the explicit pointer is passed on rdi, and the implicit one is computed directly from the stack pointer. I would like to hide as much of the ABI form llvm as possible, but that would be a much bigger change then I thought. So, I think that the only question left before I try to implement Chris's solution is why it is better to have a "byval" attribute instead of adding support for struct in arguments? That is, why define void @f(%struct.cpp_num* %num byval) is better then define void @f(%struct cpp_num %num) Just curious :-)> Ciao, > > Duncan. >Thanks a lot, Rafael
Reasonably Related Threads
- [LLVMdev] comments on Bug 1521 (Revamp LLVM by-value structure passing)
- [LLVMdev] comments on Bug 1521 (Revamp LLVM by-value structure passing)
- [LLVMdev] Two new 'llvmnotes'
- [LLVMdev] Two new 'llvmnotes'
- Current preferred approach for handling 'byval' struct arguments