[ValueTracking] Understand more select patterns in ComputeKnownBits

Some patterns of select+compare allow us to know exactly the value of the uppermost bits in the select result. For example:

  %b = icmp ugt i32 %a, 5
  %c = select i1 %b, i32 2, i32 %a

Here we know that %c is bounded by 5, and therefore KnownZero = ~APInt(5).getActiveBits() = ~7.

There are several such patterns, and this patch attempts to understand a reasonable subset of them - namely when the base values are the same (as above), and when they are related by a simple (add nsw), for example (add nsw %a, 4) and %a.

llvm-svn: 257769
This commit is contained in:
James Molloy 2016-01-14 15:23:19 +00:00
parent b28ae10a16
commit a9497f53c9
2 changed files with 101 additions and 1 deletions

View File

@ -1140,14 +1140,52 @@ static void computeKnownBitsFromOperator(Operator *I, APInt &KnownZero,
KnownZero = APInt::getHighBitsSet(BitWidth, LeadZ);
break;
}
case Instruction::Select:
case Instruction::Select: {
computeKnownBits(I->getOperand(2), KnownZero, KnownOne, DL, Depth + 1, Q);
computeKnownBits(I->getOperand(1), KnownZero2, KnownOne2, DL, Depth + 1, Q);
// Only known if known in both the LHS and RHS.
KnownOne &= KnownOne2;
KnownZero &= KnownZero2;
// There are several cmp+select patterns that ensure their result will be no
// greater than a constant. Detect a number of these.
Value *X, *Y;
ConstantInt *C1, *C2;
ICmpInst::Predicate Pred;
auto IsLessThanOrEqualTo = [](Value *X, Value *Y) {
if (X == Y)
return true;
Value *M1, *M2;
ConstantInt *C1, *C2;
if (!match(X, m_NSWAdd(m_Value(M1), m_ConstantInt(C1))))
C1 = nullptr;
if (!match(Y, m_NSWAdd(m_Value(M2), m_ConstantInt(C2))))
C2 = nullptr;
if (C1 && M1 == Y && C1->isNegative())
return true;
if (C2 && M2 == X && !C2->isNegative())
return true;
if (C1 && C2 && M1 == M2 && !C1->isNegative() && !C2->isNegative() &&
C1->getValue().ule(C2->getValue()))
return true;
return false;
};
// (select (icmp ugt X, C1), C2, Y)
// if Y <= X and C2 <= C1
// then maximum value = C1.
if (match(I, m_Select(m_ICmp(Pred, m_Value(X), m_ConstantInt(C1)),
m_ConstantInt(C2), m_Value(Y)))) {
if (Pred == ICmpInst::ICMP_UGT && IsLessThanOrEqualTo(Y, X) &&
C2->getValue().ule(C1->getValue())) {
auto V = cast<ConstantInt>(C1)->getValue() - 1;
KnownZero = ~APInt::getLowBitsSet(V.getBitWidth(), V.getActiveBits());
}
}
break;
}
case Instruction::FPTrunc:
case Instruction::FPExt:
case Instruction::FPToUI:

View File

@ -0,0 +1,62 @@
; RUN: opt -S -instsimplify < %s | FileCheck %s
; CHECK-LABEL: @one
define i32 @one(i32 %a) {
; CHECK: ret i32 0
%b = icmp ugt i32 %a, 5
%c = select i1 %b, i32 2, i32 %a
%d = lshr i32 %c, 24
ret i32 %d
}
; CHECK-LABEL: @two
define i32 @two(i32 %a) {
; CHECK: ret i32 0
%x = add nsw i32 %a, 4
%b = icmp ugt i32 %x, 5
%c = select i1 %b, i32 2, i32 %a
%d = lshr i32 %c, 24
ret i32 %d
}
; CHECK-LABEL: @two_no_nsw
define i32 @two_no_nsw(i32 %a) {
; CHECK: ret i32 %d
%x = add i32 %a, 4
%b = icmp ugt i32 %x, 5
%c = select i1 %b, i32 2, i32 %a
%d = lshr i32 %c, 24
ret i32 %d
}
; CHECK-LABEL: @three
define i32 @three(i32 %a) {
; CHECK: ret i32 0
%x = add nsw i32 %a, -4
%b = icmp ugt i32 %a, 5
%c = select i1 %b, i32 2, i32 %x
%d = lshr i32 %c, 24
ret i32 %d
}
; CHECK-LABEL: @four
define i32 @four(i32 %a) {
; CHECK: ret i32 0
%x = add nsw i32 %a, 42
%y = add nsw i32 %a, 64
%b = icmp ugt i32 %y, 5
%c = select i1 %b, i32 2, i32 %x
%d = lshr i32 %c, 24
ret i32 %d
}
; CHECK-LABEL: @four_swapped
define i32 @four_swapped(i32 %a) {
; CHECK: ret i32 %d
%x = add nsw i32 %a, 42
%y = add nsw i32 %a, 64
%b = icmp ugt i32 %x, 5
%c = select i1 %b, i32 2, i32 %y
%d = lshr i32 %c, 24
ret i32 %d
}