Skip to content

Commit

Permalink
Improve clamp recognition in ValueTracking.
Browse files Browse the repository at this point in the history
Summary:
ValueTracking was recognizing not all variations of clamp. Swapping of
true value and false value of select was added to fix this problem. This
change breaks the canonical form of cmp inside the matchMinMax function,
that is why additional checks for compare predicates is needed. Added
corresponding test cases.

Reviewers: spatel

Subscribers: llvm-commits

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

Patch by: Artur Gainullin <artur.gainullin@intel.com>

llvm-svn: 315992
  • Loading branch information
Nikolai Bozhenov committed Oct 17, 2017
1 parent a18b0b1 commit 346f432
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 22 deletions.
45 changes: 33 additions & 12 deletions llvm/lib/Analysis/ValueTracking.cpp
Expand Up @@ -4083,6 +4083,14 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
Value *CmpLHS, Value *CmpRHS,
Value *TrueVal, Value *FalseVal,
Value *&LHS, Value *&RHS) {
assert(!ICmpInst::isEquality(Pred) && "Expected not equality predicate only!");

// First, check if select has inverse order of what we will check below:
if (CmpRHS == FalseVal) {
std::swap(TrueVal, FalseVal);
Pred = CmpInst::getInversePredicate(Pred);
}

// Assume success. If there's no match, callers should not use these anyway.
LHS = TrueVal;
RHS = FalseVal;
Expand All @@ -4095,41 +4103,49 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,

// (X <s C1) ? C1 : SMIN(X, C2) ==> SMAX(SMIN(X, C2), C1)
if (match(FalseVal, m_SMin(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->slt(*C2) && Pred == CmpInst::ICMP_SLT)
C1->slt(*C2) &&
(Pred == CmpInst::ICMP_SLT || Pred == CmpInst::ICMP_SLE))
return {SPF_SMAX, SPNB_NA, false};

// (X >s C1) ? C1 : SMAX(X, C2) ==> SMIN(SMAX(X, C2), C1)
if (match(FalseVal, m_SMax(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->sgt(*C2) && Pred == CmpInst::ICMP_SGT)
C1->sgt(*C2) &&
(Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE))
return {SPF_SMIN, SPNB_NA, false};

// (X <u C1) ? C1 : UMIN(X, C2) ==> UMAX(UMIN(X, C2), C1)
if (match(FalseVal, m_UMin(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->ult(*C2) && Pred == CmpInst::ICMP_ULT)
C1->ult(*C2) &&
(Pred == CmpInst::ICMP_ULT || Pred == CmpInst::ICMP_ULE))
return {SPF_UMAX, SPNB_NA, false};

// (X >u C1) ? C1 : UMAX(X, C2) ==> UMIN(UMAX(X, C2), C1)
if (match(FalseVal, m_UMax(m_Specific(CmpLHS), m_APInt(C2))) &&
C1->ugt(*C2) && Pred == CmpInst::ICMP_UGT)
C1->ugt(*C2) &&
(Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_UGE))
return {SPF_UMIN, SPNB_NA, false};
}

if (Pred != CmpInst::ICMP_SGT && Pred != CmpInst::ICMP_SLT)
if (!CmpInst::isSigned(Pred))
return {SPF_UNKNOWN, SPNB_NA, false};

// Z = X -nsw Y
// (X >s Y) ? 0 : Z ==> (Z >s 0) ? 0 : Z ==> SMIN(Z, 0)
// (X <s Y) ? 0 : Z ==> (Z <s 0) ? 0 : Z ==> SMAX(Z, 0)
if (match(TrueVal, m_Zero()) &&
match(FalseVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS))))
return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false};
return {(Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE) ? SPF_SMIN
: SPF_SMAX,
SPNB_NA, false};

// Z = X -nsw Y
// (X >s Y) ? Z : 0 ==> (Z >s 0) ? Z : 0 ==> SMAX(Z, 0)
// (X <s Y) ? Z : 0 ==> (Z <s 0) ? Z : 0 ==> SMIN(Z, 0)
if (match(FalseVal, m_Zero()) &&
match(TrueVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS))))
return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false};
return {(Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE) ? SPF_SMAX
: SPF_SMIN,
SPNB_NA, false};

if (!match(CmpRHS, m_APInt(C1)))
return {SPF_UNKNOWN, SPNB_NA, false};
Expand All @@ -4141,14 +4157,15 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
// Is the sign bit set?
// (X <s 0) ? X : MAXVAL ==> (X >u MAXVAL) ? X : MAXVAL ==> UMAX
// (X <s 0) ? MAXVAL : X ==> (X >u MAXVAL) ? MAXVAL : X ==> UMIN
if (Pred == CmpInst::ICMP_SLT && *C1 == 0 && C2->isMaxSignedValue())
if ((Pred == CmpInst::ICMP_SLT || Pred == CmpInst::ICMP_SLE) && *C1 == 0 &&
C2->isMaxSignedValue())
return {CmpLHS == TrueVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, false};

// Is the sign bit clear?
// (X >s -1) ? MINVAL : X ==> (X <u MINVAL) ? MINVAL : X ==> UMAX
// (X >s -1) ? X : MINVAL ==> (X <u MINVAL) ? X : MINVAL ==> UMIN
if (Pred == CmpInst::ICMP_SGT && C1->isAllOnesValue() &&
C2->isMinSignedValue())
if ((Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE) &&
C1->isAllOnesValue() && C2->isMinSignedValue())
return {CmpLHS == FalseVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, false};
}

Expand All @@ -4157,13 +4174,17 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
// (X <s C) ? ~X : ~C ==> (~X >s ~C) ? ~X : ~C ==> SMAX(~X, ~C)
if (match(TrueVal, m_Not(m_Specific(CmpLHS))) &&
match(FalseVal, m_APInt(C2)) && ~(*C1) == *C2)
return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false};
return {(Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE) ? SPF_SMIN
: SPF_SMAX,
SPNB_NA, false};

// (X >s C) ? ~C : ~X ==> (~X <s ~C) ? ~C : ~X ==> SMAX(~C, ~X)
// (X <s C) ? ~C : ~X ==> (~X >s ~C) ? ~C : ~X ==> SMIN(~C, ~X)
if (match(FalseVal, m_Not(m_Specific(CmpLHS))) &&
match(TrueVal, m_APInt(C2)) && ~(*C1) == *C2)
return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false};
return {(Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE) ? SPF_SMAX
: SPF_SMIN,
SPNB_NA, false};

return {SPF_UNKNOWN, SPNB_NA, false};
}
Expand Down
20 changes: 10 additions & 10 deletions llvm/test/Transforms/InstCombine/minmax-fold.ll
Expand Up @@ -404,8 +404,8 @@ define i32 @clamp_signed3(i32 %x) {
; CHECK-LABEL: @clamp_signed3(
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X:%.*]], 255
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 255
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X]], 15
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i32 [[MIN]], i32 15
; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[MIN]], 15
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[MIN]], i32 15
; CHECK-NEXT: ret i32 [[R]]
;
%cmp2 = icmp slt i32 %x, 255
Expand All @@ -421,8 +421,8 @@ define i32 @clamp_signed4(i32 %x) {
; CHECK-LABEL: @clamp_signed4(
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X:%.*]], 15
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 15
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[X]], 255
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i32 [[MAX]], i32 255
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[MAX]], 255
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[MAX]], i32 255
; CHECK-NEXT: ret i32 [[R]]
;
%cmp2 = icmp sgt i32 %x, 15
Expand Down Expand Up @@ -472,8 +472,8 @@ define i32 @clamp_unsigned3(i32 %x) {
; CHECK-LABEL: @clamp_unsigned3(
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[X:%.*]], 255
; CHECK-NEXT: [[MIN:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 255
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[X]], 15
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i32 [[MIN]], i32 15
; CHECK-NEXT: [[TMP1:%.*]] = icmp ugt i32 [[MIN]], 15
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[MIN]], i32 15
; CHECK-NEXT: ret i32 [[R]]
;
%cmp2 = icmp ult i32 %x, 255
Expand All @@ -489,8 +489,8 @@ define i32 @clamp_unsigned4(i32 %x) {
; CHECK-LABEL: @clamp_unsigned4(
; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i32 [[X:%.*]], 15
; CHECK-NEXT: [[MAX:%.*]] = select i1 [[CMP2]], i32 [[X]], i32 15
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X]], 255
; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], i32 [[MAX]], i32 255
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[MAX]], 255
; CHECK-NEXT: [[R:%.*]] = select i1 [[TMP1]], i32 [[MAX]], i32 255
; CHECK-NEXT: ret i32 [[R]]
;
%cmp2 = icmp ugt i32 %x, 15
Expand Down Expand Up @@ -523,8 +523,8 @@ define i32 @clamp_check_for_no_infinite_loop2(i32 %i) {
; CHECK-LABEL: @clamp_check_for_no_infinite_loop2(
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[I:%.*]], -255
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i32 [[I]], i32 -255
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[I]], 0
; CHECK-NEXT: [[RES:%.*]] = select i1 [[CMP2]], i32 [[SEL1]], i32 0
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[SEL1]], 0
; CHECK-NEXT: [[RES:%.*]] = select i1 [[TMP1]], i32 [[SEL1]], i32 0
; CHECK-NEXT: ret i32 [[RES]]
;
%cmp1 = icmp sgt i32 %i, -255
Expand Down

0 comments on commit 346f432

Please sign in to comment.