[LLVMdev] Variable length condition code for SETCC and SELECT?

B. Scott Michel scottm at aero.org
Thu Jun 5 17:44:33 PDT 2008

After a hiatus on the CellSPU development, I've got all of the 
instructions necessary to get the llvm-gcc frontend to build. I've now 
discovered a new and interesting problem that I'm not sure how to solve 
cleanly and it's due to the fact that CellSPU has no fixed size 
condition flags. CellSPU's condition flags depend on the size of what's 
being compared, i.e., if both arguments to SETCC are i32, then a 
corresponding i32 comparison should be generated. Similarly, if both 
arguments to SETCC are i16 or i8, then a corresponding i16 or i8 
comparison should be generated.

Another nice feature in the CellSPU architecture is the selb instruction 
that directly corresponds to SELECT. Again, though, if SETCC is i32, 
then SELECT has to be i32; if SETCC is i16, then SELECT has to be i16, etc.

Currently, I've got what looks to be a promotion problem showing up when 
compiling _addvsi3.c during the libgcc2 phase of llvm-gcc. The optimized 
selection DAG is show below:

Optimized lowered selection DAG:
SelectionDAG has 20 nodes:
  0x14ffca0: ch = EntryToken
    0x14ffca0: <multiple use>
    0x1500710: i32 = Register  #1025
  0x1500770: i32,ch = CopyFromReg 0x14ffca0, 0x1500710
    0x14ffca0: <multiple use>
    0x1500820: i32 = Register  #1026
  0x1500880: i32,ch = CopyFromReg 0x14ffca0, 0x1500820
    0x1500880: <multiple use>
    0x1500770: <multiple use>
  0x1500a00: i32 = add 0x1500880, 0x1500770
  0x1500b50: ch = setgt
        0x14ffca0: <multiple use>
        0x1501030: i32 = Register  #1024
        0x1500a00: <multiple use>
      0x1501090: ch = CopyToReg 0x14ffca0, 0x1501030, 0x1500a00
      0x14ffca0: <multiple use>
    0x1501330: ch = TokenFactor 0x1501090, 0x14ffca0
          0x1500880: <multiple use>
          0x15004c0: i32 = Constant <4294967295>
          0x1500b50: <multiple use>
        0x1500bb0: i1 = setcc 0x1500880, 0x15004c0, 0x1500b50
          0x1500a00: <multiple use>
          0x1500770: <multiple use>
          0x1500ab0: ch = setlt
        0x1500e90: i1 = setcc 0x1500a00, 0x1500770, 0x1500ab0
          0x1500a00: <multiple use>
          0x1500770: <multiple use>
          0x1500b50: <multiple use>
        0x1500c80: i1 = setcc 0x1500a00, 0x1500770, 0x1500b50
      0x1500f60: i1 = select 0x1500bb0, 0x1500e90, 0x1500c80
      0x15011b0: i1 = Constant <1>
    0x1501220: i1 = xor 0x1500f60, 0x15011b0
    0x15012d0: ch = BasicBlock <bb20 0x14ff930>
  0x15013e0: ch = brcond 0x1501330, 0x1501220, 0x15012d0

The setcc's are promoted to i32, since they are comparing i32 operands. 
The problem arises when the select (0x1500f60) is promoted by 
SelectionDAGLegalize::PromoteOp(), because the select's i1 is promoted 
to i8, which triggers an assert because select's arguments (i32) don't 
match the new, promoted value type.

It's possible to convince the SELECT case inside of 
SelectionDAGLegalize::PromoteOp() that it should really look at the 
operands' value type and then return a result promoted to the operands' 
value (i32, in this case.) But that doesn't work, because further on, we 
don't know to promote the i1 constant <1> to i32, and another assert 
gets triggered because select's i32 is larger/not equal to the 
constant's new promotion to i8.

It'd be easy to hack PromoteOp to make a pass to determine all operands' 
promoted value types, take the max, then figure out some way to 
re-promote them to maximal promoted value type. Except that this is a 
non-optimal solution requiring PromoteOp to potentially traverse the 
operand tree twice.

Any suggestions or ideas?


More information about the llvm-dev mailing list