[llvm] r321882 - [InstCombine] add folds for min(~a, b) --> ~max(a, b)

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 5 11:01:17 PST 2018


Author: spatel
Date: Fri Jan  5 11:01:17 2018
New Revision: 321882

URL: http://llvm.org/viewvc/llvm-project?rev=321882&view=rev
Log:
[InstCombine] add folds for min(~a, b) --> ~max(a, b)

Besides the bug of omitting the inverse transform of max(~a, ~b) --> ~min(a, b),
the use checking and operand creation were off. We were potentially creating 
repeated identical instructions of existing values. This led to infinite
looping after I added the extra folds.

By using the simpler m_Not matcher and not creating new 'not' ops for a and b,
we avoid that problem. It's possible that not using IsFreeToInvert() here is
more limiting than the simpler matcher, but there are no tests for anything
more exotic. It's also possible that we should relax the use checking further
to handle a case like PR35834:
https://bugs.llvm.org/show_bug.cgi?id=35834
...but we can make that a follow-up if it is needed. 

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp?rev=321882&r1=321881&r2=321882&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineSelect.cpp Fri Jan  5 11:01:17 2018
@@ -1551,6 +1551,18 @@ Instruction *InstCombiner::visitSelectIn
         Value *NewCast = Builder.CreateCast(CastOp, NewSI, SelType);
         return replaceInstUsesWith(SI, NewCast);
       }
+
+      // MAX(~a, ~b) -> ~MIN(a, b)
+      // MIN(~a, ~b) -> ~MAX(a, b)
+      Value *A, *B;
+      if (match(LHS, m_Not(m_Value(A))) && LHS->getNumUses() <= 2 &&
+          match(RHS, m_Not(m_Value(B))) && RHS->getNumUses() <= 2) {
+        CmpInst::Predicate InvertedPred =
+            getCmpPredicateForMinMax(getInverseMinMaxSelectPattern(SPF));
+        Value *InvertedCmp = Builder.CreateICmp(InvertedPred, A, B);
+        Value *NewSel = Builder.CreateSelect(InvertedCmp, A, B);
+        return BinaryOperator::CreateNot(NewSel);
+      }
     }
 
     if (SPF) {
@@ -1570,28 +1582,6 @@ Instruction *InstCombiner::visitSelectIn
           return R;
     }
 
-    // MAX(~a, ~b) -> ~MIN(a, b)
-    if ((SPF == SPF_SMAX || SPF == SPF_UMAX) &&
-        IsFreeToInvert(LHS, LHS->hasNUses(2)) &&
-        IsFreeToInvert(RHS, RHS->hasNUses(2))) {
-      // For this transform to be profitable, we need to eliminate at least two
-      // 'not' instructions if we're going to add one 'not' instruction.
-      int NumberOfNots =
-          (LHS->hasNUses(2) && match(LHS, m_Not(m_Value()))) +
-          (RHS->hasNUses(2) && match(RHS, m_Not(m_Value()))) +
-          (SI.hasOneUse() && match(*SI.user_begin(), m_Not(m_Value())));
-
-      if (NumberOfNots >= 2) {
-        Value *NewLHS = Builder.CreateNot(LHS);
-        Value *NewRHS = Builder.CreateNot(RHS);
-        Value *NewCmp = SPF == SPF_SMAX ? Builder.CreateICmpSLT(NewLHS, NewRHS)
-                                        : Builder.CreateICmpULT(NewLHS, NewRHS);
-        Value *NewSI =
-            Builder.CreateNot(Builder.CreateSelect(NewCmp, NewLHS, NewRHS));
-        return replaceInstUsesWith(SI, NewSI);
-      }
-    }
-
     // TODO.
     // ABS(-X) -> ABS(X)
   }

Modified: llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll?rev=321882&r1=321881&r2=321882&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/max-of-nots.ll Fri Jan  5 11:01:17 2018
@@ -1,6 +1,34 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -instcombine < %s | FileCheck %s
 
+define <2 x i32> @umin_of_nots(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @umin_of_nots(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt <2 x i32> %x, %y
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> %x, <2 x i32> %y
+; CHECK-NEXT:    [[MIN:%.*]] = xor <2 x i32> [[TMP2]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[MIN]]
+;
+  %notx = xor <2 x i32> %x, <i32 -1, i32 -1>
+  %noty = xor <2 x i32> %y, <i32 -1, i32 -1>
+  %cmp = icmp ult <2 x i32> %notx, %noty
+  %min = select <2 x i1> %cmp, <2 x i32> %notx, <2 x i32> %noty
+  ret <2 x i32> %min
+}
+
+define <2 x i32> @smin_of_nots(<2 x i32> %x, <2 x i32> %y) {
+; CHECK-LABEL: @smin_of_nots(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt <2 x i32> %x, %y
+; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> %x, <2 x i32> %y
+; CHECK-NEXT:    [[MIN:%.*]] = xor <2 x i32> [[TMP2]], <i32 -1, i32 -1>
+; CHECK-NEXT:    ret <2 x i32> [[MIN]]
+;
+  %notx = xor <2 x i32> %x, <i32 -1, i32 -1>
+  %noty = xor <2 x i32> %y, <i32 -1, i32 -1>
+  %cmp = icmp sle <2 x i32> %notx, %noty
+  %min = select <2 x i1> %cmp, <2 x i32> %notx, <2 x i32> %noty
+  ret <2 x i32> %min
+}
+
 define i32 @compute_min_2(i32 %x, i32 %y) {
 ; CHECK-LABEL: @compute_min_2(
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 %x, %y




More information about the llvm-commits mailing list