summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Analysis
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2016-07-21 21:26:45 +0000
committerSanjay Patel <spatel@rotateright.com>2016-07-21 21:26:45 +0000
commita3bfb4e313718713df0f2323321b8f0fd3b1fcca (patch)
tree577711bdded3aefea68f8409e1cedb319083eb87 /llvm/lib/Analysis
parent84a6425d61d323304f5b4753df9c986906fdca0c (diff)
downloadbcm5719-llvm-a3bfb4e313718713df0f2323321b8f0fd3b1fcca.tar.gz
bcm5719-llvm-a3bfb4e313718713df0f2323321b8f0fd3b1fcca.zip
[InstSimplify] recognize trunc + icmp sgt/slt variants of select simplifications (PR28466)
rL245171 exposed a hole in InstSimplify that manifested in a strange way in PR28466: https://llvm.org/bugs/show_bug.cgi?id=28466 It's possible to use trunc + icmp sgt/slt in place of an and + icmp eq/ne, so we need to recognize that pattern to eliminate selects that are choosing between some value and some bitmasked version of that value. Note that there is significant room for improvement (refactoring) and enhancement (more patterns, possibly in InstCombine rather than here). Differential Revision: https://reviews.llvm.org/D22537 llvm-svn: 276341
Diffstat (limited to 'llvm/lib/Analysis')
-rw-r--r--llvm/lib/Analysis/InstructionSimplify.cpp40
1 files changed, 33 insertions, 7 deletions
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 45d4f14250b..7e4148ca4d2 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3406,6 +3406,33 @@ static Value *simplifySelectBitTest(Value *TrueVal, Value *FalseVal, Value *X,
return nullptr;
}
+/// An alternative way to test if a bit is set or not uses sgt/slt instead of
+/// eq/ne.
+static Value *simplifySelectWithFakeICmpEq(Value *CmpLHS, Value *TrueVal,
+ Value *FalseVal,
+ bool TrueWhenUnset) {
+ unsigned BitWidth = TrueVal->getType()->getScalarSizeInBits();
+ APInt MinSignedValue;
+ Value *X;
+ if (match(CmpLHS, m_Trunc(m_Value(X))) && (X == TrueVal || X == FalseVal)) {
+ // icmp slt (trunc X), 0 <--> icmp ne (and X, C), 0
+ // icmp sgt (trunc X), -1 <--> icmp eq (and X, C), 0
+ unsigned DestSize = CmpLHS->getType()->getScalarSizeInBits();
+ MinSignedValue = APInt::getSignedMinValue(DestSize).zext(BitWidth);
+ } else {
+ // icmp slt X, 0 <--> icmp ne (and X, C), 0
+ // icmp sgt X, -1 <--> icmp eq (and X, C), 0
+ X = CmpLHS;
+ MinSignedValue = APInt::getSignedMinValue(BitWidth);
+ }
+
+ if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, X, &MinSignedValue,
+ TrueWhenUnset))
+ return V;
+
+ return nullptr;
+}
+
/// Try to simplify a select instruction when its condition operand is an
/// integer comparison.
static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
@@ -3418,9 +3445,6 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
// FIXME: This code is nearly duplicated in InstCombine. Using/refactoring
// decomposeBitTestICmp() might help.
- unsigned BitWidth =
- Q.DL.getTypeSizeInBits(TrueVal->getType()->getScalarType());
- APInt MinSignedValue = APInt::getSignBit(BitWidth);
if (ICmpInst::isEquality(Pred) && match(CmpRHS, m_Zero())) {
Value *X;
const APInt *Y;
@@ -3429,12 +3453,14 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
Pred == ICmpInst::ICMP_EQ))
return V;
} else if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, m_Zero())) {
- if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, CmpLHS,
- &MinSignedValue, false))
+ // Comparing signed-less-than 0 checks if the sign bit is set.
+ if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal,
+ false))
return V;
} else if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, m_AllOnes())) {
- if (Value *V = simplifySelectBitTest(TrueVal, FalseVal, CmpLHS,
- &MinSignedValue, true))
+ // Comparing signed-greater-than -1 checks if the sign bit is not set.
+ if (Value *V = simplifySelectWithFakeICmpEq(CmpLHS, TrueVal, FalseVal,
+ true))
return V;
}
OpenPOWER on IntegriCloud