From 5cbd5a13a4e499264abbc3865c663496b4de63ac Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Sun, 24 Aug 2014 09:10:57 +0000 Subject: [PATCH] InstCombine: Properly optimize or'ing bittests together CFE, with -03, would turn: bool f(unsigned x) { bool a = x & 1; bool b = x & 2; return a | b; } into: %1 = lshr i32 %x, 1 %2 = or i32 %1, %x %3 = and i32 %2, 1 %4 = icmp ne i32 %3, 0 This sort of thing exposes a nasty pathology in GCC, ICC and LLVM. Instead, we would rather want: %1 = and i32 %x, 3 %2 = icmp ne i32 %1, 0 Things get a bit more interesting in the following case: %1 = lshr i32 %x, %y %2 = or i32 %1, %x %3 = and i32 %2, 1 %4 = icmp ne i32 %3, 0 Replacing it with the following sequence is better: %1 = shl nuw i32 1, %y %2 = or i32 %1, 1 %3 = and i32 %2, %x %4 = icmp ne i32 %3, 0 This sequence is preferable because %1 doesn't involve %x and could potentially be hoisted out of loops if it is invariant; only perform this transform in the non-constant case if we know we won't increase register pressure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216343 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/InstCombine/InstCombineCompares.cpp | 42 ++++++++++++++++++++++ test/Transforms/InstCombine/icmp.ll | 26 ++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index 3a501132ebd..4cf836c03b2 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1366,6 +1366,48 @@ Instruction *InstCombiner::visitICmpInstWithInstAndIntCst(ICmpInst &ICI, return &ICI; } + // (icmp pred (and (or (lshr X, Y), X), 1), 0) --> + // (icmp pred (and X, (or (shl 1, Y), 1), 0)) + // + // iff pred isn't signed + { + Value *X, *Y, *LShr; + if (!ICI.isSigned() && RHSV == 0) { + if (match(LHSI->getOperand(1), m_One())) { + Constant *One = cast(LHSI->getOperand(1)); + Value *Or = LHSI->getOperand(0); + if (match(Or, m_Or(m_Value(LShr), m_Value(X))) && + match(LShr, m_LShr(m_Specific(X), m_Value(Y)))) { + unsigned UsesRemoved = 0; + if (LHSI->hasOneUse()) + ++UsesRemoved; + if (Or->hasOneUse()) + ++UsesRemoved; + if (LShr->hasOneUse()) + ++UsesRemoved; + Value *NewOr = nullptr; + // Compute X & ((1 << Y) | 1) + if (auto *C = dyn_cast(Y)) { + if (UsesRemoved >= 1) + NewOr = + ConstantExpr::getOr(ConstantExpr::getNUWShl(One, C), One); + } else { + if (UsesRemoved >= 3) + NewOr = Builder->CreateOr(Builder->CreateShl(One, Y, + LShr->getName(), + /*HasNUW=*/true), + One, Or->getName()); + } + if (NewOr) { + Value *NewAnd = Builder->CreateAnd(X, NewOr, LHSI->getName()); + ICI.setOperand(0, NewAnd); + return &ICI; + } + } + } + } + } + // Replace ((X & AndCst) > RHSV) with ((X & AndCst) != 0), if any // bit set in (X & AndCst) will produce a result greater than RHSV. if (ICI.getPredicate() == ICmpInst::ICMP_UGT) { diff --git a/test/Transforms/InstCombine/icmp.ll b/test/Transforms/InstCombine/icmp.ll index 26e144f93a5..39438e94832 100644 --- a/test/Transforms/InstCombine/icmp.ll +++ b/test/Transforms/InstCombine/icmp.ll @@ -1424,3 +1424,29 @@ define i1 @icmp_neg_cst_slt(i32 %a) { %2 = icmp slt i32 %1, -10 ret i1 %2 } + +; CHECK-LABEL: @icmp_and_or_lshr +; CHECK-NEXT: [[SHL:%[a-z0-9]+]] = shl nuw i32 1, %y +; CHECK-NEXT: [[OR:%[a-z0-9]+]] = or i32 [[SHL]], 1 +; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 [[OR]], %x +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +define i1 @icmp_and_or_lshr(i32 %x, i32 %y) { + %shf = lshr i32 %x, %y + %or = or i32 %shf, %x + %and = and i32 %or, 1 + %ret = icmp ne i32 %and, 0 + ret i1 %ret +} + +; CHECK-LABEL: @icmp_and_or_lshr_cst +; CHECK-NEXT: [[AND:%[a-z0-9]+]] = and i32 %x, 3 +; CHECK-NEXT: [[CMP:%[a-z0-9]+]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: ret i1 [[CMP]] +define i1 @icmp_and_or_lshr_cst(i32 %x) { + %shf = lshr i32 %x, 1 + %or = or i32 %shf, %x + %and = and i32 %or, 1 + %ret = icmp ne i32 %and, 0 + ret i1 %ret +} -- 2.11.0