[InstCombine] fold negated low-bit-mask to cmp+select
authorSanjay Patel <spatel@rotateright.com>
Sun, 3 Jul 2022 16:23:29 +0000 (12:23 -0400)
committerSanjay Patel <spatel@rotateright.com>
Sun, 3 Jul 2022 16:25:26 +0000 (12:25 -0400)
(-(X & 1)) & Y --> (X & 1) == 0 ? 0 : Y
https://alive2.llvm.org/ce/z/rhpH3i

This is noted as a missing IR canonicalization in issue #55618.
We already managed to fix codegen to the expected form.

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/and.ll

index ae88656..d3578fe 100644 (file)
@@ -1771,6 +1771,16 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
     return new ZExtInst(IsZero, Ty);
   }
 
+  // (-(X & 1)) & Y --> (X & 1) == 0 ? 0 : Y
+  Value *Neg;
+  if (match(&I,
+            m_c_And(m_CombineAnd(m_Value(Neg),
+                                 m_OneUse(m_Neg(m_And(m_Value(), m_One())))),
+                    m_Value(Y)))) {
+    Value *Cmp = Builder.CreateIsNull(Neg);
+    return SelectInst::Create(Cmp, ConstantInt::getNullValue(Ty), Y);
+  }
+
   const APInt *C;
   if (match(Op1, m_APInt(C))) {
     const APInt *XorC;
index 9cf9c72..e37a348 100644 (file)
@@ -2171,8 +2171,8 @@ define <3 x i16> @lshr_shl_pow2_const_case1_undef3_vec(<3 x i16> %x) {
 define i8 @negate_lowbitmask(i8 %x, i8 %y) {
 ; CHECK-LABEL: @negate_lowbitmask(
 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[X:%.*]], 1
-; CHECK-NEXT:    [[N:%.*]] = sub nsw i8 0, [[A]]
-; CHECK-NEXT:    [[R:%.*]] = and i8 [[N]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[A]], 0
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i8 0, i8 [[Y:%.*]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a = and i8 %x, 1
@@ -2185,8 +2185,8 @@ define <2 x i5> @negate_lowbitmask_commute(<2 x i5> %x, <2 x i5> %p) {
 ; CHECK-LABEL: @negate_lowbitmask_commute(
 ; CHECK-NEXT:    [[Y:%.*]] = mul <2 x i5> [[P:%.*]], [[P]]
 ; CHECK-NEXT:    [[A:%.*]] = and <2 x i5> [[X:%.*]], <i5 1, i5 poison>
-; CHECK-NEXT:    [[N:%.*]] = sub <2 x i5> <i5 poison, i5 0>, [[A]]
-; CHECK-NEXT:    [[R:%.*]] = and <2 x i5> [[Y]], [[N]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i5> [[A]], <i5 poison, i5 0>
+; CHECK-NEXT:    [[R:%.*]] = select <2 x i1> [[TMP1]], <2 x i5> zeroinitializer, <2 x i5> [[Y]]
 ; CHECK-NEXT:    ret <2 x i5> [[R]]
 ;
   %y = mul <2 x i5> %p, %p ; thwart complexity-based canonicalization
@@ -2200,8 +2200,8 @@ define i8 @negate_lowbitmask_use1(i8 %x, i8 %y) {
 ; CHECK-LABEL: @negate_lowbitmask_use1(
 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[X:%.*]], 1
 ; CHECK-NEXT:    call void @use8(i8 [[A]])
-; CHECK-NEXT:    [[N:%.*]] = sub nsw i8 0, [[A]]
-; CHECK-NEXT:    [[R:%.*]] = and i8 [[N]], [[Y:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[A]], 0
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[TMP1]], i8 0, i8 [[Y:%.*]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %a = and i8 %x, 1
@@ -2211,6 +2211,8 @@ define i8 @negate_lowbitmask_use1(i8 %x, i8 %y) {
   ret i8 %r
 }
 
+; negative test
+
 define i8 @negate_lowbitmask_use2(i8 %x, i8 %y) {
 ; CHECK-LABEL: @negate_lowbitmask_use2(
 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[X:%.*]], 1