mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2026-04-26 12:20:42 +00:00
InstCombine: Combine mul with div.
We can combne a mul with a div if one of the operands is a multiple of
the other:
%mul = mul nsw nuw %a, C1
%ret = udiv %mul, C2
=>
%ret = mul nsw %a, (C1 / C2)
This can expose further optimization opportunities if we end up
multiplying or dividing by a power of 2.
Consider this small example:
define i32 @f(i32 %a) {
%mul = mul nuw i32 %a, 14
%div = udiv exact i32 %mul, 7
ret i32 %div
}
which gets CodeGen'd to:
imull $14, %edi, %eax
imulq $613566757, %rax, %rcx
shrq $32, %rcx
subl %ecx, %eax
shrl %eax
addl %ecx, %eax
shrl $2, %eax
retq
We can now transform this into:
define i32 @f(i32 %a) {
%shl = shl nuw i32 %a, 1
ret i32 %shl
}
which gets CodeGen'd to:
leal (%rdi,%rdi), %eax
retq
This fixes PR20681.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215815 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -97,6 +97,21 @@ static bool MultiplyOverflows(ConstantInt *C1, ConstantInt *C2, bool sign) {
|
||||
return MulExt.slt(Min) || MulExt.sgt(Max);
|
||||
}
|
||||
|
||||
/// \brief True if C2 is a multiple of C1. Quotient contains C2/C1.
|
||||
static bool IsMultiple(const APInt &C1, const APInt &C2, APInt &Quotient,
|
||||
bool IsSigned) {
|
||||
assert(C1.getBitWidth() == C2.getBitWidth() &&
|
||||
"Inconsistent width of constants!");
|
||||
|
||||
APInt Remainder(C1.getBitWidth(), /*Val=*/0ULL, IsSigned);
|
||||
if (IsSigned)
|
||||
APInt::sdivrem(C1, C2, Quotient, Remainder);
|
||||
else
|
||||
APInt::udivrem(C1, C2, Quotient, Remainder);
|
||||
|
||||
return Remainder.isMinValue();
|
||||
}
|
||||
|
||||
/// \brief A helper routine of InstCombiner::visitMul().
|
||||
///
|
||||
/// If C is a vector of known powers of 2, then this function returns
|
||||
@@ -725,8 +740,8 @@ Instruction *InstCombiner::commonIDivTransforms(BinaryOperator &I) {
|
||||
return &I;
|
||||
|
||||
if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
|
||||
// (X / C1) / C2 -> X / (C1*C2)
|
||||
if (Instruction *LHS = dyn_cast<Instruction>(Op0))
|
||||
if (Instruction *LHS = dyn_cast<Instruction>(Op0)) {
|
||||
// (X / C1) / C2 -> X / (C1*C2)
|
||||
if (Instruction::BinaryOps(LHS->getOpcode()) == I.getOpcode())
|
||||
if (ConstantInt *LHSRHS = dyn_cast<ConstantInt>(LHS->getOperand(1))) {
|
||||
if (MultiplyOverflows(RHS, LHSRHS,
|
||||
@@ -736,6 +751,64 @@ Instruction *InstCombiner::commonIDivTransforms(BinaryOperator &I) {
|
||||
ConstantExpr::getMul(RHS, LHSRHS));
|
||||
}
|
||||
|
||||
Value *X;
|
||||
const APInt *C1, *C2;
|
||||
if (match(RHS, m_APInt(C2))) {
|
||||
bool IsSigned = I.getOpcode() == Instruction::SDiv;
|
||||
if ((IsSigned && match(LHS, m_NSWMul(m_Value(X), m_APInt(C1)))) ||
|
||||
(!IsSigned && match(LHS, m_NUWMul(m_Value(X), m_APInt(C1))))) {
|
||||
APInt Quotient(C1->getBitWidth(), /*Val=*/0ULL, IsSigned);
|
||||
|
||||
// (X * C1) / C2 -> X / (C2 / C1) if C2 is a multiple of C1.
|
||||
if (IsMultiple(*C2, *C1, Quotient, IsSigned)) {
|
||||
BinaryOperator *BO = BinaryOperator::Create(
|
||||
I.getOpcode(), X, ConstantInt::get(X->getType(), Quotient));
|
||||
BO->setIsExact(I.isExact());
|
||||
return BO;
|
||||
}
|
||||
|
||||
// (X * C1) / C2 -> X * (C1 / C2) if C1 is a multiple of C2.
|
||||
if (IsMultiple(*C1, *C2, Quotient, IsSigned)) {
|
||||
BinaryOperator *BO = BinaryOperator::Create(
|
||||
Instruction::Mul, X, ConstantInt::get(X->getType(), Quotient));
|
||||
BO->setHasNoUnsignedWrap(
|
||||
!IsSigned &&
|
||||
cast<OverflowingBinaryOperator>(LHS)->hasNoUnsignedWrap());
|
||||
BO->setHasNoSignedWrap(
|
||||
cast<OverflowingBinaryOperator>(LHS)->hasNoSignedWrap());
|
||||
return BO;
|
||||
}
|
||||
}
|
||||
|
||||
if ((IsSigned && match(LHS, m_NSWShl(m_Value(X), m_APInt(C1)))) ||
|
||||
(!IsSigned && match(LHS, m_NUWShl(m_Value(X), m_APInt(C1))))) {
|
||||
APInt Quotient(C1->getBitWidth(), /*Val=*/0ULL, IsSigned);
|
||||
APInt C1Shifted = APInt::getOneBitSet(
|
||||
C1->getBitWidth(), static_cast<unsigned>(C1->getLimitedValue()));
|
||||
|
||||
// (X << C1) / C2 -> X / (C2 >> C1) if C2 is a multiple of C1.
|
||||
if (IsMultiple(*C2, C1Shifted, Quotient, IsSigned)) {
|
||||
BinaryOperator *BO = BinaryOperator::Create(
|
||||
I.getOpcode(), X, ConstantInt::get(X->getType(), Quotient));
|
||||
BO->setIsExact(I.isExact());
|
||||
return BO;
|
||||
}
|
||||
|
||||
// (X << C1) / C2 -> X * (C2 >> C1) if C1 is a multiple of C2.
|
||||
if (IsMultiple(C1Shifted, *C2, Quotient, IsSigned)) {
|
||||
BinaryOperator *BO = BinaryOperator::Create(
|
||||
Instruction::Mul, X, ConstantInt::get(X->getType(), Quotient));
|
||||
BO->setHasNoUnsignedWrap(
|
||||
!IsSigned &&
|
||||
cast<OverflowingBinaryOperator>(LHS)->hasNoUnsignedWrap());
|
||||
BO->setHasNoSignedWrap(
|
||||
cast<OverflowingBinaryOperator>(LHS)->hasNoSignedWrap());
|
||||
return BO;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!RHS->isZero()) { // avoid X udiv 0
|
||||
if (SelectInst *SI = dyn_cast<SelectInst>(Op0))
|
||||
if (Instruction *R = FoldOpIntoSelect(I, SI))
|
||||
|
||||
Reference in New Issue
Block a user