Ralf Karrenberg
2010-Jan-25 10:44 UTC
[LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
Hey everybody, I am struggling to get rid of a problem which seems to be related to a multi-return value optimization: I generate bitcode for a c++-function with llvm-g++ which is then linked, transformed and optimized at runtime using LLVM. The function has quite a few parameters, including structs and struct-pointers with 3 float fields. The problem is, that I require the function to preserve the number and type of its arguments, but some optimization on 64bit breaks up some of the struct parameters (I suppose only those that are just loaded and/or stored somewhere) and inserts a double and a float. Same goes for load and store instructions of the same struct-type: in general it might be a good idea to only do two loads/stores (1 double, 1 float) instead of three (3 float), but I don't want this to happen. Unfortunately, the optimization seems to happen in the frontend already (llvm-gcc/gcc/config/i386/llvm-i386.cpp and/or llvm-gcc/gcc/llvm-convert.cpp) - can I do something to prevent this? One thing that works is generating code for 32bit (-m32), but this obviously causes other problems. Best regards, Ralf
Duncan Sands
2010-Jan-25 11:13 UTC
[LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
Hi Ralf,> The problem is, that I require the function to preserve the number and > type of its arguments, but some optimization on 64bit breaks up some of > the struct parameters (I suppose only those that are just loaded and/or > stored somewhere) and inserts a double and a float.this is almost certainly *not* an optimization - the llvm-g++ front-end generates this because the x86-64 ABI requires it. There's not much that can be done about it if you want your functions to be callable from code compiled with a different compiler, such as gcc. Ciao, Duncan.
Ralf Karrenberg
2010-Jan-25 11:57 UTC
[LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
Uh, sorry, did not pay attention where I was replying ;) Hey Duncan, I do not understand why this behaviour is required. What is the problem in having a function receive a single struct-parameter with three floats compared to two scalar parameters? source-code (C++): struct Test3Float { float a, b, c; }; void test(Test3Float param, Test3Float* result) { ... } bitcode: %"struct.Test3Float" = type { float, float, float } define void @_Z4test10Test3FloatPS_(double %param.0, float %param.1, %"struct.Test3Float"* %result) { ... } Best, Ralf Duncan Sands wrote:> Hi Ralf, please don't only reply to me personally: please reply to the > mailing > list as well. That way others can respond with their own comments, > and the > discussion will be archived, for the benefit of those who have the > same issue in > the future. > > Thanks, > > Duncan. >
Duncan Sands
2010-Jan-25 12:35 UTC
[LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
Hi Ralf,> I do not understand why this behaviour is required. What is the problem > in having a function receive a single struct-parameter with three floats > compared to two scalar parameters? > > source-code (C++): > struct Test3Float { float a, b, c; }; > void test(Test3Float param, Test3Float* result) { ... }if you compile this with GCC, you will see that it too passes the first two floats in one double register, and the remaining float in a different register. The GCC people didn't make this behaviour up, they are following the platform ABI specification (which you can find floating around on the internet; the name is something like "System V application binary interface"). In order to conform to the standard, the object code produced by LLVM also needs to pass the struct in the same way. That said, you could imagine that in the bitcode the struct would be passed as a struct, rather than double+float, and the code generators would take care of squirting out the appropriate double+float machine code. Sadly this is not the case: ABI conformance is handled in the front-end. The fundamental reason for this is that some ABI's (eg: the x86-64 one) specify how parameters are passed based on type information that is available in C but not in LLVM. For example, a complex number is passed differently to a struct containing two floats, even though in LLVM a complex number is exactly the same as a struct containing two floats. So if the code generators were to take care of everything, then the entire C type system would somehow have to be represented in LLVM bitcode, just for this. Instead the decision was taken to require front-ends to deal with this kind of issue. Yes, this sucks - but no-one came up with a better solution yet.> bitcode: > %"struct.Test3Float" = type { float, float, float } > define void @_Z4test10Test3FloatPS_(double %param.0, float %param.1, > %"struct.Test3Float"* %result) { ... }Ciao, Duncan.
Seemingly Similar Threads
- [LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
- [LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
- [LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
- [LLVMdev] 64bit MRV problem: { float, float, float} -> { double, float }
- [LLVMdev] Question about NoWrap flag for SCEVAddRecExpr