From 0c73079855de925bf08335fe39b0b112f3d9407a Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 21 Nov 2008 07:33:58 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@59800 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Scalar/InstructionCombining.cpp | 45 ++++++++++++++----- .../InstCombine/2008-11-20-DivMulRem.ll | 34 ++++++++++++++ 2 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 test/Transforms/InstCombine/2008-11-20-DivMulRem.ll diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index e7d596773f7..ee6b51cf296 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -2477,17 +2477,6 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { Constant *CP1 = Subtract(ConstantInt::get(I.getType(), 1), C2); return BinaryOperator::CreateMul(Op0, CP1); } - - // X - ((X / Y) * Y) --> X % Y - if (Op1I->getOpcode() == Instruction::Mul) - if (Instruction *I = dyn_cast(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))) 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(Op0); + if (!BO || + (BO->getOpcode() != Instruction::UDiv && + BO->getOpcode() != Instruction::SDiv)) { + Op1 = Op0; + BO = dyn_cast(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) return BinaryOperator::CreateAnd(Op0, I.getOperand(1)); diff --git a/test/Transforms/InstCombine/2008-11-20-DivMulRem.ll b/test/Transforms/InstCombine/2008-11-20-DivMulRem.ll new file mode 100644 index 00000000000..8c58a2ae7f7 --- /dev/null +++ b/test/Transforms/InstCombine/2008-11-20-DivMulRem.ll @@ -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 +}