JinGu Kang via llvm-dev
2015-Dec-22 13:01 UTC
[llvm-dev] 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
Tim Northover via llvm-dev
2015-Dec-22 20:55 UTC
[llvm-dev] Question about TargetLowering::SimplifyDemandedBits with AND
Hi Jingu, On 22 December 2015 at 05:01, JinGu Kang via llvm-dev <llvm-dev at lists.llvm.org> wrote:> 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.
JinGu Kang via llvm-dev
2015-Dec-22 21:43 UTC
[llvm-dev] Question about TargetLowering::SimplifyDemandedBits with AND
Great comment, Tim!!! The problem is solved now!!! :) Thank you so much, JinGu Kang On 22/12/15 20:55, Tim Northover wrote:> Hi Jingu, > > On 22 December 2015 at 05:01, JinGu Kang via llvm-dev > <llvm-dev at lists.llvm.org> wrote: >> 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.