Instcombine x-((x/y)*y) into a remainder operator.
authorDan Gohman <gohman@apple.com>
Mon, 17 Sep 2007 17:31:57 +0000 (17:31 +0000)
committerDan Gohman <gohman@apple.com>
Mon, 17 Sep 2007 17:31:57 +0000 (17:31 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@42035 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/InstructionCombining.cpp
test/Transforms/InstCombine/srem.ll [new file with mode: 0644]
test/Transforms/InstCombine/urem.ll [new file with mode: 0644]

index 787a3d5ccf52ca1a0ac966744e0ffd412578c99d..55ef0a8098512eae2524031b83b0da6650ed85d0 100644 (file)
@@ -2257,6 +2257,17 @@ 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<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));
+          }
     }
   }
 
@@ -2902,7 +2913,7 @@ static unsigned getICmpCode(const ICmpInst *ICI) {
 
 /// getICmpValue - This is the complement of getICmpCode, which turns an
 /// opcode and two operands into either a constant true or false, or a brand 
-/// new /// ICmp instruction. The sign is passed in to determine which kind
+/// new ICmp instruction. The sign is passed in to determine which kind
 /// of predicate to use in new icmp instructions.
 static Value *getICmpValue(bool sign, unsigned code, Value *LHS, Value *RHS) {
   switch (code) {
diff --git a/test/Transforms/InstCombine/srem.ll b/test/Transforms/InstCombine/srem.ll
new file mode 100644 (file)
index 0000000..864775a
--- /dev/null
@@ -0,0 +1,8 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep srem
+
+define i64 @foo(i64 %x1, i64 %y2) {
+       %r = sdiv i64 %x1, %y2
+       %r7 = mul i64 %r, %y2
+       %r8 = sub i64 %x1, %r7
+       ret i64 %r8
+}
diff --git a/test/Transforms/InstCombine/urem.ll b/test/Transforms/InstCombine/urem.ll
new file mode 100644 (file)
index 0000000..24e7463
--- /dev/null
@@ -0,0 +1,8 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep urem
+
+define i64 @rem_unsigned(i64 %x1, i64 %y2) {
+       %r = udiv i64 %x1, %y2
+       %r7 = mul i64 %r, %y2
+       %r8 = sub i64 %x1, %r7
+       ret i64 %r8
+}