[turbofan] Optimize division/modulus by constant.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Tue, 14 Oct 2014 11:57:06 +0000 (11:57 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Tue, 14 Oct 2014 11:57:06 +0000 (11:57 +0000)
TEST=cctest,mjsunit,unittests
R=dcarney@chromium.org, svenpanne@chromium.org

Review URL: https://codereview.chromium.org/654833002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24595 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

30 files changed:
src/compiler/arm/code-generator-arm.cc
src/compiler/arm/instruction-codes-arm.h
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/code-generator-arm64.cc
src/compiler/arm64/instruction-codes-arm64.h
src/compiler/arm64/instruction-selector-arm64.cc
src/compiler/ia32/code-generator-ia32.cc
src/compiler/ia32/instruction-codes-ia32.h
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/instruction-selector.cc
src/compiler/machine-operator-reducer.cc
src/compiler/machine-operator-reducer.h
src/compiler/machine-operator.cc
src/compiler/machine-operator.h
src/compiler/opcodes.h
src/compiler/raw-machine-assembler.h
src/compiler/x64/code-generator-x64.cc
src/compiler/x64/instruction-codes-x64.h
src/compiler/x64/instruction-selector-x64.cc
test/cctest/compiler/test-run-machops.cc
test/mjsunit/asm/int32div.js [new file with mode: 0644]
test/mjsunit/asm/int32mod.js [new file with mode: 0644]
test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
test/unittests/compiler/graph-unittest.cc
test/unittests/compiler/graph-unittest.h
test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
test/unittests/compiler/machine-operator-reducer-unittest.cc
test/unittests/compiler/machine-operator-unittest.cc
test/unittests/compiler/x64/instruction-selector-x64-unittest.cc

index 6f8859b..c218587 100644 (file)
@@ -239,6 +239,15 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArmSmmul:
+      __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmSmmla:
+      __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+               i.InputRegister(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmSdiv: {
       CpuFeatureScope scope(masm(), SUDIV);
       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
index 8654a2c..3c97482 100644 (file)
@@ -26,6 +26,8 @@ namespace compiler {
   V(ArmMul)                        \
   V(ArmMla)                        \
   V(ArmMls)                        \
+  V(ArmSmmul)                      \
+  V(ArmSmmla)                      \
   V(ArmSdiv)                       \
   V(ArmUdiv)                       \
   V(ArmMov)                        \
index 0790b46..19ba71c 100644 (file)
@@ -78,6 +78,8 @@ class ArmOperandGenerator : public OperandGenerator {
       case kArmMul:
       case kArmMla:
       case kArmMls:
+      case kArmSmmul:
+      case kArmSmmla:
       case kArmSdiv:
       case kArmUdiv:
       case kArmBfc:
@@ -569,6 +571,20 @@ void InstructionSelector::VisitInt32Add(Node* node) {
          g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
     return;
   }
+  if (m.left().IsInt32MulHigh() && CanCover(node, m.left().node())) {
+    Int32BinopMatcher mleft(m.left().node());
+    Emit(kArmSmmla, g.DefineAsRegister(node),
+         g.UseRegister(mleft.left().node()),
+         g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
+    return;
+  }
+  if (m.right().IsInt32MulHigh() && CanCover(node, m.right().node())) {
+    Int32BinopMatcher mright(m.right().node());
+    Emit(kArmSmmla, g.DefineAsRegister(node),
+         g.UseRegister(mright.left().node()),
+         g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
+    return;
+  }
   VisitBinop(this, node, kArmAdd, kArmAdd);
 }
 
@@ -612,6 +628,13 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  ArmOperandGenerator g(this);
+  Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+}
+
+
 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
                     ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
                     InstructionOperand* result_operand,
index c4a7d0e..ce4336a 100644 (file)
@@ -252,6 +252,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Mul32:
       __ Mul(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
       break;
+    case kArm64Smull:
+      __ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
     case kArm64Madd:
       __ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
               i.InputRegister(2));
index 4d19290..63756d1 100644 (file)
@@ -36,6 +36,7 @@ namespace compiler {
   V(Arm64Sub32)                    \
   V(Arm64Mul)                      \
   V(Arm64Mul32)                    \
+  V(Arm64Smull)                    \
   V(Arm64Madd)                     \
   V(Arm64Madd32)                   \
   V(Arm64Msub)                     \
index 893c005..04c486f 100644 (file)
@@ -746,6 +746,16 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  // TODO(arm64): Can we do better here?
+  Arm64OperandGenerator g(this);
+  InstructionOperand* const smull_operand = g.TempRegister();
+  Emit(kArm64Smull, smull_operand, g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+  Emit(kArm64Asr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
+}
+
+
 void InstructionSelector::VisitInt32Div(Node* node) {
   VisitRRR(this, kArm64Idiv32, node);
 }
index 8543fd7..81cf899 100644 (file)
@@ -244,6 +244,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
         __ imul(i.OutputRegister(), i.InputOperand(1));
       }
       break;
+    case kIA32ImulHigh:
+      __ imul(i.InputRegister(1));
+      break;
     case kIA32Idiv:
       __ cdq();
       __ idiv(i.InputOperand(1));
index 91844c4..251a489 100644 (file)
@@ -20,6 +20,7 @@ namespace compiler {
   V(IA32Xor)                       \
   V(IA32Sub)                       \
   V(IA32Imul)                      \
+  V(IA32ImulHigh)                  \
   V(IA32Idiv)                      \
   V(IA32Udiv)                      \
   V(IA32Not)                       \
index d6edb45..add0a3f 100644 (file)
@@ -455,6 +455,16 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  IA32OperandGenerator g(this);
+  InstructionOperand* temps[] = {g.TempRegister(eax)};
+  size_t temp_count = arraysize(temps);
+  Emit(kIA32ImulHigh, g.DefineAsFixed(node, edx),
+       g.UseFixed(node->InputAt(0), eax), g.UseRegister(node->InputAt(1)),
+       temp_count, temps);
+}
+
+
 static inline void VisitDiv(InstructionSelector* selector, Node* node,
                             ArchOpcode opcode) {
   IA32OperandGenerator g(selector);
index 0cfd950..bd3bfd7 100644 (file)
@@ -658,6 +658,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitInt32SubWithOverflow(node);
     case IrOpcode::kInt32Mul:
       return VisitInt32Mul(node);
+    case IrOpcode::kInt32MulHigh:
+      return VisitInt32MulHigh(node);
     case IrOpcode::kInt32Div:
       return VisitInt32Div(node);
     case IrOpcode::kInt32Mod:
index cdb2182..6d02272 100644 (file)
@@ -5,6 +5,7 @@
 #include "src/compiler/machine-operator-reducer.h"
 
 #include "src/base/bits.h"
+#include "src/base/division-by-constant.h"
 #include "src/codegen.h"
 #include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
@@ -42,6 +43,54 @@ Node* MachineOperatorReducer::Int64Constant(int64_t value) {
 }
 
 
+Node* MachineOperatorReducer::Word32And(Node* lhs, uint32_t rhs) {
+  return graph()->NewNode(machine()->Word32And(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
+  return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
+  return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Add(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::TruncatingDiv(Node* dividend, int32_t divisor) {
+  DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
+  base::MagicNumbersForDivision<uint32_t> const mag =
+      base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+  Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
+                                    Uint32Constant(mag.multiplier));
+  if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
+    quotient = Int32Add(quotient, dividend);
+  } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
+    quotient = Int32Sub(quotient, dividend);
+  }
+  if (mag.shift) {
+    quotient = Word32Sar(quotient, mag.shift);
+  }
+  return Int32Add(quotient, Word32Shr(dividend, 31));
+}
+
+
 // Perform constant folding and strength reduction on machine operators.
 Reduction MachineOperatorReducer::Reduce(Node* node) {
   switch (node->opcode()) {
@@ -227,25 +276,8 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
       }
       break;
     }
-    case IrOpcode::kInt32Div: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(1)) return Replace(m.left().node());  // x / 1 => x
-      // TODO(turbofan): if (m.left().Is(0))
-      // TODO(turbofan): if (m.right().IsPowerOf2())
-      // TODO(turbofan): if (m.right().Is(0))
-      // TODO(turbofan): if (m.LeftEqualsRight())
-      if (m.IsFoldable() && !m.right().Is(0)) {  // K / K => K
-        if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value());
-        return ReplaceInt32(m.left().Value() / m.right().Value());
-      }
-      if (m.right().Is(-1)) {  // x / -1 => 0 - x
-        node->set_op(machine()->Int32Sub());
-        node->ReplaceInput(0, Int32Constant(0));
-        node->ReplaceInput(1, m.left().node());
-        return Changed(node);
-      }
-      break;
-    }
+    case IrOpcode::kInt32Div:
+      return ReduceInt32Div(node);
     case IrOpcode::kUint32Div: {
       Uint32BinopMatcher m(node);
       if (m.right().Is(1)) return Replace(m.left().node());  // x / 1 => x
@@ -499,7 +531,50 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
 }
 
 
-Reduction MachineOperatorReducer::ReduceInt32Mod(Node* const node) {
+Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
+  if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
+  // TODO(turbofan): if (m.left().Is(0))
+  // TODO(turbofan): if (m.LeftEqualsRight())
+  if (m.IsFoldable() && !m.right().Is(0)) {  // K / K => K
+    if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value());
+    return ReplaceInt32(m.left().Value() / m.right().Value());
+  }
+  if (m.right().Is(-1)) {  // x / -1 => 0 - x
+    node->set_op(machine()->Int32Sub());
+    node->ReplaceInput(0, Int32Constant(0));
+    node->ReplaceInput(1, m.left().node());
+    return Changed(node);
+  }
+  if (m.right().HasValue()) {
+    int32_t const divisor = m.right().Value();
+    Node* const dividend = m.left().node();
+    Node* quotient = dividend;
+    if (base::bits::IsPowerOfTwo32(Abs(divisor))) {
+      uint32_t const shift = WhichPowerOf2Abs(divisor);
+      DCHECK_NE(0, shift);
+      if (shift > 1) {
+        quotient = Word32Sar(quotient, 31);
+      }
+      quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
+      quotient = Word32Sar(quotient, shift);
+    } else {
+      quotient = TruncatingDiv(quotient, Abs(divisor));
+    }
+    if (divisor < 0) {
+      node->set_op(machine()->Int32Sub());
+      node->ReplaceInput(0, Int32Constant(0));
+      node->ReplaceInput(1, quotient);
+      return Changed(node);
+    }
+    return Replace(quotient);
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
   Int32BinopMatcher m(node);
   if (m.right().Is(1)) return ReplaceInt32(0);   // x % 1  => 0
   if (m.right().Is(-1)) return ReplaceInt32(0);  // x % -1 => 0
@@ -509,29 +584,35 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* const node) {
   if (m.IsFoldable() && !m.right().Is(0)) {  // K % K => K
     return ReplaceInt32(m.left().Value() % m.right().Value());
   }
-  if (m.right().IsPowerOf2()) {
-    int32_t const divisor = m.right().Value();
-    Node* zero = Int32Constant(0);
-    Node* mask = Int32Constant(divisor - 1);
-    Node* dividend = m.left().node();
-
-    Node* check = graph()->NewNode(machine()->Int32LessThan(), dividend, zero);
-    Node* branch =
-        graph()->NewNode(common()->Branch(), check, graph()->start());
-
-    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-    Node* neg = graph()->NewNode(
-        machine()->Int32Sub(), zero,
-        graph()->NewNode(
-            machine()->Word32And(),
-            graph()->NewNode(machine()->Int32Sub(), zero, dividend), mask));
-
-    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-    Node* pos = graph()->NewNode(machine()->Word32And(), dividend, mask);
-
-    Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-    Node* phi = graph()->NewNode(common()->Phi(kMachInt32, 2), neg, pos, merge);
-    return Replace(phi);
+  if (m.right().HasValue()) {
+    Node* const dividend = m.left().node();
+    int32_t const divisor = Abs(m.right().Value());
+    if (base::bits::IsPowerOfTwo32(divisor)) {
+      uint32_t const mask = divisor - 1;
+      Node* const zero = Int32Constant(0);
+
+      Node* check =
+          graph()->NewNode(machine()->Int32LessThan(), dividend, zero);
+      Node* branch =
+          graph()->NewNode(common()->Branch(), check, graph()->start());
+
+      Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+      Node* neg = Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask));
+
+      Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+      Node* pos = Word32And(dividend, mask);
+
+      Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+      Node* phi =
+          graph()->NewNode(common()->Phi(kMachInt32, 2), neg, pos, merge);
+      return Replace(phi);
+    } else {
+      Node* quotient = TruncatingDiv(dividend, divisor);
+      node->set_op(machine()->Int32Sub());
+      DCHECK_EQ(dividend, node->InputAt(0));
+      node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
+      return Changed(node);
+    }
   }
   return NoChange();
 }
index d8978a4..92c2337 100644 (file)
@@ -34,6 +34,14 @@ class MachineOperatorReducer FINAL : public Reducer {
   Node* Uint32Constant(uint32_t value) {
     return Int32Constant(bit_cast<uint32_t>(value));
   }
+  Node* Word32And(Node* lhs, uint32_t rhs);
+  Node* Word32Sar(Node* lhs, uint32_t rhs);
+  Node* Word32Shr(Node* lhs, uint32_t rhs);
+  Node* Int32Add(Node* lhs, Node* rhs);
+  Node* Int32Sub(Node* lhs, Node* rhs);
+  Node* Int32Mul(Node* lhs, Node* rhs);
+
+  Node* TruncatingDiv(Node* dividend, int32_t divisor);
 
   Reduction ReplaceBool(bool value) { return ReplaceInt32(value ? 1 : 0); }
   Reduction ReplaceFloat32(volatile float value) {
@@ -49,6 +57,7 @@ class MachineOperatorReducer FINAL : public Reducer {
     return Replace(Int64Constant(value));
   }
 
+  Reduction ReduceInt32Div(Node* node);
   Reduction ReduceInt32Mod(Node* node);
   Reduction ReduceProjection(size_t index, Node* node);
 
index f53e4ba..b5da829 100644 (file)
@@ -75,6 +75,7 @@ StoreRepresentation const& StoreRepresentationOf(Operator const* op) {
   V(Int32Sub, Operator::kNoProperties, 2, 1)                                  \
   V(Int32SubWithOverflow, Operator::kNoProperties, 2, 2)                      \
   V(Int32Mul, Operator::kAssociative | Operator::kCommutative, 2, 1)          \
+  V(Int32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 1)      \
   V(Int32Div, Operator::kNoProperties, 2, 1)                                  \
   V(Int32Mod, Operator::kNoProperties, 2, 1)                                  \
   V(Int32LessThan, Operator::kNoProperties, 2, 1)                             \
index 58be985..568d3eb 100644 (file)
@@ -82,6 +82,7 @@ class MachineOperatorBuilder FINAL {
   const Operator* Int32Sub();
   const Operator* Int32SubWithOverflow();
   const Operator* Int32Mul();
+  const Operator* Int32MulHigh();
   const Operator* Int32Div();
   const Operator* Int32Mod();
   const Operator* Int32LessThan();
index ced9847..ea8263d 100644 (file)
   V(Int32Sub)                 \
   V(Int32SubWithOverflow)     \
   V(Int32Mul)                 \
+  V(Int32MulHigh)             \
   V(Int32Div)                 \
   V(Int32Mod)                 \
   V(Int32LessThan)            \
index 8e68a88..35f884f 100644 (file)
@@ -225,6 +225,9 @@ class RawMachineAssembler : public GraphBuilder {
   Node* Int32Mul(Node* a, Node* b) {
     return NewNode(machine()->Int32Mul(), a, b);
   }
+  Node* Int32MulHigh(Node* a, Node* b) {
+    return NewNode(machine()->Int32MulHigh(), a, b);
+  }
   Node* Int32Div(Node* a, Node* b) {
     return NewNode(machine()->Int32Div(), a, b);
   }
index 4411876..361862c 100644 (file)
@@ -283,6 +283,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kX64Imul:
       ASSEMBLE_MULT(imulq);
       break;
+    case kX64ImulHigh32:
+      __ imull(i.InputRegister(1));
+      break;
     case kX64Idiv32:
       __ cdq();
       __ idivl(i.InputRegister(1));
index 6767164..835baf5 100644 (file)
@@ -28,6 +28,7 @@ namespace compiler {
   V(X64Sub32)                      \
   V(X64Imul)                       \
   V(X64Imul32)                     \
+  V(X64ImulHigh32)                 \
   V(X64Idiv)                       \
   V(X64Idiv32)                     \
   V(X64Udiv)                       \
index 6a3d9c0..d102e84 100644 (file)
@@ -546,6 +546,16 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
 }
 
 
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  X64OperandGenerator g(this);
+  InstructionOperand* temps[] = {g.TempRegister(rax)};
+  size_t temp_count = arraysize(temps);
+  Emit(kX64ImulHigh32, g.DefineAsFixed(node, rdx),
+       g.UseFixed(node->InputAt(0), rax), g.UseRegister(node->InputAt(1)),
+       temp_count, temps);
+}
+
+
 static void VisitDiv(InstructionSelector* selector, Node* node,
                      ArchOpcode opcode) {
   X64OperandGenerator g(selector);
index b861967..527b269 100644 (file)
@@ -58,25 +58,25 @@ static Node* Int32Input(RawMachineAssemblerTester<int32_t>* m, int index) {
 TEST(CodeGenInt32Binop) {
   RawMachineAssemblerTester<void> m;
 
-  const Operator* ops[] = {
-      m.machine()->Word32And(),      m.machine()->Word32Or(),
-      m.machine()->Word32Xor(),      m.machine()->Word32Shl(),
-      m.machine()->Word32Shr(),      m.machine()->Word32Sar(),
-      m.machine()->Word32Equal(),    m.machine()->Int32Add(),
-      m.machine()->Int32Sub(),       m.machine()->Int32Mul(),
-      m.machine()->Int32Div(),       m.machine()->Uint32Div(),
-      m.machine()->Int32Mod(),       m.machine()->Uint32Mod(),
-      m.machine()->Int32LessThan(),  m.machine()->Int32LessThanOrEqual(),
-      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(),
-      NULL};
-
-  for (int i = 0; ops[i] != NULL; i++) {
+  const Operator* kOps[] = {
+      m.machine()->Word32And(),            m.machine()->Word32Or(),
+      m.machine()->Word32Xor(),            m.machine()->Word32Shl(),
+      m.machine()->Word32Shr(),            m.machine()->Word32Sar(),
+      m.machine()->Word32Equal(),          m.machine()->Int32Add(),
+      m.machine()->Int32Sub(),             m.machine()->Int32Mul(),
+      m.machine()->Int32MulHigh(),         m.machine()->Int32Div(),
+      m.machine()->Uint32Div(),            m.machine()->Int32Mod(),
+      m.machine()->Uint32Mod(),            m.machine()->Int32LessThan(),
+      m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(),
+      m.machine()->Uint32LessThanOrEqual()};
+
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     for (int j = 0; j < 8; j++) {
       for (int k = 0; k < 8; k++) {
         RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
         Node* a = Int32Input(&m, j);
         Node* b = Int32Input(&m, k);
-        m.Return(m.NewNode(ops[i], a, b));
+        m.Return(m.NewNode(kOps[i], a, b));
         m.GenerateCode();
       }
     }
@@ -1233,6 +1233,20 @@ TEST(RunInt32MulP) {
 }
 
 
+TEST(RunInt32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Int32MulHigh(bt.param0, bt.param1));
+  FOR_INT32_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      int32_t expected = static_cast<int32_t>(
+          (static_cast<int64_t>(*i) * static_cast<int64_t>(*j)) >> 32);
+      CHECK_EQ(expected, bt.call(*i, *j));
+    }
+  }
+}
+
+
 TEST(RunInt32MulImm) {
   {
     FOR_UINT32_INPUTS(i) {
@@ -2674,22 +2688,22 @@ TEST(RunDeadNodes) {
 TEST(RunDeadInt32Binops) {
   RawMachineAssemblerTester<int32_t> m;
 
-  const Operator* ops[] = {
-      m.machine()->Word32And(),             m.machine()->Word32Or(),
-      m.machine()->Word32Xor(),             m.machine()->Word32Shl(),
-      m.machine()->Word32Shr(),             m.machine()->Word32Sar(),
-      m.machine()->Word32Ror(),             m.machine()->Word32Equal(),
-      m.machine()->Int32Add(),              m.machine()->Int32Sub(),
-      m.machine()->Int32Mul(),              m.machine()->Int32Div(),
-      m.machine()->Uint32Div(),             m.machine()->Int32Mod(),
-      m.machine()->Uint32Mod(),             m.machine()->Int32LessThan(),
-      m.machine()->Int32LessThanOrEqual(),  m.machine()->Uint32LessThan(),
-      m.machine()->Uint32LessThanOrEqual(), NULL};
+  const Operator* kOps[] = {
+      m.machine()->Word32And(),      m.machine()->Word32Or(),
+      m.machine()->Word32Xor(),      m.machine()->Word32Shl(),
+      m.machine()->Word32Shr(),      m.machine()->Word32Sar(),
+      m.machine()->Word32Ror(),      m.machine()->Word32Equal(),
+      m.machine()->Int32Add(),       m.machine()->Int32Sub(),
+      m.machine()->Int32Mul(),       m.machine()->Int32MulHigh(),
+      m.machine()->Int32Div(),       m.machine()->Uint32Div(),
+      m.machine()->Int32Mod(),       m.machine()->Uint32Mod(),
+      m.machine()->Int32LessThan(),  m.machine()->Int32LessThanOrEqual(),
+      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual()};
 
-  for (int i = 0; ops[i] != NULL; i++) {
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
-    int constant = 0x55555 + i;
-    m.NewNode(ops[i], m.Parameter(0), m.Parameter(1));
+    int32_t constant = static_cast<int32_t>(0x55555 + i);
+    m.NewNode(kOps[i], m.Parameter(0), m.Parameter(1));
     m.Return(m.Int32Constant(constant));
 
     CHECK_EQ(constant, m.Call(1, 1));
diff --git a/test/mjsunit/asm/int32div.js b/test/mjsunit/asm/int32div.js
new file mode 100644 (file)
index 0000000..f5d2433
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Div(divisor) {
+  var name = "div_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) / " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var div = Int32Div(divisor);
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend / divisor) | 0, div(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/int32mod.js b/test/mjsunit/asm/int32mod.js
new file mode 100644 (file)
index 0000000..ec3e887
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Mod(divisor) {
+  var name = "mod_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) % " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Int32Mod(divisor);
+  for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend % divisor) | 0, mod(dividend));
+  }
+}
index f0931c7..0c71d2f 100644 (file)
@@ -1369,27 +1369,105 @@ TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
 TEST_F(InstructionSelectorTest, Int32AddWithInt32Mul) {
   {
     StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(
-        m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(p0, m.Int32Mul(p1, p2));
+    m.Return(n);
     Stream s = m.Build();
     ASSERT_EQ(1U, s.size());
     EXPECT_EQ(kArmMla, s[0]->arch_opcode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
   }
   {
     StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-    m.Return(
-        m.Int32Add(m.Int32Mul(m.Parameter(1), m.Parameter(2)), m.Parameter(0)));
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(m.Int32Mul(p1, p2), p0);
+    m.Return(n);
     Stream s = m.Build();
     ASSERT_EQ(1U, s.size());
     EXPECT_EQ(kArmMla, s[0]->arch_opcode());
-    EXPECT_EQ(3U, s[0]->InputCount());
-    EXPECT_EQ(1U, s[0]->OutputCount());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
   }
 }
 
 
+TEST_F(InstructionSelectorTest, Int32AddWithInt32MulHigh) {
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(p0, m.Int32MulHigh(p1, p2));
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSmmla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+  {
+    StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+    Node* const p0 = m.Parameter(0);
+    Node* const p1 = m.Parameter(1);
+    Node* const p2 = m.Parameter(2);
+    Node* const n = m.Int32Add(m.Int32MulHigh(p1, p2), p0);
+    m.Return(n);
+    Stream s = m.Build();
+    ASSERT_EQ(1U, s.size());
+    EXPECT_EQ(kArmSmmla, s[0]->arch_opcode());
+    ASSERT_EQ(3U, s[0]->InputCount());
+    EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(0)));
+    EXPECT_EQ(s.ToVreg(p2), s.ToVreg(s[0]->InputAt(1)));
+    EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(2)));
+    ASSERT_EQ(1U, s[0]->OutputCount());
+    EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  }
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArmSub, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1)));
+}
+
+
+TEST_F(InstructionSelectorTest, Int32SubWithInt32MulForMLS) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
+  m.Return(
+      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+  Stream s = m.Build(MLS);
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmMls, s[0]->arch_opcode());
+  EXPECT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(3U, s[0]->InputCount());
+}
+
+
 TEST_F(InstructionSelectorTest, Int32DivWithParameters) {
   StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
   m.Return(m.Int32Div(m.Parameter(0), m.Parameter(1)));
@@ -1554,29 +1632,20 @@ TEST_F(InstructionSelectorTest, Int32MulWithImmediate) {
 }
 
 
-TEST_F(InstructionSelectorTest, Int32SubWithInt32Mul) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(
-      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
+TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
   Stream s = m.Build();
-  ASSERT_EQ(2U, s.size());
-  EXPECT_EQ(kArmMul, s[0]->arch_opcode());
-  ASSERT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(kArmSub, s[1]->arch_opcode());
-  ASSERT_EQ(2U, s[1]->InputCount());
-  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(1)));
-}
-
-
-TEST_F(InstructionSelectorTest, Int32SubWithInt32MulForMLS) {
-  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32, kMachInt32);
-  m.Return(
-      m.Int32Sub(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
-  Stream s = m.Build(MLS);
   ASSERT_EQ(1U, s.size());
-  EXPECT_EQ(kArmMls, s[0]->arch_opcode());
-  EXPECT_EQ(1U, s[0]->OutputCount());
-  EXPECT_EQ(3U, s[0]->InputCount());
+  EXPECT_EQ(kArmSmmul, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
 }
 
 
index b4c3145..81ed616 100644 (file)
@@ -1759,6 +1759,28 @@ TEST_F(InstructionSelectorTest, Word64AndWithImmediateWithWord64Shr) {
   }
 }
 
+
+TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(2U, s.size());
+  EXPECT_EQ(kArm64Smull, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(kArm64Asr, s[1]->arch_opcode());
+  ASSERT_EQ(2U, s[1]->InputCount());
+  EXPECT_EQ(s.ToVreg(s[0]->Output()), s.ToVreg(s[1]->InputAt(0)));
+  EXPECT_EQ(32, s.ToInt64(s[1]->InputAt(1)));
+  ASSERT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[1]->Output()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 4fc3c87..5c414ab 100644 (file)
@@ -941,6 +941,7 @@ IS_BINOP_MATCHER(NumberSubtract)
 IS_BINOP_MATCHER(Word32And)
 IS_BINOP_MATCHER(Word32Sar)
 IS_BINOP_MATCHER(Word32Shl)
+IS_BINOP_MATCHER(Word32Shr)
 IS_BINOP_MATCHER(Word32Ror)
 IS_BINOP_MATCHER(Word32Equal)
 IS_BINOP_MATCHER(Word64And)
@@ -948,8 +949,10 @@ IS_BINOP_MATCHER(Word64Sar)
 IS_BINOP_MATCHER(Word64Shl)
 IS_BINOP_MATCHER(Word64Equal)
 IS_BINOP_MATCHER(Int32AddWithOverflow)
+IS_BINOP_MATCHER(Int32Add)
 IS_BINOP_MATCHER(Int32Sub)
 IS_BINOP_MATCHER(Int32Mul)
+IS_BINOP_MATCHER(Int32MulHigh)
 IS_BINOP_MATCHER(Int32LessThan)
 IS_BINOP_MATCHER(Uint32LessThan)
 IS_BINOP_MATCHER(Uint32LessThanOrEqual)
index 84fb6ee..ee66629 100644 (file)
@@ -134,6 +134,8 @@ Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher,
                            const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsWord32Shl(const Matcher<Node*>& lhs_matcher,
                            const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsWord32Shr(const Matcher<Node*>& lhs_matcher,
+                           const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsWord32Ror(const Matcher<Node*>& lhs_matcher,
                            const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher,
@@ -148,10 +150,14 @@ Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_matcher,
                              const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsInt32AddWithOverflow(const Matcher<Node*>& lhs_matcher,
                                       const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32Add(const Matcher<Node*>& lhs_matcher,
+                          const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsInt32Sub(const Matcher<Node*>& lhs_matcher,
                           const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsInt32Mul(const Matcher<Node*>& lhs_matcher,
                           const Matcher<Node*>& rhs_matcher);
+Matcher<Node*> IsInt32MulHigh(const Matcher<Node*>& lhs_matcher,
+                              const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsInt32LessThan(const Matcher<Node*>& lhs_matcher,
                                const Matcher<Node*>& rhs_matcher);
 Matcher<Node*> IsUint32LessThan(const Matcher<Node*>& lhs_matcher,
index e892ad3..2ce7bca 100644 (file)
@@ -103,6 +103,7 @@ TEST_F(InstructionSelectorTest, TruncateFloat64ToFloat32WithParameter) {
 // -----------------------------------------------------------------------------
 // Better left operand for commutative binops
 
+
 TEST_F(InstructionSelectorTest, BetterLeftOperandTestAddBinop) {
   StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
   Node* param1 = m.Parameter(0);
@@ -136,6 +137,7 @@ TEST_F(InstructionSelectorTest, BetterLeftOperandTestMulBinop) {
 // -----------------------------------------------------------------------------
 // Conversions.
 
+
 TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
   StreamBuilder m(this, kMachFloat64, kMachUint32);
   m.Return(m.ChangeUint32ToFloat64(m.Parameter(0)));
@@ -148,6 +150,7 @@ TEST_F(InstructionSelectorTest, ChangeUint32ToFloat64WithParameter) {
 // -----------------------------------------------------------------------------
 // Loads and stores
 
+
 namespace {
 
 struct MemoryAccess {
@@ -295,6 +298,7 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
 // -----------------------------------------------------------------------------
 // AddressingMode for loads and stores.
 
+
 class AddressingModeUnitTest : public InstructionSelectorTest {
  public:
   AddressingModeUnitTest() : m(NULL) { Reset(); }
@@ -438,6 +442,7 @@ TEST_F(AddressingModeUnitTest, AddressingMode_MI) {
 // -----------------------------------------------------------------------------
 // Multiplication.
 
+
 namespace {
 
 struct MultParam {
@@ -576,6 +581,23 @@ TEST_P(InstructionSelectorMultTest, MultAdd32) {
 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
                         ::testing::ValuesIn(kMultParams));
 
+
+TEST_F(InstructionSelectorTest, Int32MulHigh) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kIA32ImulHigh, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 9ee74ce..19fcecd 100644 (file)
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "src/base/bits.h"
+#include "src/base/division-by-constant.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator-reducer.h"
 #include "src/compiler/typer.h"
@@ -31,6 +32,26 @@ class MachineOperatorReducerTest : public GraphTest {
     return reducer.Reduce(node);
   }
 
+  Matcher<Node*> IsTruncatingDiv(const Matcher<Node*>& dividend_matcher,
+                                 const int32_t divisor) {
+    base::MagicNumbersForDivision<uint32_t> const mag =
+        base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+    int32_t const multiplier = bit_cast<int32_t>(mag.multiplier);
+    int32_t const shift = bit_cast<int32_t>(mag.shift);
+    Matcher<Node*> quotient_matcher =
+        IsInt32MulHigh(dividend_matcher, IsInt32Constant(multiplier));
+    if (divisor > 0 && multiplier < 0) {
+      quotient_matcher = IsInt32Add(quotient_matcher, dividend_matcher);
+    } else if (divisor < 0 && multiplier > 0) {
+      quotient_matcher = IsInt32Sub(quotient_matcher, dividend_matcher);
+    }
+    if (shift) {
+      quotient_matcher = IsWord32Sar(quotient_matcher, IsInt32Constant(shift));
+    }
+    return IsInt32Add(quotient_matcher,
+                      IsWord32Shr(dividend_matcher, IsInt32Constant(31)));
+  }
+
   MachineOperatorBuilder* machine() { return &machine_; }
 
  private:
@@ -51,7 +72,7 @@ class MachineOperatorReducerTestWithParam
 
 namespace {
 
-static const float kFloat32Values[] = {
+const float kFloat32Values[] = {
     -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f,
     -1.22813e+35f,                           -1.20555e+35f, -1.34584e+34f,
     -1.0079e+32f,                            -6.49364e+26f, -3.06077e+25f,
@@ -88,7 +109,7 @@ static const float kFloat32Values[] = {
     std::numeric_limits<float>::infinity()};
 
 
-static const double kFloat64Values[] = {
+const double kFloat64Values[] = {
     -V8_INFINITY,  -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
     -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
     -1.67813e+72,  -2.3382e+55,   -3.179e+30,    -1.441e+09,    -1.0647e+09,
@@ -111,83 +132,97 @@ static const double kFloat64Values[] = {
     5.72883e+289,  8.5798e+290,   1.40256e+294,  1.79769e+308,  V8_INFINITY};
 
 
-static const int32_t kInt32Values[] = {
-    -2147483647 - 1, -1914954528, -1698749618, -1578693386, -1577976073,
-    -1573998034,     -1529085059, -1499540537, -1299205097, -1090814845,
-    -938186388,      -806828902,  -750927650,  -520676892,  -513661538,
-    -453036354,      -433622833,  -282638793,  -28375,      -27788,
-    -22770,          -18806,      -14173,      -11956,      -11200,
-    -10212,          -8160,       -3751,       -2758,       -1522,
-    -121,            -120,        -118,        -117,        -106,
-    -84,             -80,         -74,         -59,         -52,
-    -48,             -39,         -35,         -17,         -11,
-    -10,             -9,          -7,          -5,          0,
-    9,               12,          17,          23,          29,
-    31,              33,          35,          40,          47,
-    55,              56,          62,          64,          67,
-    68,              69,          74,          79,          84,
-    89,              90,          97,          104,         118,
-    124,             126,         127,         7278,        17787,
-    24136,           24202,       25570,       26680,       30242,
-    32399,           420886487,   642166225,   821912648,   822577803,
-    851385718,       1212241078,  1411419304,  1589626102,  1596437184,
-    1876245816,      1954730266,  2008792749,  2045320228,  2147483647};
-
-
-static const int64_t kInt64Values[] = {
-    V8_INT64_C(-9223372036854775807) - 1, V8_INT64_C(-8974392461363618006),
-    V8_INT64_C(-8874367046689588135),     V8_INT64_C(-8269197512118230839),
-    V8_INT64_C(-8146091527100606733),     V8_INT64_C(-7550917981466150848),
-    V8_INT64_C(-7216590251577894337),     V8_INT64_C(-6464086891160048440),
-    V8_INT64_C(-6365616494908257190),     V8_INT64_C(-6305630541365849726),
-    V8_INT64_C(-5982222642272245453),     V8_INT64_C(-5510103099058504169),
-    V8_INT64_C(-5496838675802432701),     V8_INT64_C(-4047626578868642657),
-    V8_INT64_C(-4033755046900164544),     V8_INT64_C(-3554299241457877041),
-    V8_INT64_C(-2482258764588614470),     V8_INT64_C(-1688515425526875335),
-    V8_INT64_C(-924784137176548532),      V8_INT64_C(-725316567157391307),
-    V8_INT64_C(-439022654781092241),      V8_INT64_C(-105545757668917080),
-    V8_INT64_C(-2088319373),              V8_INT64_C(-2073699916),
-    V8_INT64_C(-1844949911),              V8_INT64_C(-1831090548),
-    V8_INT64_C(-1756711933),              V8_INT64_C(-1559409497),
-    V8_INT64_C(-1281179700),              V8_INT64_C(-1211513985),
-    V8_INT64_C(-1182371520),              V8_INT64_C(-785934753),
-    V8_INT64_C(-767480697),               V8_INT64_C(-705745662),
-    V8_INT64_C(-514362436),               V8_INT64_C(-459916580),
-    V8_INT64_C(-312328082),               V8_INT64_C(-302949707),
-    V8_INT64_C(-285499304),               V8_INT64_C(-125701262),
-    V8_INT64_C(-95139843),                V8_INT64_C(-32768),
-    V8_INT64_C(-27542),                   V8_INT64_C(-23600),
-    V8_INT64_C(-18582),                   V8_INT64_C(-17770),
-    V8_INT64_C(-9086),                    V8_INT64_C(-9010),
-    V8_INT64_C(-8244),                    V8_INT64_C(-2890),
-    V8_INT64_C(-103),                     V8_INT64_C(-34),
-    V8_INT64_C(-27),                      V8_INT64_C(-25),
-    V8_INT64_C(-9),                       V8_INT64_C(-7),
-    V8_INT64_C(0),                        V8_INT64_C(2),
-    V8_INT64_C(38),                       V8_INT64_C(58),
-    V8_INT64_C(65),                       V8_INT64_C(93),
-    V8_INT64_C(111),                      V8_INT64_C(1003),
-    V8_INT64_C(1267),                     V8_INT64_C(12797),
-    V8_INT64_C(23122),                    V8_INT64_C(28200),
-    V8_INT64_C(30888),                    V8_INT64_C(42648848),
-    V8_INT64_C(116836693),                V8_INT64_C(263003643),
-    V8_INT64_C(571039860),                V8_INT64_C(1079398689),
-    V8_INT64_C(1145196402),               V8_INT64_C(1184846321),
-    V8_INT64_C(1758281648),               V8_INT64_C(1859991374),
-    V8_INT64_C(1960251588),               V8_INT64_C(2042443199),
-    V8_INT64_C(296220586027987448),       V8_INT64_C(1015494173071134726),
-    V8_INT64_C(1151237951914455318),      V8_INT64_C(1331941174616854174),
-    V8_INT64_C(2022020418667972654),      V8_INT64_C(2450251424374977035),
-    V8_INT64_C(3668393562685561486),      V8_INT64_C(4858229301215502171),
-    V8_INT64_C(4919426235170669383),      V8_INT64_C(5034286595330341762),
-    V8_INT64_C(5055797915536941182),      V8_INT64_C(6072389716149252074),
-    V8_INT64_C(6185309910199801210),      V8_INT64_C(6297328311011094138),
-    V8_INT64_C(6932372858072165827),      V8_INT64_C(8483640924987737210),
-    V8_INT64_C(8663764179455849203),      V8_INT64_C(8877197042645298254),
-    V8_INT64_C(8901543506779157333),      V8_INT64_C(9223372036854775807)};
-
-
-static const uint32_t kUint32Values[] = {
+const int32_t kInt32Values[] = {
+    std::numeric_limits<int32_t>::min(), -1914954528, -1698749618,
+    -1578693386,                         -1577976073, -1573998034,
+    -1529085059,                         -1499540537, -1299205097,
+    -1090814845,                         -938186388,  -806828902,
+    -750927650,                          -520676892,  -513661538,
+    -453036354,                          -433622833,  -282638793,
+    -28375,                              -27788,      -22770,
+    -18806,                              -14173,      -11956,
+    -11200,                              -10212,      -8160,
+    -3751,                               -2758,       -1522,
+    -121,                                -120,        -118,
+    -117,                                -106,        -84,
+    -80,                                 -74,         -59,
+    -52,                                 -48,         -39,
+    -35,                                 -17,         -11,
+    -10,                                 -9,          -7,
+    -5,                                  0,           9,
+    12,                                  17,          23,
+    29,                                  31,          33,
+    35,                                  40,          47,
+    55,                                  56,          62,
+    64,                                  67,          68,
+    69,                                  74,          79,
+    84,                                  89,          90,
+    97,                                  104,         118,
+    124,                                 126,         127,
+    7278,                                17787,       24136,
+    24202,                               25570,       26680,
+    30242,                               32399,       420886487,
+    642166225,                           821912648,   822577803,
+    851385718,                           1212241078,  1411419304,
+    1589626102,                          1596437184,  1876245816,
+    1954730266,                          2008792749,  2045320228,
+    std::numeric_limits<int32_t>::max()};
+
+
+const int64_t kInt64Values[] = {
+    std::numeric_limits<int64_t>::min(), V8_INT64_C(-8974392461363618006),
+    V8_INT64_C(-8874367046689588135),    V8_INT64_C(-8269197512118230839),
+    V8_INT64_C(-8146091527100606733),    V8_INT64_C(-7550917981466150848),
+    V8_INT64_C(-7216590251577894337),    V8_INT64_C(-6464086891160048440),
+    V8_INT64_C(-6365616494908257190),    V8_INT64_C(-6305630541365849726),
+    V8_INT64_C(-5982222642272245453),    V8_INT64_C(-5510103099058504169),
+    V8_INT64_C(-5496838675802432701),    V8_INT64_C(-4047626578868642657),
+    V8_INT64_C(-4033755046900164544),    V8_INT64_C(-3554299241457877041),
+    V8_INT64_C(-2482258764588614470),    V8_INT64_C(-1688515425526875335),
+    V8_INT64_C(-924784137176548532),     V8_INT64_C(-725316567157391307),
+    V8_INT64_C(-439022654781092241),     V8_INT64_C(-105545757668917080),
+    V8_INT64_C(-2088319373),             V8_INT64_C(-2073699916),
+    V8_INT64_C(-1844949911),             V8_INT64_C(-1831090548),
+    V8_INT64_C(-1756711933),             V8_INT64_C(-1559409497),
+    V8_INT64_C(-1281179700),             V8_INT64_C(-1211513985),
+    V8_INT64_C(-1182371520),             V8_INT64_C(-785934753),
+    V8_INT64_C(-767480697),              V8_INT64_C(-705745662),
+    V8_INT64_C(-514362436),              V8_INT64_C(-459916580),
+    V8_INT64_C(-312328082),              V8_INT64_C(-302949707),
+    V8_INT64_C(-285499304),              V8_INT64_C(-125701262),
+    V8_INT64_C(-95139843),               V8_INT64_C(-32768),
+    V8_INT64_C(-27542),                  V8_INT64_C(-23600),
+    V8_INT64_C(-18582),                  V8_INT64_C(-17770),
+    V8_INT64_C(-9086),                   V8_INT64_C(-9010),
+    V8_INT64_C(-8244),                   V8_INT64_C(-2890),
+    V8_INT64_C(-103),                    V8_INT64_C(-34),
+    V8_INT64_C(-27),                     V8_INT64_C(-25),
+    V8_INT64_C(-9),                      V8_INT64_C(-7),
+    V8_INT64_C(0),                       V8_INT64_C(2),
+    V8_INT64_C(38),                      V8_INT64_C(58),
+    V8_INT64_C(65),                      V8_INT64_C(93),
+    V8_INT64_C(111),                     V8_INT64_C(1003),
+    V8_INT64_C(1267),                    V8_INT64_C(12797),
+    V8_INT64_C(23122),                   V8_INT64_C(28200),
+    V8_INT64_C(30888),                   V8_INT64_C(42648848),
+    V8_INT64_C(116836693),               V8_INT64_C(263003643),
+    V8_INT64_C(571039860),               V8_INT64_C(1079398689),
+    V8_INT64_C(1145196402),              V8_INT64_C(1184846321),
+    V8_INT64_C(1758281648),              V8_INT64_C(1859991374),
+    V8_INT64_C(1960251588),              V8_INT64_C(2042443199),
+    V8_INT64_C(296220586027987448),      V8_INT64_C(1015494173071134726),
+    V8_INT64_C(1151237951914455318),     V8_INT64_C(1331941174616854174),
+    V8_INT64_C(2022020418667972654),     V8_INT64_C(2450251424374977035),
+    V8_INT64_C(3668393562685561486),     V8_INT64_C(4858229301215502171),
+    V8_INT64_C(4919426235170669383),     V8_INT64_C(5034286595330341762),
+    V8_INT64_C(5055797915536941182),     V8_INT64_C(6072389716149252074),
+    V8_INT64_C(6185309910199801210),     V8_INT64_C(6297328311011094138),
+    V8_INT64_C(6932372858072165827),     V8_INT64_C(8483640924987737210),
+    V8_INT64_C(8663764179455849203),     V8_INT64_C(8877197042645298254),
+    V8_INT64_C(8901543506779157333),     std::numeric_limits<int64_t>::max()};
+
+
+const uint32_t kUint32Values[] = {
     0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
     0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
     0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
@@ -569,21 +604,115 @@ TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Shr) {
 
 
 // -----------------------------------------------------------------------------
+// Int32Div
+
+
+TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
+  Node* const p0 = Parameter(0);
+  {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(0)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(1)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_EQ(r.replacement(), p0);
+  }
+  {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(-1)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), p0));
+  }
+  {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(2)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsWord32Sar(IsInt32Add(IsWord32Shr(p0, IsInt32Constant(31)), p0),
+                    IsInt32Constant(1)));
+  }
+  {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(-2)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsInt32Sub(
+            IsInt32Constant(0),
+            IsWord32Sar(IsInt32Add(IsWord32Shr(p0, IsInt32Constant(31)), p0),
+                        IsInt32Constant(1))));
+  }
+  TRACED_FORRANGE(int32_t, shift, 2, 30) {
+    Reduction const r = Reduce(
+        graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(1 << shift)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsWord32Sar(IsInt32Add(IsWord32Shr(IsWord32Sar(p0, IsInt32Constant(31)),
+                                           IsInt32Constant(32 - shift)),
+                               p0),
+                    IsInt32Constant(shift)));
+  }
+  TRACED_FORRANGE(int32_t, shift, 2, 31) {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0,
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(
+        r.replacement(),
+        IsInt32Sub(
+            IsInt32Constant(0),
+            IsWord32Sar(
+                IsInt32Add(IsWord32Shr(IsWord32Sar(p0, IsInt32Constant(31)),
+                                       IsInt32Constant(32 - shift)),
+                           p0),
+                IsInt32Constant(shift))));
+  }
+  TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+    if (divisor < 0) {
+      if (base::bits::IsPowerOfTwo32(-divisor)) continue;
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(divisor)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0),
+                                              IsTruncatingDiv(p0, -divisor)));
+    } else if (divisor > 0) {
+      if (base::bits::IsPowerOfTwo32(divisor)) continue;
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(divisor)));
+      ASSERT_TRUE(r.Changed());
+      EXPECT_THAT(r.replacement(), IsTruncatingDiv(p0, divisor));
+    }
+  }
+}
+
+
+// -----------------------------------------------------------------------------
 // Int32Mod
 
 
-TEST_F(MachineOperatorReducerTest, Int32ModWithPowerOfTwo) {
-  Node* p0 = Parameter(0);
-  TRACED_FORRANGE(int32_t, x, 1, 30) {
-    int32_t const divisor = 1 << x;
-    Node* node =
-        graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(divisor));
-    Reduction r = Reduce(node);
+TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
+  Node* const p0 = Parameter(0);
+  static const int32_t kOnes[] = {-1, 1};
+  TRACED_FOREACH(int32_t, one, kOnes) {
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(one)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(), IsInt32Constant(0));
+  }
+  TRACED_FORRANGE(int32_t, shift, 1, 30) {
+    Reduction const r = Reduce(
+        graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1 << shift)));
     ASSERT_TRUE(r.Changed());
 
     Capture<Node*> branch;
-    Node* phi = r.replacement();
-    int32_t const mask = divisor - 1;
+    Node* const phi = r.replacement();
+    int32_t const mask = (1 << shift) - 1;
     EXPECT_THAT(
         phi, IsPhi(kMachInt32,
                    IsInt32Sub(IsInt32Constant(0),
@@ -596,6 +725,36 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithPowerOfTwo) {
                                IsBranch(IsInt32LessThan(p0, IsInt32Constant(0)),
                                         graph()->start()))))));
   }
+  TRACED_FORRANGE(int32_t, shift, 1, 31) {
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0,
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift)));
+    ASSERT_TRUE(r.Changed());
+
+    Capture<Node*> branch;
+    Node* const phi = r.replacement();
+    int32_t const mask = bit_cast<int32_t, uint32_t>((1U << shift) - 1);
+    EXPECT_THAT(
+        phi, IsPhi(kMachInt32,
+                   IsInt32Sub(IsInt32Constant(0),
+                              IsWord32And(IsInt32Sub(IsInt32Constant(0), p0),
+                                          IsInt32Constant(mask))),
+                   IsWord32And(p0, IsInt32Constant(mask)),
+                   IsMerge(IsIfTrue(CaptureEq(&branch)),
+                           IsIfFalse(AllOf(
+                               CaptureEq(&branch),
+                               IsBranch(IsInt32LessThan(p0, IsInt32Constant(0)),
+                                        graph()->start()))))));
+  }
+  TRACED_FOREACH(int32_t, divisor, kInt32Values) {
+    if (divisor == 0 || base::bits::IsPowerOfTwo32(Abs(divisor))) continue;
+    Reduction const r = Reduce(
+        graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(divisor)));
+    ASSERT_TRUE(r.Changed());
+    EXPECT_THAT(r.replacement(),
+                IsInt32Sub(p0, IsInt32Mul(IsTruncatingDiv(p0, Abs(divisor)),
+                                          IsInt32Constant(Abs(divisor)))));
+  }
 }
 
 
index 0f63e3c..9d66f9e 100644 (file)
@@ -173,35 +173,36 @@ const PureOperator kPureOperators[] = {
     &MachineOperatorBuilder::Name, IrOpcode::k##Name, input_count, \
         output_count                                               \
   }
-    PURE(Word32And, 2, 1),              PURE(Word32Or, 2, 1),
-    PURE(Word32Xor, 2, 1),              PURE(Word32Shl, 2, 1),
-    PURE(Word32Shr, 2, 1),              PURE(Word32Sar, 2, 1),
-    PURE(Word32Ror, 2, 1),              PURE(Word32Equal, 2, 1),
-    PURE(Word64And, 2, 1),              PURE(Word64Or, 2, 1),
-    PURE(Word64Xor, 2, 1),              PURE(Word64Shl, 2, 1),
-    PURE(Word64Shr, 2, 1),              PURE(Word64Sar, 2, 1),
-    PURE(Word64Ror, 2, 1),              PURE(Word64Equal, 2, 1),
-    PURE(Int32Add, 2, 1),               PURE(Int32AddWithOverflow, 2, 2),
-    PURE(Int32Sub, 2, 1),               PURE(Int32SubWithOverflow, 2, 2),
-    PURE(Int32Mul, 2, 1),               PURE(Int32Div, 2, 1),
-    PURE(Uint32Div, 2, 1),              PURE(Int32Mod, 2, 1),
-    PURE(Uint32Mod, 2, 1),              PURE(Int32LessThan, 2, 1),
-    PURE(Int32LessThanOrEqual, 2, 1),   PURE(Uint32LessThan, 2, 1),
-    PURE(Uint32LessThanOrEqual, 2, 1),  PURE(Int64Add, 2, 1),
-    PURE(Int64Sub, 2, 1),               PURE(Int64Mul, 2, 1),
-    PURE(Int64Div, 2, 1),               PURE(Uint64Div, 2, 1),
-    PURE(Int64Mod, 2, 1),               PURE(Uint64Mod, 2, 1),
-    PURE(Int64LessThan, 2, 1),          PURE(Int64LessThanOrEqual, 2, 1),
-    PURE(Uint64LessThan, 2, 1),         PURE(ChangeFloat32ToFloat64, 1, 1),
-    PURE(ChangeFloat64ToInt32, 1, 1),   PURE(ChangeFloat64ToUint32, 1, 1),
-    PURE(ChangeInt32ToInt64, 1, 1),     PURE(ChangeUint32ToFloat64, 1, 1),
-    PURE(ChangeUint32ToUint64, 1, 1),   PURE(TruncateFloat64ToFloat32, 1, 1),
-    PURE(TruncateFloat64ToInt32, 1, 1), PURE(TruncateInt64ToInt32, 1, 1),
-    PURE(Float64Add, 2, 1),             PURE(Float64Sub, 2, 1),
-    PURE(Float64Mul, 2, 1),             PURE(Float64Div, 2, 1),
-    PURE(Float64Mod, 2, 1),             PURE(Float64Sqrt, 1, 1),
-    PURE(Float64Equal, 2, 1),           PURE(Float64LessThan, 2, 1),
-    PURE(Float64LessThanOrEqual, 2, 1), PURE(LoadStackPointer, 0, 1)
+    PURE(Word32And, 2, 1),                PURE(Word32Or, 2, 1),
+    PURE(Word32Xor, 2, 1),                PURE(Word32Shl, 2, 1),
+    PURE(Word32Shr, 2, 1),                PURE(Word32Sar, 2, 1),
+    PURE(Word32Ror, 2, 1),                PURE(Word32Equal, 2, 1),
+    PURE(Word64And, 2, 1),                PURE(Word64Or, 2, 1),
+    PURE(Word64Xor, 2, 1),                PURE(Word64Shl, 2, 1),
+    PURE(Word64Shr, 2, 1),                PURE(Word64Sar, 2, 1),
+    PURE(Word64Ror, 2, 1),                PURE(Word64Equal, 2, 1),
+    PURE(Int32Add, 2, 1),                 PURE(Int32AddWithOverflow, 2, 2),
+    PURE(Int32Sub, 2, 1),                 PURE(Int32SubWithOverflow, 2, 2),
+    PURE(Int32Mul, 2, 1),                 PURE(Int32MulHigh, 2, 1),
+    PURE(Int32Div, 2, 1),                 PURE(Uint32Div, 2, 1),
+    PURE(Int32Mod, 2, 1),                 PURE(Uint32Mod, 2, 1),
+    PURE(Int32LessThan, 2, 1),            PURE(Int32LessThanOrEqual, 2, 1),
+    PURE(Uint32LessThan, 2, 1),           PURE(Uint32LessThanOrEqual, 2, 1),
+    PURE(Int64Add, 2, 1),                 PURE(Int64Sub, 2, 1),
+    PURE(Int64Mul, 2, 1),                 PURE(Int64Div, 2, 1),
+    PURE(Uint64Div, 2, 1),                PURE(Int64Mod, 2, 1),
+    PURE(Uint64Mod, 2, 1),                PURE(Int64LessThan, 2, 1),
+    PURE(Int64LessThanOrEqual, 2, 1),     PURE(Uint64LessThan, 2, 1),
+    PURE(ChangeFloat32ToFloat64, 1, 1),   PURE(ChangeFloat64ToInt32, 1, 1),
+    PURE(ChangeFloat64ToUint32, 1, 1),    PURE(ChangeInt32ToInt64, 1, 1),
+    PURE(ChangeUint32ToFloat64, 1, 1),    PURE(ChangeUint32ToUint64, 1, 1),
+    PURE(TruncateFloat64ToFloat32, 1, 1), PURE(TruncateFloat64ToInt32, 1, 1),
+    PURE(TruncateInt64ToInt32, 1, 1),     PURE(Float64Add, 2, 1),
+    PURE(Float64Sub, 2, 1),               PURE(Float64Mul, 2, 1),
+    PURE(Float64Div, 2, 1),               PURE(Float64Mod, 2, 1),
+    PURE(Float64Sqrt, 1, 1),              PURE(Float64Equal, 2, 1),
+    PURE(Float64LessThan, 2, 1),          PURE(Float64LessThanOrEqual, 2, 1),
+    PURE(LoadStackPointer, 0, 1)
 #undef PURE
 };
 
index d42f68a..8470818 100644 (file)
@@ -498,6 +498,23 @@ TEST_P(InstructionSelectorMultTest, MultAdd64) {
 INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorMultTest,
                         ::testing::ValuesIn(kMultParams));
 
+
+TEST_F(InstructionSelectorTest, Int32MulHigh) {
+  StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Int32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64ImulHigh32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  ASSERT_EQ(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8