[llvm] r320640 - [EarlyCSE] recognize commuted and swapped variants of min/max as equivalent (PR35642)

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 13 13:58:15 PST 2017


Author: spatel
Date: Wed Dec 13 13:58:15 2017
New Revision: 320640

URL: http://llvm.org/viewvc/llvm-project?rev=320640&view=rev
Log:
[EarlyCSE] recognize commuted and swapped variants of min/max as equivalent (PR35642)

As shown in:
https://bugs.llvm.org/show_bug.cgi?id=35642
...we can have different forms of min/max, so we should recognize those here in EarlyCSE 
similar to how we already handle binops and compares that can commute.

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

Modified:
    llvm/trunk/lib/Transforms/Scalar/EarlyCSE.cpp
    llvm/trunk/test/Transforms/EarlyCSE/commute.ll

Modified: llvm/trunk/lib/Transforms/Scalar/EarlyCSE.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/EarlyCSE.cpp?rev=320640&r1=320639&r2=320640&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/EarlyCSE.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/EarlyCSE.cpp Wed Dec 13 13:58:15 2017
@@ -27,6 +27,7 @@
 #include "llvm/Analysis/MemorySSAUpdater.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
@@ -142,6 +143,19 @@ unsigned DenseMapInfo<SimpleValue>::getH
     return hash_combine(Inst->getOpcode(), Pred, LHS, RHS);
   }
 
+  // Hash min/max (cmp + select) to allow for commuted operands, non-canonical
+  // compare predicate (eg, the compare for smin may use 'sgt' rather than
+  // 'slt'), and non-canonical operands in the compare.
+  Value *A, *B;
+  SelectPatternFlavor SPF = matchSelectPattern(Inst, A, B).Flavor;
+  // TODO: We should also detect abs and FP min/max.
+  if (SPF == SPF_SMIN || SPF == SPF_SMAX ||
+      SPF == SPF_UMIN || SPF == SPF_UMAX) {
+    if (A > B)
+      std::swap(A, B);
+    return hash_combine(Inst->getOpcode(), SPF, A, B);
+  }
+
   if (CastInst *CI = dyn_cast<CastInst>(Inst))
     return hash_combine(CI->getOpcode(), CI->getType(), CI->getOperand(0));
 
@@ -200,6 +214,19 @@ bool DenseMapInfo<SimpleValue>::isEqual(
            LHSCmp->getSwappedPredicate() == RHSCmp->getPredicate();
   }
 
+  // Min/max can occur with commuted operands, non-canonical predicates, and/or
+  // non-canonical operands.
+  Value *LHSA, *LHSB;
+  SelectPatternFlavor LSPF = matchSelectPattern(LHSI, LHSA, LHSB).Flavor;
+  // TODO: We should also detect abs and FP min/max.
+  if (LSPF == SPF_SMIN || LSPF == SPF_SMAX ||
+      LSPF == SPF_UMIN || LSPF == SPF_UMAX) {
+    Value *RHSA, *RHSB;
+    SelectPatternFlavor RSPF = matchSelectPattern(RHSI, RHSA, RHSB).Flavor;
+    return (LSPF == RSPF && ((LHSA == RHSA && LHSB == RHSB) ||
+                             (LHSA == RHSB && LHSB == RHSA)));
+  }
+
   return false;
 }
 

Modified: llvm/trunk/test/Transforms/EarlyCSE/commute.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/EarlyCSE/commute.ll?rev=320640&r1=320639&r2=320640&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/EarlyCSE/commute.ll (original)
+++ llvm/trunk/test/Transforms/EarlyCSE/commute.ll Wed Dec 13 13:58:15 2017
@@ -78,8 +78,7 @@ define i8 @smin_commute(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %b, %a
 ; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT:    [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT:    [[R:%.*]] = mul i8 [[M1]], [[M2]]
+; CHECK-NEXT:    [[R:%.*]] = mul i8 [[M1]], [[M1]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %cmp1 = icmp slt i8 %a, %b
@@ -97,9 +96,7 @@ define i1 @smin_swapped(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i8 %a, %b
 ; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
-; CHECK-NEXT:    [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[M2]], [[M1]]
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %cmp1 = icmp sgt i8 %a, %b
   %cmp2 = icmp slt i8 %a, %b
@@ -114,9 +111,7 @@ define i8 @smax_commute(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp sgt i8 %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %b, %a
 ; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT:    [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT:    [[R:%.*]] = urem i8 [[M2]], [[M1]]
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 0
 ;
   %cmp1 = icmp sgt i8 %a, %b
   %cmp2 = icmp sgt i8 %b, %a
@@ -131,9 +126,7 @@ define i8 @smax_swapped(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 %a, %b
 ; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
-; CHECK-NEXT:    [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b
-; CHECK-NEXT:    [[R:%.*]] = sdiv i8 [[M1]], [[M2]]
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 1
 ;
   %cmp1 = icmp slt i8 %a, %b
   %cmp2 = icmp sgt i8 %a, %b
@@ -148,9 +141,7 @@ define i8 @umin_commute(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 %b, %a
 ; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT:    [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT:    [[R:%.*]] = sub i8 [[M2]], [[M1]]
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 0
 ;
   %cmp1 = icmp ult i8 %a, %b
   %cmp2 = icmp ult i8 %b, %a
@@ -167,9 +158,7 @@ define <2 x i8> @umin_swapped(<2 x i8> %
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt <2 x i8> %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult <2 x i8> %a, %b
 ; CHECK-NEXT:    [[M1:%.*]] = select <2 x i1> [[CMP1]], <2 x i8> %b, <2 x i8> %a
-; CHECK-NEXT:    [[M2:%.*]] = select <2 x i1> [[CMP2]], <2 x i8> %a, <2 x i8> %b
-; CHECK-NEXT:    [[R:%.*]] = sub <2 x i8> [[M2]], [[M1]]
-; CHECK-NEXT:    ret <2 x i8> [[R]]
+; CHECK-NEXT:    ret <2 x i8> zeroinitializer
 ;
   %cmp1 = icmp ugt <2 x i8> %a, %b
   %cmp2 = icmp ult <2 x i8> %a, %b
@@ -184,9 +173,7 @@ define i8 @umax_commute(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %b, %a
 ; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 %a, i8 %b
-; CHECK-NEXT:    [[M2:%.*]] = select i1 [[CMP2]], i8 %b, i8 %a
-; CHECK-NEXT:    [[R:%.*]] = udiv i8 [[M1]], [[M2]]
-; CHECK-NEXT:    ret i8 [[R]]
+; CHECK-NEXT:    ret i8 1
 ;
   %cmp1 = icmp ugt i8 %a, %b
   %cmp2 = icmp ugt i8 %b, %a
@@ -201,8 +188,7 @@ define i8 @umax_swapped(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i8 %a, %b
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i8 %a, %b
 ; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 %b, i8 %a
-; CHECK-NEXT:    [[M2:%.*]] = select i1 [[CMP2]], i8 %a, i8 %b
-; CHECK-NEXT:    [[R:%.*]] = add i8 [[M2]], [[M1]]
+; CHECK-NEXT:    [[R:%.*]] = add i8 [[M1]], [[M1]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %cmp1 = icmp ult i8 %a, %b
@@ -213,3 +199,22 @@ define i8 @umax_swapped(i8 %a, i8 %b) {
   ret i8 %r
 }
 
+; Min/max may exist with non-canonical operands. Value tracking can match those.
+
+define i8 @smax_nsw(i8 %a, i8 %b) {
+; CHECK-LABEL: @smax_nsw(
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i8 %a, %b
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i8 %a, %b
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i8 [[SUB]], 0
+; CHECK-NEXT:    [[M1:%.*]] = select i1 [[CMP1]], i8 0, i8 [[SUB]]
+; CHECK-NEXT:    ret i8 0
+;
+  %sub = sub nsw i8 %a, %b
+  %cmp1 = icmp slt i8 %a, %b
+  %cmp2 = icmp sgt i8 %sub, 0
+  %m1 = select i1 %cmp1, i8 0, i8 %sub
+  %m2 = select i1 %cmp2, i8 %sub, i8 0
+  %r = sub i8 %m2, %m1
+  ret i8 %r
+}
+




More information about the llvm-commits mailing list