Skip to content

Commit

Permalink
[ValueTracking] Match select abs pattern when there's an sext involved
Browse files Browse the repository at this point in the history
When checking a select to see if it matches an abs, allow the true/false values
to be a sign-extension of the comparison value instead of requiring that they're
directly the comparison value, as all the comparison cares about is the sign of
the value.

This fixes a regression due to r333702, where we were no longer generating ctlz
due to isKnownNonNegative failing to match such a pattern.

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


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@333927 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
john-brawn-arm committed Jun 4, 2018
1 parent 8177aaf commit 9495e9e
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 6 deletions.
24 changes: 18 additions & 6 deletions lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4604,23 +4604,35 @@ static SelectPatternResult matchSelectPattern(CmpInst::Predicate Pred,

const APInt *C1;
if (match(CmpRHS, m_APInt(C1))) {
if ((CmpLHS == TrueVal && match(FalseVal, m_Neg(m_Specific(CmpLHS)))) ||
(CmpLHS == FalseVal && match(TrueVal, m_Neg(m_Specific(CmpLHS))))) {
// Set RHS to the negate operand. LHS was assigned to CmpLHS earlier.
RHS = (CmpLHS == TrueVal) ? FalseVal : TrueVal;
// Sign-extending LHS does not change its sign, so TrueVal/FalseVal can
// match against either LHS or sext(LHS).
auto MaybeSExtLHS = m_CombineOr(m_Specific(CmpLHS),
m_SExt(m_Specific(CmpLHS)));
if ((match(TrueVal, MaybeSExtLHS) &&
match(FalseVal, m_Neg(m_Specific(TrueVal)))) ||
(match(FalseVal, MaybeSExtLHS) &&
match(TrueVal, m_Neg(m_Specific(FalseVal))))) {
// Set LHS and RHS so that RHS is the negated operand of the select
if (match(TrueVal, MaybeSExtLHS)) {
LHS = TrueVal;
RHS = FalseVal;
} else {
LHS = FalseVal;
RHS = TrueVal;
}

// ABS(X) ==> (X >s 0) ? X : -X and (X >s -1) ? X : -X
// NABS(X) ==> (X >s 0) ? -X : X and (X >s -1) ? -X : X
if (Pred == ICmpInst::ICMP_SGT &&
(C1->isNullValue() || C1->isAllOnesValue())) {
return {(CmpLHS == TrueVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false};
return {(LHS == TrueVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false};
}

// ABS(X) ==> (X <s 0) ? -X : X and (X <s 1) ? -X : X
// NABS(X) ==> (X <s 0) ? X : -X and (X <s 1) ? X : -X
if (Pred == ICmpInst::ICMP_SLT &&
(C1->isNullValue() || C1->isOneValue())) {
return {(CmpLHS == FalseVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false};
return {(LHS == FalseVal) ? SPF_ABS : SPF_NABS, SPNB_NA, false};
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions test/Transforms/LoopIdiom/ARM/ctlz.ll
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,48 @@ while.cond: ; preds = %while.cond, %entry
while.end: ; preds = %while.cond
ret i32 %i.0
}

; Recognize CTLZ builtin pattern.
; Here it will replace the loop -
; assume builtin is always profitable.
;
; int ctlz_sext(short in)
; {
; int n = in;
; if (in < 0)
; n = -n;
; int i = 0;
; while(n >>= 1) {
; i++;
; }
; return i;
; }
;
; ALL: entry
; ALL: %0 = ashr i32 %abs_n, 1
; ALL-NEXT: %1 = call i32 @llvm.ctlz.i32(i32 %0, i1 false)
; ALL-NEXT: %2 = sub i32 32, %1
; ALL-NEXT: %3 = add i32 %2, 1
; ALL: %i.0.lcssa = phi i32 [ %2, %while.cond ]
; ALL: ret i32 %i.0.lcssa

; Function Attrs: norecurse nounwind readnone uwtable
define i32 @ctlz_sext(i16 %in) {
entry:
%n = sext i16 %in to i32
%c = icmp sgt i16 %in, 0
%negn = sub nsw i32 0, %n
%abs_n = select i1 %c, i32 %n, i32 %negn
br label %while.cond

while.cond: ; preds = %while.cond, %entry
%n.addr.0 = phi i32 [ %abs_n, %entry ], [ %shr, %while.cond ]
%i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ]
%shr = ashr i32 %n.addr.0, 1
%tobool = icmp eq i32 %shr, 0
%inc = add nsw i32 %i.0, 1
br i1 %tobool, label %while.end, label %while.cond

while.end: ; preds = %while.cond
ret i32 %i.0
}
45 changes: 45 additions & 0 deletions test/Transforms/LoopIdiom/X86/ctlz.ll
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,51 @@ while.end: ; preds = %while.cond
ret i32 %i.0
}

; Recognize CTLZ builtin pattern.
; Here it will replace the loop -
; assume builtin is always profitable.
;
; int ctlz_sext(short in)
; {
; int n = in;
; if (in < 0)
; n = -n;
; int i = 0;
; while(n >>= 1) {
; i++;
; }
; return i;
; }
;
; ALL: entry
; ALL: %0 = ashr i32 %abs_n, 1
; ALL-NEXT: %1 = call i32 @llvm.ctlz.i32(i32 %0, i1 false)
; ALL-NEXT: %2 = sub i32 32, %1
; ALL-NEXT: %3 = add i32 %2, 1
; ALL: %i.0.lcssa = phi i32 [ %2, %while.cond ]
; ALL: ret i32 %i.0.lcssa

; Function Attrs: norecurse nounwind readnone uwtable
define i32 @ctlz_sext(i16 %in) {
entry:
%n = sext i16 %in to i32
%c = icmp sgt i16 %in, 0
%negn = sub nsw i32 0, %n
%abs_n = select i1 %c, i32 %n, i32 %negn
br label %while.cond

while.cond: ; preds = %while.cond, %entry
%n.addr.0 = phi i32 [ %abs_n, %entry ], [ %shr, %while.cond ]
%i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ]
%shr = ashr i32 %n.addr.0, 1
%tobool = icmp eq i32 %shr, 0
%inc = add nsw i32 %i.0, 1
br i1 %tobool, label %while.end, label %while.cond

while.end: ; preds = %while.cond
ret i32 %i.0
}

; This loop contains a volatile store. If x is initially negative,
; the code will be an infinite loop because the ashr will eventually produce
; all ones and continue doing so. This prevents the loop from terminating. If
Expand Down

0 comments on commit 9495e9e

Please sign in to comment.