Optimize (x/y)*y into x-(x%y) in general. Div and rem are about the same, and

a subtract is cheaper than a multiply. This generalizes an existing transform.

llvm-svn: 59800
This commit is contained in:
Nick Lewycky 2008-11-21 07:33:58 +00:00
parent 6b0cf14ba4
commit 07d726ec4d
2 changed files with 68 additions and 11 deletions

View File

@ -2477,17 +2477,6 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
Constant *CP1 = Subtract(ConstantInt::get(I.getType(), 1), C2); Constant *CP1 = Subtract(ConstantInt::get(I.getType(), 1), C2);
return BinaryOperator::CreateMul(Op0, CP1); return BinaryOperator::CreateMul(Op0, CP1);
} }
// X - ((X / Y) * Y) --> X % Y
if (Op1I->getOpcode() == Instruction::Mul)
if (Instruction *I = dyn_cast<Instruction>(Op1I->getOperand(0)))
if (Op0 == I->getOperand(0) &&
Op1I->getOperand(1) == I->getOperand(1)) {
if (I->getOpcode() == Instruction::SDiv)
return BinaryOperator::CreateSRem(Op0, Op1I->getOperand(1));
if (I->getOpcode() == Instruction::UDiv)
return BinaryOperator::CreateURem(Op0, Op1I->getOperand(1));
}
} }
} }
@ -2622,6 +2611,40 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) {
if (Value *Op1v = dyn_castNegVal(I.getOperand(1))) if (Value *Op1v = dyn_castNegVal(I.getOperand(1)))
return BinaryOperator::CreateMul(Op0v, Op1v); return BinaryOperator::CreateMul(Op0v, Op1v);
// (X / Y) * Y = X - (X % Y)
// (X / Y) * -Y = (X % Y) - X
{
Value *Op1 = I.getOperand(1);
BinaryOperator *BO = dyn_cast<BinaryOperator>(Op0);
if (!BO ||
(BO->getOpcode() != Instruction::UDiv &&
BO->getOpcode() != Instruction::SDiv)) {
Op1 = Op0;
BO = dyn_cast<BinaryOperator>(I.getOperand(1));
}
Value *Neg = dyn_castNegVal(Op1);
if (BO && BO->hasOneUse() &&
(BO->getOperand(1) == Op1 || BO->getOperand(1) == Neg) &&
(BO->getOpcode() == Instruction::UDiv ||
BO->getOpcode() == Instruction::SDiv)) {
Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1);
Instruction *Rem;
if (BO->getOpcode() == Instruction::UDiv)
Rem = BinaryOperator::CreateURem(Op0BO, Op1BO);
else
Rem = BinaryOperator::CreateSRem(Op0BO, Op1BO);
InsertNewInstBefore(Rem, I);
Rem->takeName(BO);
if (Op1BO == Op1)
return BinaryOperator::CreateSub(Op0BO, Rem);
else
return BinaryOperator::CreateSub(Rem, Op0BO);
}
}
if (I.getType() == Type::Int1Ty) if (I.getType() == Type::Int1Ty)
return BinaryOperator::CreateAnd(Op0, I.getOperand(1)); return BinaryOperator::CreateAnd(Op0, I.getOperand(1));

View File

@ -0,0 +1,34 @@
; RUN: llvm-as < %s | opt -instcombine | llvm-dis > %t
; RUN: grep urem %t | count 3
; RUN: grep srem %t | count 1
; RUN: grep sub %t | count 2
; RUN: grep add %t | count 1
; PR3103
define i8 @test1(i8 %x, i8 %y) {
%A = udiv i8 %x, %y
%B = mul i8 %A, %y
%C = sub i8 %x, %B
ret i8 %C
}
define i8 @test2(i8 %x, i8 %y) {
%A = sdiv i8 %x, %y
%B = mul i8 %A, %y
%C = sub i8 %x, %B
ret i8 %C
}
define i8 @test3(i8 %x, i8 %y) {
%A = udiv i8 %x, %y
%B = mul i8 %A, %y
%C = sub i8 %B, %x
ret i8 %C
}
define i8 @test4(i8 %x) {
%A = udiv i8 %x, 3
%B = mul i8 %A, -3
%C = sub i8 %x, %B
ret i8 %C
}