diff options
author | Sanjay Patel <spatel@rotateright.com> | 2018-10-31 13:25:10 +0000 |
---|---|---|
committer | Sanjay Patel <spatel@rotateright.com> | 2018-10-31 13:25:10 +0000 |
commit | 2efccd2cf2804e2143c67c01bdfa44c5e3d887ac (patch) | |
tree | ce23bc836150bb8447502180787c33cdef04d330 /llvm/lib/Analysis | |
parent | dd2120c08f1d4865fe5ecee5d3270b85af104652 (diff) | |
download | bcm5719-llvm-2efccd2cf2804e2143c67c01bdfa44c5e3d887ac.tar.gz bcm5719-llvm-2efccd2cf2804e2143c67c01bdfa44c5e3d887ac.zip |
[InstSimplify] fold icmp based on range of abs/nabs
This is a fix for PR39475:
https://bugs.llvm.org/show_bug.cgi?id=39475
We managed to get some of these patterns using computeKnownBits in D47041, but that
can't be used for nabs(). Instead, put in some range-based logic, so we can fold
both abs/nabs with icmp with a constant value.
Alive proofs:
https://rise4fun.com/Alive/21r
Name: abs_nsw_is_positive
%cmp = icmp slt i32 %x, 0
%negx = sub nsw i32 0, %x
%abs = select i1 %cmp, i32 %negx, i32 %x
%r = icmp sgt i32 %abs, -1
=>
%r = i1 true
Name: abs_nsw_is_not_negative
%cmp = icmp slt i32 %x, 0
%negx = sub nsw i32 0, %x
%abs = select i1 %cmp, i32 %negx, i32 %x
%r = icmp slt i32 %abs, 0
=>
%r = i1 false
Name: nabs_is_negative_or_0
%cmp = icmp slt i32 %x, 0
%negx = sub i32 0, %x
%nabs = select i1 %cmp, i32 %x, i32 %negx
%r = icmp slt i32 %nabs, 1
=>
%r = i1 true
Name: nabs_is_not_over_0
%cmp = icmp slt i32 %x, 0
%negx = sub i32 0, %x
%nabs = select i1 %cmp, i32 %x, i32 %negx
%r = icmp sgt i32 %nabs, 0
=>
%r = i1 false
Differential Revision: https://reviews.llvm.org/D53844
llvm-svn: 345717
Diffstat (limited to 'llvm/lib/Analysis')
-rw-r--r-- | llvm/lib/Analysis/InstructionSimplify.cpp | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 6ff72638512..b1381932e7f 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2996,6 +2996,45 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, return nullptr; } +static Value *simplifyICmpWithAbsNabs(CmpInst::Predicate Pred, Value *Op0, + Value *Op1) { + // We need a comparison with a constant. + const APInt *C; + if (!match(Op1, m_APInt(C))) + return nullptr; + + // matchSelectPattern returns the negation part of an abs pattern in SP1. + // If the negate has an NSW flag, abs(INT_MIN) is undefined. Without that + // constraint, we can't make a contiguous range for the result of abs. + ICmpInst::Predicate AbsPred = ICmpInst::BAD_ICMP_PREDICATE; + Value *SP0, *SP1; + SelectPatternFlavor SPF = matchSelectPattern(Op0, SP0, SP1).Flavor; + if (SPF == SelectPatternFlavor::SPF_ABS && + cast<Instruction>(SP1)->hasNoSignedWrap()) + // The result of abs(X) is >= 0 (with nsw). + AbsPred = ICmpInst::ICMP_SGE; + if (SPF == SelectPatternFlavor::SPF_NABS) + // The result of -abs(X) is <= 0. + AbsPred = ICmpInst::ICMP_SLE; + + if (AbsPred == ICmpInst::BAD_ICMP_PREDICATE) + return nullptr; + + // Intersect the range of abs/nabs with the range of this icmp. + // If there is no intersection, the icmp must be false. + // If the intersection equals the range of abs/nabs, the icmp must be true. + APInt Zero = APInt::getNullValue(C->getBitWidth()); + ConstantRange AbsRange = ConstantRange::makeExactICmpRegion(AbsPred, Zero); + ConstantRange CmpRange = ConstantRange::makeExactICmpRegion(Pred, *C); + ConstantRange Intersection = AbsRange.intersectWith(CmpRange); + if (Intersection.isEmptySet()) + return getFalse(GetCompareTy(Op0)); + if (Intersection == AbsRange) + return getTrue(GetCompareTy(Op0)); + + return nullptr; +} + /// Simplify integer comparisons where at least one operand of the compare /// matches an integer min/max idiom. static Value *simplifyICmpWithMinMax(CmpInst::Predicate Pred, Value *LHS, @@ -3427,6 +3466,9 @@ static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, if (Value *V = simplifyICmpWithMinMax(Pred, LHS, RHS, Q, MaxRecurse)) return V; + if (Value *V = simplifyICmpWithAbsNabs(Pred, LHS, RHS)) + return V; + // Simplify comparisons of related pointers using a powerful, recursive // GEP-walk when we have target data available.. if (LHS->getType()->isPointerTy()) |