[llvm] r330001 - [InstCombine]: foldSelectICmpAndAnd(): and is commutative

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 13 02:57:58 PDT 2018


Author: lebedevri
Date: Fri Apr 13 02:57:57 2018
New Revision: 330001

URL: http://llvm.org/viewvc/llvm-project?rev=330001&view=rev
Log:
[InstCombine]: foldSelectICmpAndAnd(): and is commutative

Summary:
The fold added in D45108 did not account for the fact that
the and instruction is commutative, and if the mask is a variable,
the mask variable and the fold variable may be swapped.

I have noticed this by accident when looking into [[ https://bugs.llvm.org/show_bug.cgi?id=6773 | PR6773 ]]

This extends/generalizes that fold, so it is handled too.

Reviewers: spatel, craig.topper

Reviewed By: spatel

Subscribers: llvm-commits

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

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/trunk/test/Transforms/InstCombine/select-of-bittest.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp?rev=330001&r1=330000&r2=330001&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp Fri Apr 13 02:57:57 2018
@@ -402,39 +402,35 @@ Instruction *InstCombiner::foldSelectInt
 ///   zext (icmp ne i32 (and X, (or Y, (shl 1, Z))), 0)
 /// Note:
 ///   Z may be 0 if lshr is missing.
-/// Worst case scenario is that we will replace 5 instructions with 5 different
+/// Worst-case scenario is that we will replace 5 instructions with 5 different
 /// instructions, but we got rid of select.
-static Instruction *foldSelectICmpAndAnd(Type *SelType, const ICmpInst *IC,
-                                         Value *TrueVal, Value *FalseVal,
+static Instruction *foldSelectICmpAndAnd(Type *SelType, const ICmpInst *Cmp,
+                                         Value *TVal, Value *FVal,
                                          InstCombiner::BuilderTy &Builder) {
-  if (!(IC->hasOneUse() && IC->getOperand(0)->hasOneUse()))
+  if (!(Cmp->hasOneUse() && Cmp->getOperand(0)->hasOneUse() &&
+        Cmp->getPredicate() == ICmpInst::ICMP_EQ &&
+        match(Cmp->getOperand(1), m_Zero()) && match(FVal, m_One())))
     return nullptr;
 
-  Value *X, *Y;
-  ICmpInst::Predicate EqPred;
-  if (!(match(IC, m_ICmp(EqPred, m_And(m_Value(X), m_Value(Y)), m_Zero())) &&
-        ICmpInst::Predicate::ICMP_EQ == EqPred && match(FalseVal, m_One())))
-    return nullptr;
-
-  // The TrueVal has general form of:
-  //   and %B, 1
+  // The TrueVal has general form of:  and %B, 1
   Value *B;
-  if (!match(TrueVal, m_OneUse(m_And(m_Value(B), m_One()))))
+  if (!match(TVal, m_OneUse(m_And(m_Value(B), m_One()))))
     return nullptr;
 
-  // Where %B can be one of:
-  //        %X
-  // or
-  //   lshr %X, %Z
-  // Where %Z may or may not be a constant.
-  Value *MaskB, *Z;
-  if (match(B, m_Specific(X))) {
-    MaskB = ConstantInt::get(SelType, 1);
-  } else if (match(B, m_OneUse(m_LShr(m_Specific(X), m_Value(Z))))) {
-    MaskB = Builder.CreateShl(ConstantInt::get(SelType, 1), Z);
-  } else
+  // Where %B may be optionally shifted:  lshr %X, %Z.
+  Value *X, *Z;
+  const bool HasShift = match(B, m_OneUse(m_LShr(m_Value(X), m_Value(Z))));
+  if (!HasShift)
+    X = B;
+
+  Value *Y;
+  if (!match(Cmp->getOperand(0), m_c_And(m_Specific(X), m_Value(Y))))
     return nullptr;
 
+  // ((X & Y) == 0) ? ((X >> Z) & 1) : 1 --> (X & (Y | (1 << Z))) != 0
+  // ((X & Y) == 0) ? (X & 1) : 1 --> (X & (Y | 1)) != 0
+  Constant *One = ConstantInt::get(SelType, 1);
+  Value *MaskB = HasShift ? Builder.CreateShl(One, Z) : One;
   Value *FullMask = Builder.CreateOr(Y, MaskB);
   Value *MaskedX = Builder.CreateAnd(X, FullMask);
   Value *ICmpNeZero = Builder.CreateIsNotNull(MaskedX);

Modified: llvm/trunk/test/Transforms/InstCombine/select-of-bittest.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/select-of-bittest.ll?rev=330001&r1=330000&r2=330001&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/select-of-bittest.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/select-of-bittest.ll Fri Apr 13 02:57:57 2018
@@ -177,11 +177,10 @@ define i32 @f_var0(i32 %arg, i32 %arg1)
 ; Should be exactly as the previous one
 define i32 @f_var0_commutative_and(i32 %arg, i32 %arg1) {
 ; CHECK-LABEL: @f_var0_commutative_and(
-; CHECK-NEXT:    [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP]], 0
-; CHECK-NEXT:    [[TMP3:%.*]] = lshr i32 [[ARG]], 1
-; CHECK-NEXT:    [[TMP4:%.*]] = and i32 [[TMP3]], 1
-; CHECK-NEXT:    [[TMP5:%.*]] = select i1 [[TMP2]], i32 [[TMP4]], i32 1
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 2
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0
+; CHECK-NEXT:    [[TMP5:%.*]] = zext i1 [[TMP3]] to i32
 ; CHECK-NEXT:    ret i32 [[TMP5]]
 ;
   %tmp = and i32 %arg1, %arg ; in different order
@@ -259,10 +258,10 @@ define i32 @f_var1(i32 %arg, i32 %arg1)
 ; Should be exactly as the previous one
 define i32 @f_var1_commutative_and(i32 %arg, i32 %arg1) {
 ; CHECK-LABEL: @f_var1_commutative_and(
-; CHECK-NEXT:    [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]]
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i32 [[TMP]], 0
-; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[ARG]], 1
-; CHECK-NEXT:    [[TMP4:%.*]] = select i1 [[TMP2]], i32 [[TMP3]], i32 1
+; CHECK-NEXT:    [[TMP1:%.*]] = or i32 [[ARG1:%.*]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], [[ARG:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0
+; CHECK-NEXT:    [[TMP4:%.*]] = zext i1 [[TMP3]] to i32
 ; CHECK-NEXT:    ret i32 [[TMP4]]
 ;
   %tmp = and i32 %arg1, %arg ; in different order
@@ -398,11 +397,11 @@ define i32 @f_var3(i32 %arg, i32 %arg1,
 ; Should be exactly as the previous one
 define i32 @f_var3_commutative_and(i32 %arg, i32 %arg1, i32 %arg2) {
 ; CHECK-LABEL: @f_var3_commutative_and(
-; CHECK-NEXT:    [[TMP:%.*]] = and i32 [[ARG1:%.*]], [[ARG:%.*]]
-; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i32 [[TMP]], 0
-; CHECK-NEXT:    [[TMP4:%.*]] = lshr i32 [[ARG]], [[ARG2:%.*]]
-; CHECK-NEXT:    [[TMP5:%.*]] = and i32 [[TMP4]], 1
-; CHECK-NEXT:    [[TMP6:%.*]] = select i1 [[TMP3]], i32 [[TMP5]], i32 1
+; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 1, [[ARG2:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[ARG1:%.*]]
+; CHECK-NEXT:    [[TMP3:%.*]] = and i32 [[TMP2]], [[ARG:%.*]]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0
+; CHECK-NEXT:    [[TMP6:%.*]] = zext i1 [[TMP4]] to i32
 ; CHECK-NEXT:    ret i32 [[TMP6]]
 ;
   %tmp = and i32 %arg1, %arg ; in different order




More information about the llvm-commits mailing list