mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-03 00:33:09 +00:00
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
This commit is contained in:
parent
7ca2a7d742
commit
5cbd5a13a4
@ -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<Constant>(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<Constant>(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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user