Question about TargetLowering::SimplifyDemandedBits with AND

Hi All,

I have faced a problem with TargetLowering::SimplifyDemandedBits with AND. Here is a example as following:

/* C source code */
struct A
{
   unsigned int a;
   unsigned char c1, c2;
   bool b1 : 1;
   bool b2 : 1;
   bool b3 : 1;
};

int main ()
{
   struct A x[1];
   x[0].b1 = false;

   int s = 0;
   s = x[0].b1 ? 1 : 0; <--- Here is problem.

   if (s != 0)
     __builtin_abort ();
   return 0;
}

/* IR of "s = x[0].b1 ? 1 : 0;" */
...
   %b12 = getelementptr inbounds %struct.A, %struct.A* %arrayidx1, i32 0, i32 3
   %bf.load3 = load i8, i8* %b12, align 2
   %bf.clear4 = and i8 %bf.load3, 1
   %bf.cast = trunc i8 %bf.clear4 to i1
   %cond = select i1 %bf.cast, i32 1, i32 0
   store i32 %cond, i32* %s, align 4
...

/* Initial Selection DAG of "s = x[0].b1 ? 1 : 0;" */
...
   0x81d17c0: i8,ch = load 0x81cca20, 0x81cbfb8, 0x81cc0e0<LD1[%b12](align=2)> [ORD=14]

     0x81d17c0: <multiple use>
           0x81d17c0: <multiple use>
           0x81d18e8: i8 = Constant<1>

         0x81d1a10: i8 = and 0x81d17c0, 0x81d18e8 [ORD=15]

       0x81d1b38: i1 = truncate 0x81d1a10 [ORD=16]

       0x81d1c60: i32 = Constant<1>

       0x81cc330: <multiple use>
     0x81d1d88: i32 = select 0x81d1b38, 0x81d1c60, 0x81cc330 [ORD=17]
...

Until initial selection DAG, it looks fine. Let's look at dag after dag combine.
/* After dag combine, "s = x[0].b1 ? 1 : 0;" */
...
   0x81d17c0: i8,ch = load 0x81cca20, 0x81cbfb8, 0x81cc0e0<LD1[%b12](align=2)> [ORD=14]

       0x81d17c0: <multiple use>
       --> 'and' was removed.
     0x81d1b38: i1 = truncate 0x81d17c0 [ORD=16]

     0x81d1c60: i32 = Constant<1>

     0x81cc330: <multiple use>
   0x81d1d88: i32 = select 0x81d1b38, 0x81d1c60, 0x81cc330 [ORD=17]
...

The target, which I am working, does not have i1's register class. It means that the 'truncate' is changed to its first operand 'load' during type legalize because it should be promoted. Therefore I have wanted to keep the 'and' to make correct 1 bit value. But dag combine pass is removing the 'and' on TargetLowering::SimplifyDemandedBits function. When I look at the function, even though the LHS does not have knownbit information, the code uses it with NewMask to compare LHS with RHS. Is it intended? Could someone explain it? If I missed something, please let me know.

Thanks,
JinGu Kang

Hi Jingu,

The target, which I am working, does not have i1's register class. It means
that the 'truncate' is changed to its first operand 'load' during type
legalize because it should be promoted. Therefore I have wanted to keep the
'and' to make correct 1 bit value. But dag combine pass is removing the
'and' on TargetLowering::SimplifyDemandedBits function.

This is correct, the AND is immediately followed by a TRUNCATE, which
means it's redundant.

When I look at the
function, even though the LHS does not have knownbit information, the code
uses it with NewMask to compare LHS with RHS. Is it intended? Could someone
explain it? If I missed something, please let me know.

What would normally happen is that the AND would be reinserted if
necessary during type legalization (based on a getBooleanContents
query). LLVM would decide it needed to promote the i1 operand of
SELECT to an i32. The default boolean contents are
UndefinedBooleanContent, which means that whatever implements SELECT
is only going to look at the first bit so LLVM inserts an ANY_EXTEND
which becomes a nop.

If you change that to ZeroOrOneBooleanContent then LLVM will know that
SELECT expects either a 0 or 1 in its i32 and use ZERO_EXTEND instead.
The (i32 ZERO_EXTEND i1) then gets further lowered to an AND.

Alternatively, you could change your code that actually implements
SELECT to only look at the low bit of the boolean i32. Which path is
better depends on the instructions your CPU has available, but both
could work.

Cheers.

Tim.

Great comment, Tim!!! The problem is solved now!!! :slight_smile:

Thank you so much,
JinGu Kang