From f59da46fd7f0cc1e4e132ef60747cc4548564739 Mon Sep 17 00:00:00 2001 From: James Molloy Date: Thu, 14 Jan 2016 15:23:19 +0000 Subject: [PATCH] [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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257769 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/ValueTracking.cpp | 40 +++++++++++- test/Analysis/ValueTracking/select-maxbits.ll | 62 +++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 test/Analysis/ValueTracking/select-maxbits.ll diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index a83e207bd26..50dd03f52b4 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -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(C1)->getValue() - 1; + KnownZero = ~APInt::getLowBitsSet(V.getBitWidth(), V.getActiveBits()); + } + } break; + } case Instruction::FPTrunc: case Instruction::FPExt: case Instruction::FPToUI: diff --git a/test/Analysis/ValueTracking/select-maxbits.ll b/test/Analysis/ValueTracking/select-maxbits.ll new file mode 100644 index 00000000000..4b121745048 --- /dev/null +++ b/test/Analysis/ValueTracking/select-maxbits.ll @@ -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 +} \ No newline at end of file