[llvm] 682f0b3 - [InstCombine] use select-of-constants with set/clear bit mask patterns

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Sun May 3 06:49:42 PDT 2020


Author: Sanjay Patel
Date: 2020-05-03T09:44:43-04:00
New Revision: 682f0b366be266b9473507f12be21021e3e4912f

URL: https://github.com/llvm/llvm-project/commit/682f0b366be266b9473507f12be21021e3e4912f
DIFF: https://github.com/llvm/llvm-project/commit/682f0b366be266b9473507f12be21021e3e4912f.diff

LOG: [InstCombine] use select-of-constants with set/clear bit mask patterns

Cond ? (X & ~C) : (X | C) --> (X & ~C) | (Cond ? 0 : C)
Cond ? (X | C) : (X & ~C) --> (X & ~C) | (Cond ? C : 0)

The select-of-constants form results in better codegen.
There's an existing test diff that shows a transform that
results in an extra IR instruction, but that's an existing
problem.

This is motivated by code seen in LLVM itself - see PR37581:
https://bugs.llvm.org/show_bug.cgi?id=37581

define i8 @src(i8 %x, i8 %C, i1 %b)  {
  %notC = xor i8 %C, -1
  %and = and i8 %x, %notC
  %or = or i8 %x, %C
  %cond = select i1 %b, i8 %or, i8 %and
  ret i8 %cond
}

define i8 @tgt(i8 %x, i8 %C, i1 %b)  {
  %notC = xor i8 %C, -1
  %and = and i8 %x, %notC
  %mul = select i1 %b, i8 %C, i8 0
  %or = or i8 %mul, %and
  ret i8 %or
}

http://volta.cs.utah.edu:8080/z/Vt2WVm

Differential Revision: https://reviews.llvm.org/D78880

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/cast.ll
    llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index b9d3274219d2..a43a026f05e2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -671,6 +671,38 @@ static Value *foldSelectICmpAndOr(const ICmpInst *IC, Value *TrueVal,
   return Builder.CreateOr(V, Y);
 }
 
+/// Canonicalize a set or clear of a masked set of constant bits to
+/// select-of-constants form.
+static Instruction *foldSetClearBits(SelectInst &Sel,
+                                     InstCombiner::BuilderTy &Builder) {
+  Value *Cond = Sel.getCondition();
+  Value *T = Sel.getTrueValue();
+  Value *F = Sel.getFalseValue();
+  Type *Ty = Sel.getType();
+  Value *X;
+  const APInt *NotC, *C;
+
+  // Cond ? (X & ~C) : (X | C) --> (X & ~C) | (Cond ? 0 : C)
+  if (match(T, m_And(m_Value(X), m_APInt(NotC))) &&
+      match(F, m_OneUse(m_Or(m_Specific(X), m_APInt(C)))) && *NotC == ~(*C)) {
+    Constant *Zero = ConstantInt::getNullValue(Ty);
+    Constant *OrC = ConstantInt::get(Ty, *C);
+    Value *NewSel = Builder.CreateSelect(Cond, Zero, OrC, "masksel", &Sel);
+    return BinaryOperator::CreateOr(T, NewSel);
+  }
+
+  // Cond ? (X | C) : (X & ~C) --> (X & ~C) | (Cond ? C : 0)
+  if (match(F, m_And(m_Value(X), m_APInt(NotC))) &&
+      match(T, m_OneUse(m_Or(m_Specific(X), m_APInt(C)))) && *NotC == ~(*C)) {
+    Constant *Zero = ConstantInt::getNullValue(Ty);
+    Constant *OrC = ConstantInt::get(Ty, *C);
+    Value *NewSel = Builder.CreateSelect(Cond, OrC, Zero, "masksel", &Sel);
+    return BinaryOperator::CreateOr(F, NewSel);
+  }
+
+  return nullptr;
+}
+
 /// Transform patterns such as (a > b) ? a - b : 0 into usub.sat(a, b).
 /// There are 8 commuted/swapped variants of this pattern.
 /// TODO: Also support a - UMIN(a,b) patterns.
@@ -2553,6 +2585,8 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
     return Add;
   if (Instruction *Add = foldOverflowingAddSubSelect(SI, Builder))
     return Add;
+  if (Instruction *Or = foldSetClearBits(SI, Builder))
+    return Or;
 
   // Turn (select C, (op X, Y), (op X, Z)) -> (op X, (select C, Y, Z))
   auto *TI = dyn_cast<Instruction>(TrueVal);

diff  --git a/llvm/test/Transforms/InstCombine/cast.ll b/llvm/test/Transforms/InstCombine/cast.ll
index d85286b46029..6ecd0e398654 100644
--- a/llvm/test/Transforms/InstCombine/cast.ll
+++ b/llvm/test/Transforms/InstCombine/cast.ll
@@ -666,9 +666,10 @@ define i64 @test50(i64 %x) {
 define i64 @test51(i64 %A, i1 %cond) {
 ; ALL-LABEL: @test51(
 ; ALL-NEXT:    [[C:%.*]] = and i64 [[A:%.*]], 4294967294
-; ALL-NEXT:    [[D:%.*]] = or i64 [[A]], 1
-; ALL-NEXT:    [[E:%.*]] = select i1 [[COND:%.*]], i64 [[C]], i64 [[D]]
-; ALL-NEXT:    [[SEXT:%.*]] = shl i64 [[E]], 32
+; ALL-NEXT:    [[NOT_COND:%.*]] = xor i1 [[COND:%.*]], true
+; ALL-NEXT:    [[MASKSEL:%.*]] = zext i1 [[NOT_COND]] to i64
+; ALL-NEXT:    [[E:%.*]] = or i64 [[C]], [[MASKSEL]]
+; ALL-NEXT:    [[SEXT:%.*]] = shl nuw i64 [[E]], 32
 ; ALL-NEXT:    [[F:%.*]] = ashr exact i64 [[SEXT]], 32
 ; ALL-NEXT:    ret i64 [[F]]
 ;

diff  --git a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
index f0aeeceb8a7e..d46227d74db3 100644
--- a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
+++ b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
@@ -1456,8 +1456,8 @@ define i32 @shift_xor_multiuse_cmp_and(i32 %x, i32 %y, i32 %z, i32 %w) {
 define i8 @set_bits(i8 %x, i1 %b)  {
 ; CHECK-LABEL: @set_bits(
 ; CHECK-NEXT:    [[AND:%.*]] = and i8 [[X:%.*]], -6
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X]], 5
-; CHECK-NEXT:    [[COND:%.*]] = select i1 [[B:%.*]], i8 [[OR]], i8 [[AND]]
+; CHECK-NEXT:    [[MASKSEL:%.*]] = select i1 [[B:%.*]], i8 5, i8 0
+; CHECK-NEXT:    [[COND:%.*]] = or i8 [[AND]], [[MASKSEL]]
 ; CHECK-NEXT:    ret i8 [[COND]]
 ;
   %and = and i8 %x, 250
@@ -1466,6 +1466,8 @@ define i8 @set_bits(i8 %x, i1 %b)  {
   ret i8 %cond
 }
 
+; Negative test
+
 define i8 @set_bits_not_inverse_constant(i8 %x, i1 %b)  {
 ; CHECK-LABEL: @set_bits_not_inverse_constant(
 ; CHECK-NEXT:    [[AND:%.*]] = and i8 [[X:%.*]], -6
@@ -1483,8 +1485,8 @@ define i8 @set_bits_extra_use1(i8 %x, i1 %b)  {
 ; CHECK-LABEL: @set_bits_extra_use1(
 ; CHECK-NEXT:    [[AND:%.*]] = and i8 [[X:%.*]], -6
 ; CHECK-NEXT:    call void @use(i8 [[AND]])
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[X]], 5
-; CHECK-NEXT:    [[COND:%.*]] = select i1 [[B:%.*]], i8 [[OR]], i8 [[AND]]
+; CHECK-NEXT:    [[MASKSEL:%.*]] = select i1 [[B:%.*]], i8 5, i8 0
+; CHECK-NEXT:    [[COND:%.*]] = or i8 [[AND]], [[MASKSEL]]
 ; CHECK-NEXT:    ret i8 [[COND]]
 ;
   %and = and i8 %x, 250
@@ -1494,6 +1496,8 @@ define i8 @set_bits_extra_use1(i8 %x, i1 %b)  {
   ret i8 %cond
 }
 
+; Negative test
+
 define i8 @set_bits_extra_use2(i8 %x, i1 %b)  {
 ; CHECK-LABEL: @set_bits_extra_use2(
 ; CHECK-NEXT:    [[AND:%.*]] = and i8 [[X:%.*]], -6
@@ -1512,8 +1516,8 @@ define i8 @set_bits_extra_use2(i8 %x, i1 %b)  {
 define <2 x i8> @clear_bits(<2 x i8> %x, <2 x i1> %b)  {
 ; CHECK-LABEL: @clear_bits(
 ; CHECK-NEXT:    [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 37, i8 37>
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[X]], <i8 -38, i8 -38>
-; CHECK-NEXT:    [[COND:%.*]] = select <2 x i1> [[B:%.*]], <2 x i8> [[AND]], <2 x i8> [[OR]]
+; CHECK-NEXT:    [[MASKSEL:%.*]] = select <2 x i1> [[B:%.*]], <2 x i8> zeroinitializer, <2 x i8> <i8 -38, i8 -38>
+; CHECK-NEXT:    [[COND:%.*]] = or <2 x i8> [[AND]], [[MASKSEL]]
 ; CHECK-NEXT:    ret <2 x i8> [[COND]]
 ;
   %and = and <2 x i8> %x, <i8 37, i8 37>
@@ -1522,6 +1526,8 @@ define <2 x i8> @clear_bits(<2 x i8> %x, <2 x i1> %b)  {
   ret <2 x i8> %cond
 }
 
+; Negative test
+
 define <2 x i8> @clear_bits_not_inverse_constant(<2 x i8> %x, <2 x i1> %b)  {
 ; CHECK-LABEL: @clear_bits_not_inverse_constant(
 ; CHECK-NEXT:    [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 undef, i8 37>
@@ -1539,8 +1545,8 @@ define <2 x i8> @clear_bits_extra_use1(<2 x i8> %x, i1 %b)  {
 ; CHECK-LABEL: @clear_bits_extra_use1(
 ; CHECK-NEXT:    [[AND:%.*]] = and <2 x i8> [[X:%.*]], <i8 37, i8 37>
 ; CHECK-NEXT:    call void @use_vec(<2 x i8> [[AND]])
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[X]], <i8 -38, i8 -38>
-; CHECK-NEXT:    [[COND:%.*]] = select i1 [[B:%.*]], <2 x i8> [[AND]], <2 x i8> [[OR]]
+; CHECK-NEXT:    [[MASKSEL:%.*]] = select i1 [[B:%.*]], <2 x i8> zeroinitializer, <2 x i8> <i8 -38, i8 -38>
+; CHECK-NEXT:    [[COND:%.*]] = or <2 x i8> [[AND]], [[MASKSEL]]
 ; CHECK-NEXT:    ret <2 x i8> [[COND]]
 ;
   %and = and <2 x i8> %x, <i8 37, i8 37>
@@ -1550,6 +1556,8 @@ define <2 x i8> @clear_bits_extra_use1(<2 x i8> %x, i1 %b)  {
   ret <2 x i8> %cond
 }
 
+; Negative test
+
 define i8 @clear_bits_extra_use2(i8 %x, i1 %b)  {
 ; CHECK-LABEL: @clear_bits_extra_use2(
 ; CHECK-NEXT:    [[AND:%.*]] = and i8 [[X:%.*]], -6


        


More information about the llvm-commits mailing list