[llvm] fbb1b43 - [ValueTracking] enhance matching of umin/umax with 'not' operands

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 6 08:52:06 PDT 2020


Author: Sanjay Patel
Date: 2020-04-06T11:51:59-04:00
New Revision: fbb1b43f135a1af24cecbc7243d52fe6f85b7082

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

LOG: [ValueTracking] enhance matching of umin/umax with 'not' operands

The cmyk test is based on the known regression that resulted from:
rGf2fbdf76d8d0

This improves on the equivalent signed min/max change:
rG867f0c3c4d8c

The underlying icmp equivalence is:
  ~X pred ~Y --> Y pred X

For an icmp with constant, canonicalization results in a swapped pred:
  ~X < C -->  X > ~C

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/CodeGen/X86/vec_minmax_match.ll
    llvm/test/Transforms/InstCombine/max-of-nots.ll
    llvm/unittests/Analysis/ValueTrackingTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 01025ab71d75..4fa43a320031 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5157,6 +5157,31 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
   if (SPR.Flavor != SelectPatternFlavor::SPF_UNKNOWN)
     return SPR;
 
+  // Look through 'not' ops to find disguised min/max.
+  // (X > Y) ? ~X : ~Y ==> (~X < ~Y) ? ~X : ~Y ==> MIN(~X, ~Y)
+  // (X < Y) ? ~X : ~Y ==> (~X > ~Y) ? ~X : ~Y ==> MAX(~X, ~Y)
+  if (CmpLHS == getNotValue(TrueVal) && CmpRHS == getNotValue(FalseVal)) {
+    switch (Pred) {
+    case CmpInst::ICMP_SGT: return {SPF_SMIN, SPNB_NA, false};
+    case CmpInst::ICMP_SLT: return {SPF_SMAX, SPNB_NA, false};
+    case CmpInst::ICMP_UGT: return {SPF_UMIN, SPNB_NA, false};
+    case CmpInst::ICMP_ULT: return {SPF_UMAX, SPNB_NA, false};
+    default: break;
+    }
+  }
+
+  // (X > Y) ? ~Y : ~X ==> (~X < ~Y) ? ~Y : ~X ==> MAX(~Y, ~X)
+  // (X < Y) ? ~Y : ~X ==> (~X > ~Y) ? ~Y : ~X ==> MIN(~Y, ~X)
+  if (CmpLHS == getNotValue(FalseVal) && CmpRHS == getNotValue(TrueVal)) {
+    switch (Pred) {
+    case CmpInst::ICMP_SGT: return {SPF_SMAX, SPNB_NA, false};
+    case CmpInst::ICMP_SLT: return {SPF_SMIN, SPNB_NA, false};
+    case CmpInst::ICMP_UGT: return {SPF_UMAX, SPNB_NA, false};
+    case CmpInst::ICMP_ULT: return {SPF_UMIN, SPNB_NA, false};
+    default: break;
+    }
+  }
+
   if (Pred != CmpInst::ICMP_SGT && Pred != CmpInst::ICMP_SLT)
     return {SPF_UNKNOWN, SPNB_NA, false};
 
@@ -5174,17 +5199,6 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
       match(TrueVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS))))
     return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false};
 
-  // Look through 'not' ops to find disguised signed min/max.
-  // (X >s Y) ? ~X : ~Y ==> (~X <s ~Y) ? ~X : ~Y ==> SMIN(~X, ~Y)
-  // (X <s Y) ? ~X : ~Y ==> (~X >s ~Y) ? ~X : ~Y ==> SMAX(~X, ~Y)
-  if (CmpLHS == getNotValue(TrueVal) && CmpRHS == getNotValue(FalseVal))
-    return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false};
-
-  // (X >s Y) ? ~Y : ~X ==> (~X <s ~Y) ? ~Y : ~X ==> SMAX(~Y, ~X)
-  // (X <s Y) ? ~Y : ~X ==> (~X >s ~Y) ? ~Y : ~X ==> SMIN(~Y, ~X)
-  if (CmpLHS == getNotValue(FalseVal) && CmpRHS == getNotValue(TrueVal))
-    return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false};
-
   const APInt *C1;
   if (!match(CmpRHS, m_APInt(C1)))
     return {SPF_UNKNOWN, SPNB_NA, false};

diff  --git a/llvm/test/CodeGen/X86/vec_minmax_match.ll b/llvm/test/CodeGen/X86/vec_minmax_match.ll
index 4d6bb799fe3e..526503ce4bfe 100644
--- a/llvm/test/CodeGen/X86/vec_minmax_match.ll
+++ b/llvm/test/CodeGen/X86/vec_minmax_match.ll
@@ -219,15 +219,12 @@ define <4 x i32> @clamp_unsigned2(<4 x i32> %x) {
   ret <4 x i32> %r
 }
 
-define <4 x i32> @wrong_pred_for_smin_with_not(<4 x i32> %x) {
-; CHECK-LABEL: wrong_pred_for_smin_with_not:
+define <4 x i32> @umin_not_ops(<4 x i32> %x) {
+; CHECK-LABEL: umin_not_ops:
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    vpcmpeqd %xmm1, %xmm1, %xmm1
-; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm1
-; CHECK-NEXT:    vpmaxud {{.*}}(%rip), %xmm0, %xmm2
-; CHECK-NEXT:    vpcmpeqd %xmm2, %xmm0, %xmm0
-; CHECK-NEXT:    vmovaps {{.*#+}} xmm2 = [4294967291,4294967291,4294967291,4294967291]
-; CHECK-NEXT:    vblendvps %xmm0, %xmm1, %xmm2, %xmm0
+; CHECK-NEXT:    vpxor %xmm1, %xmm0, %xmm0
+; CHECK-NEXT:    vpminud {{.*}}(%rip), %xmm0, %xmm0
 ; CHECK-NEXT:    retq
   %not_x = xor <4 x i32> %x, <i32 -1, i32 -1, i32 -1, i32 -1>
   %cmp = icmp ugt <4 x i32> %x, <i32 4, i32 4, i32 4, i32 4>

diff  --git a/llvm/test/Transforms/InstCombine/max-of-nots.ll b/llvm/test/Transforms/InstCombine/max-of-nots.ll
index 3f4bd02b85c7..e6649d70946b 100644
--- a/llvm/test/Transforms/InstCombine/max-of-nots.ll
+++ b/llvm/test/Transforms/InstCombine/max-of-nots.ll
@@ -507,18 +507,14 @@ define void @cmyk5(i8 %r, i8 %g, i8 %b) {
 
 define void @cmyk6(i8 %r, i8 %g, i8 %b) {
 ; CHECK-LABEL: @cmyk6(
-; CHECK-NEXT:    [[NOTR:%.*]] = xor i8 [[R:%.*]], -1
-; CHECK-NEXT:    [[NOTG:%.*]] = xor i8 [[G:%.*]], -1
-; CHECK-NEXT:    [[NOTB:%.*]] = xor i8 [[B:%.*]], -1
-; CHECK-NEXT:    [[CMP_GR:%.*]] = icmp ult i8 [[G]], [[R]]
-; CHECK-NEXT:    [[CMP_BR:%.*]] = icmp ult i8 [[B]], [[R]]
-; CHECK-NEXT:    [[SEL_RB:%.*]] = select i1 [[CMP_BR]], i8 [[NOTR]], i8 [[NOTB]]
-; CHECK-NEXT:    [[CMP_BG:%.*]] = icmp ult i8 [[B]], [[G]]
-; CHECK-NEXT:    [[SEL_GB:%.*]] = select i1 [[CMP_BG]], i8 [[NOTG]], i8 [[NOTB]]
-; CHECK-NEXT:    [[K:%.*]] = select i1 [[CMP_GR]], i8 [[SEL_RB]], i8 [[SEL_GB]]
-; CHECK-NEXT:    [[CK:%.*]] = sub i8 [[NOTR]], [[K]]
-; CHECK-NEXT:    [[MK:%.*]] = sub i8 [[NOTG]], [[K]]
-; CHECK-NEXT:    [[YK:%.*]] = sub i8 [[NOTB]], [[K]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ugt i8 [[R:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 [[R]], i8 [[B]]
+; CHECK-NEXT:    [[TMP3:%.*]] = icmp ugt i8 [[TMP2]], [[G:%.*]]
+; CHECK-NEXT:    [[K_V:%.*]] = select i1 [[TMP3]], i8 [[TMP2]], i8 [[G]]
+; CHECK-NEXT:    [[K:%.*]] = xor i8 [[K_V]], -1
+; CHECK-NEXT:    [[CK:%.*]] = sub i8 [[K_V]], [[R]]
+; CHECK-NEXT:    [[MK:%.*]] = sub i8 [[K_V]], [[G]]
+; CHECK-NEXT:    [[YK:%.*]] = sub i8 [[K_V]], [[B]]
 ; CHECK-NEXT:    tail call void @use(i8 [[CK]], i8 [[MK]], i8 [[YK]], i8 [[K]])
 ; CHECK-NEXT:    ret void
 ;

diff  --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 34d9716b5fc5..775ff3a0bb45 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -519,7 +519,7 @@ TEST_F(MatchSelectPatternTest, NotNotUMin) {
       "  %A = select <2 x i1> %cmp, <2 x i8> %an, <2 x i8> %bn\n"
       "  ret <2 x i8> %A\n"
       "}\n");
-  expectPattern({SPF_UNKNOWN, SPNB_NA, false});
+  expectPattern({SPF_UMIN, SPNB_NA, false});
 }
 
 TEST_F(MatchSelectPatternTest, NotNotUMinSwap) {
@@ -531,7 +531,7 @@ TEST_F(MatchSelectPatternTest, NotNotUMinSwap) {
       "  %A = select i1 %cmp, i8 %bn, i8 %an\n"
       "  ret i8 %A\n"
       "}\n");
-  expectPattern({SPF_UNKNOWN, SPNB_NA, false});
+  expectPattern({SPF_UMIN, SPNB_NA, false});
 }
 
 TEST_F(MatchSelectPatternTest, NotNotUMax) {
@@ -543,7 +543,7 @@ TEST_F(MatchSelectPatternTest, NotNotUMax) {
       "  %A = select <2 x i1> %cmp, <2 x i8> %an, <2 x i8> %bn\n"
       "  ret <2 x i8> %A\n"
       "}\n");
-  expectPattern({SPF_UNKNOWN, SPNB_NA, false});
+  expectPattern({SPF_UMAX, SPNB_NA, false});
 }
 
 TEST_F(MatchSelectPatternTest, NotNotUMaxSwap) {
@@ -555,7 +555,7 @@ TEST_F(MatchSelectPatternTest, NotNotUMaxSwap) {
       "  %A = select i1 %cmp, i8 %bn, i8 %an\n"
       "  ret i8 %A\n"
       "}\n");
-  expectPattern({SPF_UNKNOWN, SPNB_NA, false});
+  expectPattern({SPF_UMAX, SPNB_NA, false});
 }
 
 TEST_F(MatchSelectPatternTest, NotNotEq) {


        


More information about the llvm-commits mailing list