[LLVMbugs] [Bug 1104] NEW: Bad struct argument "packing/conversion" in llvm-gcc4

bugzilla-daemon at cs.uiuc.edu bugzilla-daemon at cs.uiuc.edu
Wed Jan 10 13:17:43 PST 2007


           Summary: Bad struct argument "packing/conversion" in llvm-gcc4
           Product: tools
           Version: trunk
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: major
          Priority: P2
         Component: llvm-gcc
        AssignedTo: unassignedbugs at nondot.org
        ReportedBy: zhiruz at gmail.com

When I was playing with the new (TOT) llvm-gcc4 and LLVM opt, I found a pretty
serious problem due to a weird struct argument transformation by llvm-gcc4,
which could potentially lead to code size blow-up.

I have a simple example here. Basically, the C code decribes an addition routine
for two complex numbers. 
typedef struct { short r; short i; } complex;
complex add_complex(complex a, complex b)
    complex c;
    c.r = a.r + b.r;   
    c.i = a.i + b.i;
    return c;

After "llvm-makegcc -O3", the struct parameters "a" and "b" are converted into
two "int32" scalars. Since two 16-bit fields are packed together, many extra
truncates and shifts are introduced.  
//========complex.ll (by llvm-makegcc -O3) ================// 
define csretcc void %add_complex(%struct.complex* %agg.result, i32 %a.0, i32 %b.0) {
        %tmp30 = trunc i32 %a.0 to i16          ; <i16> [#uses=1] 
        %tmp427 = trunc i32 %b.0 to i16         ; <i16> [#uses=1] 
        %tmp5 = add i16 %tmp427, %tmp30         ; <i16> [#uses=1]
        %tmp828 = lshr i32 %a.0, i8 16          ; <i32> [#uses=1] 
        %tmp829 = trunc i32 %tmp828 to i16              ; <i16> [#uses=1] 
        %tmp1025 = lshr i32 %b.0, i8 16         ; <i32> [#uses=1]
        %tmp1026 = trunc i32 %tmp1025 to i16            ; <i16> [#uses=1] 
        %tmp11 = add i16 %tmp1026, %tmp829              ; <i16> [#uses=1] 
        %tmp13 = getelementptr %struct.complex* %agg.result, i32 0, i32 0      
        ; <i16*> [#uses=1]
        store i16 %tmp5, i16* %tmp13 
        %tmp16 = getelementptr %struct.complex* %agg.result, i32 0, i32 1      
        ; <i16*> [#uses=1] 
        store i16 %tmp11, i16* %tmp16
        ret void

I was confused as I thought ScalarReplAggregates pass should convert it to two
i16 scalars. To confirm this is not LLVM opt's problem, I tried "llvm-makegcc
-O0" option and saw the same conversion for the structure arguments. 
So it looks like a llvm-gcc4 bug. To me, this conversion does not make much
sense. If the purpose is to do scalar promotion, why not split the "complex"
struct into two "int16"s? 

With the hope to get a little bit more insights, I tested more cases and got the
following not-so-encouraging results:

* struct {int, int, int} ==> int64, int32 (understandable, pack to the same
size, but introduces unneccessary truncates and shifts)
* struct {double, double} ==> int64, int64 (bad conversion, requires a lot of
redundant bitcast/load/store) 
* struct {double, int a[1000]} ==> int64, plus FIVE HUNDRED separate int64 (WOW,
I am stunned ...)

The C code and the output .bc are attached.

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.

More information about the llvm-bugs mailing list