[turbofan] Also optimize unsigned division by constant.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Mon, 3 Nov 2014 10:04:37 +0000 (10:04 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Mon, 3 Nov 2014 10:05:46 +0000 (10:05 +0000)
TEST=cctest,mjsunit,unittests
R=jarin@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25061}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25061 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

35 files changed:
src/arm64/macro-assembler-arm64-inl.h
src/arm64/macro-assembler-arm64.h
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/change-lowering.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/simplified-lowering.cc
src/compiler/typer.cc
src/compiler/verifier.cc
src/compiler/x64/code-generator-x64.cc
src/compiler/x64/instruction-codes-x64.h
src/compiler/x64/instruction-selector-x64.cc
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
test/cctest/compiler/test-run-machops.cc
test/cctest/test-disasm-x64.cc
test/mjsunit/asm/uint32div.js [new file with mode: 0644]
test/mjsunit/asm/uint32mod.js [new file with mode: 0644]
test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
test/unittests/compiler/change-lowering-unittest.cc
test/unittests/compiler/machine-operator-reducer-unittest.cc
test/unittests/compiler/x64/instruction-selector-x64-unittest.cc

index 22c49efbc350b7d6b5266f860975e5d7adb4b29f..4a4d644daebba183245b40365ba519dc23fb58cf 100644 (file)
@@ -1126,6 +1126,14 @@ void MacroAssembler::Smulh(const Register& rd,
 }
 
 
+void MacroAssembler::Umull(const Register& rd, const Register& rn,
+                           const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  umaddl(rd, rn, rm, xzr);
+}
+
+
 void MacroAssembler::Stnp(const CPURegister& rt,
                           const CPURegister& rt2,
                           const MemOperand& dst) {
index 99e6d37d86a0b83f1f826f496e190d8604fcfccb..cff42d7df74a638404c66b5f8e9a538ef07d4a3a 100644 (file)
@@ -490,6 +490,7 @@ class MacroAssembler : public Assembler {
   inline void Smulh(const Register& rd,
                     const Register& rn,
                     const Register& rm);
+  inline void Umull(const Register& rd, const Register& rn, const Register& rm);
   inline void Stnp(const CPURegister& rt,
                    const CPURegister& rt2,
                    const MemOperand& dst);
index 814f5e7da8a03544922fafe654e9aba44ff6ba6f..91bb660453862456b1b1786ff1db60d6cd7c442c 100644 (file)
@@ -248,6 +248,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
                i.InputRegister(2));
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
+    case kArmUmull:
+      __ umull(i.OutputRegister(0), i.OutputRegister(1), i.InputRegister(0),
+               i.InputRegister(1), i.OutputSBit());
+      break;
     case kArmSdiv: {
       CpuFeatureScope scope(masm(), SUDIV);
       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
index 04559a39cde3d4171e4301a48361d30f8ad37d24..c48369e7d6e447031e8a2d576ef2bf1f4ba5928f 100644 (file)
@@ -28,6 +28,7 @@ namespace compiler {
   V(ArmMls)                        \
   V(ArmSmmul)                      \
   V(ArmSmmla)                      \
+  V(ArmUmull)                      \
   V(ArmSdiv)                       \
   V(ArmUdiv)                       \
   V(ArmMov)                        \
index 3f3aff4541b0380d06ac2b76a09b4044a106a26d..a071bbccf8422ff371018a68085d46fea377505d 100644 (file)
@@ -86,6 +86,7 @@ class ArmOperandGenerator : public OperandGenerator {
       case kArmMls:
       case kArmSmmul:
       case kArmSmmla:
+      case kArmUmull:
       case kArmSdiv:
       case kArmUdiv:
       case kArmBfc:
@@ -658,6 +659,15 @@ void InstructionSelector::VisitInt32MulHigh(Node* node) {
 }
 
 
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  ArmOperandGenerator g(this);
+  InstructionOperand* outputs[] = {g.TempRegister(), g.DefineAsRegister(node)};
+  InstructionOperand* inputs[] = {g.UseRegister(node->InputAt(0)),
+                                  g.UseRegister(node->InputAt(1))};
+  Emit(kArmUmull, arraysize(outputs), outputs, arraysize(inputs), inputs);
+}
+
+
 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
                     ArchOpcode f64i32_opcode, ArchOpcode i32f64_opcode,
                     InstructionOperand* result_operand,
index 38c6531c5f3a4f4a49efb136ebe347bc3e3a068a..35f4d39618673454d58189e5feb2d46d1efbf807 100644 (file)
@@ -267,6 +267,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Smull:
       __ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
       break;
+    case kArm64Umull:
+      __ Umull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
     case kArm64Madd:
       __ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
               i.InputRegister(2));
index ab14a7cc619f09dd7ab586de1429ce41f04c02f5..c798a0d911e2cf9a14a893a92090de7c523bc717 100644 (file)
@@ -37,6 +37,7 @@ namespace compiler {
   V(Arm64Mul)                      \
   V(Arm64Mul32)                    \
   V(Arm64Smull)                    \
+  V(Arm64Umull)                    \
   V(Arm64Madd)                     \
   V(Arm64Madd32)                   \
   V(Arm64Msub)                     \
index 39cd6ca77e0cc31b1a50c4d4a4ed53cf0ebd672c..bf768c91bde37c1b94033126874007c9b98b96d6 100644 (file)
@@ -778,6 +778,16 @@ void InstructionSelector::VisitInt32MulHigh(Node* node) {
 }
 
 
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  // TODO(arm64): Can we do better here?
+  Arm64OperandGenerator g(this);
+  InstructionOperand* const smull_operand = g.TempRegister();
+  Emit(kArm64Umull, smull_operand, g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+  Emit(kArm64Lsr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
+}
+
+
 void InstructionSelector::VisitInt32Div(Node* node) {
   VisitRRR(this, kArm64Idiv32, node);
 }
index 3b3998086422500e0962bc9c313d04dbc0af018b..0b4a39952ae69bab681a32ac0d590a986f8ab9cd 100644 (file)
@@ -53,7 +53,7 @@ Node* ChangeLowering::HeapNumberValueIndexConstant() {
 Node* ChangeLowering::SmiMaxValueConstant() {
   const int smi_value_size = machine()->Is32() ? SmiTagging<4>::SmiValueSize()
                                                : SmiTagging<8>::SmiValueSize();
-  return jsgraph()->IntPtrConstant(
+  return jsgraph()->Int32Constant(
       -(static_cast<int>(0xffffffffu << (smi_value_size - 1)) + 1));
 }
 
index fd4663653af83ef3bbce4f1caaff6f7f00ab7e1d..8711242a7b1514ae1cb6dee87e0542e10ac44849 100644 (file)
@@ -247,6 +247,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kIA32ImulHigh:
       __ imul(i.InputRegister(1));
       break;
+    case kIA32UmulHigh:
+      __ mul(i.InputRegister(1));
+      break;
     case kIA32Idiv:
       __ cdq();
       __ idiv(i.InputOperand(1));
index c922a3d9a335d0005dabaab29d83a82892223d1a..f72a1cad963eddb903be5b15464b0de1445a84f7 100644 (file)
@@ -21,6 +21,7 @@ namespace compiler {
   V(IA32Sub)                       \
   V(IA32Imul)                      \
   V(IA32ImulHigh)                  \
+  V(IA32UmulHigh)                  \
   V(IA32Idiv)                      \
   V(IA32Udiv)                      \
   V(IA32Not)                       \
index 1dd9c165b3a0576f7585fc23205f905ee64e197a..c242fb431c6f343d99875aea584b7372ffa482c9 100644 (file)
@@ -646,22 +646,43 @@ void InstructionSelector::VisitInt32Mul(Node* node) {
 }
 
 
-void InstructionSelector::VisitInt32MulHigh(Node* node) {
-  IA32OperandGenerator g(this);
-  Emit(kIA32ImulHigh, g.DefineAsFixed(node, edx),
-       g.UseFixed(node->InputAt(0), eax),
-       g.UseUniqueRegister(node->InputAt(1)));
+namespace {
+
+void VisitMulHigh(InstructionSelector* selector, Node* node,
+                  ArchOpcode opcode) {
+  IA32OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsFixed(node, edx),
+                 g.UseFixed(node->InputAt(0), eax),
+                 g.UseUniqueRegister(node->InputAt(1)));
 }
 
 
-static inline void VisitDiv(InstructionSelector* selector, Node* node,
-                            ArchOpcode opcode) {
+void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
   IA32OperandGenerator g(selector);
   InstructionOperand* temps[] = {g.TempRegister(edx)};
-  size_t temp_count = arraysize(temps);
   selector->Emit(opcode, g.DefineAsFixed(node, eax),
                  g.UseFixed(node->InputAt(0), eax),
-                 g.UseUnique(node->InputAt(1)), temp_count, temps);
+                 g.UseUnique(node->InputAt(1)), arraysize(temps), temps);
+}
+
+
+void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
+  IA32OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsFixed(node, edx),
+                 g.UseFixed(node->InputAt(0), eax),
+                 g.UseUnique(node->InputAt(1)));
+}
+
+}  // namespace
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  VisitMulHigh(this, node, kIA32ImulHigh);
+}
+
+
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  VisitMulHigh(this, node, kIA32UmulHigh);
 }
 
 
@@ -675,15 +696,6 @@ void InstructionSelector::VisitUint32Div(Node* node) {
 }
 
 
-static inline void VisitMod(InstructionSelector* selector, Node* node,
-                            ArchOpcode opcode) {
-  IA32OperandGenerator g(selector);
-  selector->Emit(opcode, g.DefineAsFixed(node, edx),
-                 g.UseFixed(node->InputAt(0), eax),
-                 g.UseUnique(node->InputAt(1)));
-}
-
-
 void InstructionSelector::VisitInt32Mod(Node* node) {
   VisitMod(this, node, kIA32Idiv);
 }
index 122bb5ff2c653163eb921a0a7d1475e2f9396738..877230ca2ab742c22b10c82b910769078d2938b6 100644 (file)
@@ -738,6 +738,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitUint32LessThanOrEqual(node);
     case IrOpcode::kUint32Mod:
       return VisitUint32Mod(node);
+    case IrOpcode::kUint32MulHigh:
+      return VisitUint32MulHigh(node);
     case IrOpcode::kInt64Add:
       return VisitInt64Add(node);
     case IrOpcode::kInt64Sub:
index 3803af5e34f99dfb64de1b6180c3fa5781e3c8d6..1f73262f95f63a6a25cee83bcbe2d355c3bb58b2 100644 (file)
@@ -49,11 +49,13 @@ Node* MachineOperatorReducer::Word32And(Node* lhs, uint32_t rhs) {
 
 
 Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
+  if (rhs == 0) return lhs;
   return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
 }
 
 
 Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
+  if (rhs == 0) return lhs;
   return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
 }
 
@@ -78,7 +80,8 @@ Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
 }
 
 
-Node* MachineOperatorReducer::TruncatingDiv(Node* dividend, int32_t divisor) {
+Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
+  DCHECK_NE(0, divisor);
   DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
   base::MagicNumbersForDivision<uint32_t> const mag =
       base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
@@ -89,10 +92,25 @@ Node* MachineOperatorReducer::TruncatingDiv(Node* dividend, int32_t divisor) {
   } 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(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
+}
+
+
+Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
+  DCHECK_LT(0, divisor);
+  base::MagicNumbersForDivision<uint32_t> const mag =
+      base::UnsignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+  Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
+                                    Uint32Constant(mag.multiplier));
+  if (mag.add) {
+    DCHECK_LE(1, mag.shift);
+    quotient = Word32Shr(
+        Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
+        mag.shift - 1);
+  } else {
+    quotient = Word32Shr(quotient, mag.shift);
   }
-  return Int32Add(quotient, Word32Shr(dividend, 31));
+  return quotient;
 }
 
 
@@ -572,7 +590,7 @@ Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
       quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
       quotient = Word32Sar(quotient, shift);
     } else {
-      quotient = TruncatingDiv(quotient, Abs(divisor));
+      quotient = Int32Div(quotient, Abs(divisor));
     }
     if (divisor < 0) {
       node->set_op(machine()->Int32Sub());
@@ -600,11 +618,17 @@ Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
     Node* const zero = Int32Constant(0);
     return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
   }
-  if (m.right().IsPowerOf2()) {  // x / 2^n => x >> n
-    node->TrimInputCount(2);
-    node->set_op(machine()->Word32Shr());
-    node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
-    return Changed(node);
+  if (m.right().HasValue()) {
+    Node* const dividend = m.left().node();
+    uint32_t const divisor = m.right().Value();
+    if (base::bits::IsPowerOfTwo32(divisor)) {  // x / 2^n => x >> n
+      node->set_op(machine()->Word32Shr());
+      node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
+      node->TrimInputCount(2);
+      return Changed(node);
+    } else {
+      return Replace(Uint32Div(dividend, divisor));
+    }
   }
   return NoChange();
 }
@@ -640,17 +664,20 @@ Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
       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);
+
+      DCHECK_EQ(3, node->InputCount());
+      node->set_op(common()->Phi(kMachInt32, 2));
+      node->ReplaceInput(0, neg);
+      node->ReplaceInput(1, pos);
+      node->ReplaceInput(2, merge);
     } else {
-      Node* quotient = TruncatingDiv(dividend, divisor);
+      Node* quotient = Int32Div(dividend, divisor);
       node->set_op(machine()->Int32Sub());
       DCHECK_EQ(dividend, node->InputAt(0));
       node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
       node->TrimInputCount(2);
-      return Changed(node);
     }
+    return Changed(node);
   }
   return NoChange();
 }
@@ -666,10 +693,19 @@ Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
     return ReplaceUint32(
         base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
   }
-  if (m.right().IsPowerOf2()) {  // x % 2^n => x & 2^n-1
+  if (m.right().HasValue()) {
+    Node* const dividend = m.left().node();
+    uint32_t const divisor = m.right().Value();
+    if (base::bits::IsPowerOfTwo32(divisor)) {  // x % 2^n => x & 2^n-1
+      node->set_op(machine()->Word32And());
+      node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
+    } else {
+      Node* quotient = Uint32Div(dividend, divisor);
+      node->set_op(machine()->Int32Sub());
+      DCHECK_EQ(dividend, node->InputAt(0));
+      node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
+    }
     node->TrimInputCount(2);
-    node->set_op(machine()->Word32And());
-    node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
     return Changed(node);
   }
   return NoChange();
index 475ed2ecdd9db413d5f41642aebd5edc3f1d27c2..f19184b75e68caf153c18a9ec150dfe9f967700c 100644 (file)
@@ -41,8 +41,8 @@ class MachineOperatorReducer FINAL : public Reducer {
   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);
+  Node* Int32Div(Node* dividend, int32_t divisor);
+  Node* Uint32Div(Node* dividend, uint32_t divisor);
 
   Reduction ReplaceBool(bool value) { return ReplaceInt32(value ? 1 : 0); }
   Reduction ReplaceFloat32(volatile float value) {
index a4aaa66cfdd242713d7acfeab4888aa6263d8677..2ea1bf3ba22de45e9f41f6e72d7092cc7adbf221 100644 (file)
@@ -84,6 +84,7 @@ StoreRepresentation const& StoreRepresentationOf(Operator const* op) {
   V(Uint32LessThan, Operator::kNoProperties, 2, 0, 1)                         \
   V(Uint32LessThanOrEqual, Operator::kNoProperties, 2, 0, 1)                  \
   V(Uint32Mod, Operator::kNoProperties, 2, 1, 1)                              \
+  V(Uint32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)  \
   V(Int64Add, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
   V(Int64Sub, Operator::kNoProperties, 2, 0, 1)                               \
   V(Int64Mul, Operator::kAssociative | Operator::kCommutative, 2, 0, 1)       \
index eff9b8b2501b7efb6c55c94feb73ac725ce1df7d..979a887ac5d24f5f9288776d78bca80ccf8075b0 100644 (file)
@@ -108,6 +108,7 @@ class MachineOperatorBuilder FINAL : public ZoneObject {
   const Operator* Uint32LessThan();
   const Operator* Uint32LessThanOrEqual();
   const Operator* Uint32Mod();
+  const Operator* Uint32MulHigh();
   bool Int32DivIsSafe() const { return flags_ & kInt32DivIsSafe; }
   bool Int32ModIsSafe() const { return flags_ & kInt32ModIsSafe; }
   bool Uint32DivIsSafe() const { return flags_ & kUint32DivIsSafe; }
index ac3f0629bd1e69d0f27fb84c443737e237a739a5..132f9cc75444b22b9ebe76d0e09b1481cd69bd40 100644 (file)
   V(Uint32LessThan)           \
   V(Uint32LessThanOrEqual)    \
   V(Uint32Mod)                \
+  V(Uint32MulHigh)            \
   V(Int64Add)                 \
   V(Int64Sub)                 \
   V(Int64Mul)                 \
index 01fa509e2ff65c959c691fe69996dcad7cbd9758..b7b82b1d34e2d6e9e292dc1414596d9f29da04c9 100644 (file)
@@ -102,14 +102,15 @@ class RawMachineAssembler : public GraphBuilder {
     return Load(rep, base, Int32Constant(0));
   }
   Node* Load(MachineType rep, Node* base, Node* index) {
-    return NewNode(machine()->Load(rep), base, index);
+    return NewNode(machine()->Load(rep), base, index, graph()->start(),
+                   graph()->start());
   }
   void Store(MachineType rep, Node* base, Node* value) {
     Store(rep, base, Int32Constant(0), value);
   }
   void Store(MachineType rep, Node* base, Node* index, Node* value) {
     NewNode(machine()->Store(StoreRepresentation(rep, kNoWriteBarrier)), base,
-            index, value);
+            index, value, graph()->start(), graph()->start());
   }
   // Arithmetic Operations.
   Node* WordAnd(Node* a, Node* b) {
@@ -231,10 +232,10 @@ class RawMachineAssembler : public GraphBuilder {
     return NewNode(machine()->Int32MulHigh(), a, b);
   }
   Node* Int32Div(Node* a, Node* b) {
-    return NewNode(machine()->Int32Div(), a, b);
+    return NewNode(machine()->Int32Div(), a, b, graph()->start());
   }
   Node* Int32Mod(Node* a, Node* b) {
-    return NewNode(machine()->Int32Mod(), a, b);
+    return NewNode(machine()->Int32Mod(), a, b, graph()->start());
   }
   Node* Int32LessThan(Node* a, Node* b) {
     return NewNode(machine()->Int32LessThan(), a, b);
@@ -243,7 +244,7 @@ class RawMachineAssembler : public GraphBuilder {
     return NewNode(machine()->Int32LessThanOrEqual(), a, b);
   }
   Node* Uint32Div(Node* a, Node* b) {
-    return NewNode(machine()->Uint32Div(), a, b);
+    return NewNode(machine()->Uint32Div(), a, b, graph()->start());
   }
   Node* Uint32LessThan(Node* a, Node* b) {
     return NewNode(machine()->Uint32LessThan(), a, b);
@@ -252,7 +253,10 @@ class RawMachineAssembler : public GraphBuilder {
     return NewNode(machine()->Uint32LessThanOrEqual(), a, b);
   }
   Node* Uint32Mod(Node* a, Node* b) {
-    return NewNode(machine()->Uint32Mod(), a, b);
+    return NewNode(machine()->Uint32Mod(), a, b, graph()->start());
+  }
+  Node* Uint32MulHigh(Node* a, Node* b) {
+    return NewNode(machine()->Uint32MulHigh(), a, b);
   }
   Node* Int32GreaterThan(Node* a, Node* b) { return Int32LessThan(b, a); }
   Node* Int32GreaterThanOrEqual(Node* a, Node* b) {
index 0f784c650e1d22b689c4d3e649341f0ac5d8ac19..3069865adb29664c8b68f589b74d17f66d217cb0 100644 (file)
@@ -857,11 +857,13 @@ class RepresentationSelector {
       case IrOpcode::kInt32Add:
       case IrOpcode::kInt32Sub:
       case IrOpcode::kInt32Mul:
+      case IrOpcode::kInt32MulHigh:
       case IrOpcode::kInt32Div:
       case IrOpcode::kInt32Mod:
         return VisitInt32Binop(node);
       case IrOpcode::kUint32Div:
       case IrOpcode::kUint32Mod:
+      case IrOpcode::kUint32MulHigh:
         return VisitUint32Binop(node);
       case IrOpcode::kInt32LessThan:
       case IrOpcode::kInt32LessThanOrEqual:
index 6b32258d111bdc277bce729b4b6324487654e051..1c169c23af666782745c10d4b0e2fe13528c05e3 100644 (file)
@@ -1606,7 +1606,7 @@ Bounds Typer::Visitor::TypeInt32Mul(Node* node) {
 
 
 Bounds Typer::Visitor::TypeInt32MulHigh(Node* node) {
-  return Bounds(Type::Integral32());
+  return Bounds(Type::Signed32());
 }
 
 
@@ -1650,6 +1650,11 @@ Bounds Typer::Visitor::TypeUint32Mod(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeUint32MulHigh(Node* node) {
+  return Bounds(Type::Unsigned32());
+}
+
+
 Bounds Typer::Visitor::TypeInt64Add(Node* node) {
   return Bounds(Type::Internal());
 }
index 29342763b153b9e69adcef40b3dfd47cb712859c..434b845ae236b0d73e45434a7811366c5ad7697d 100644 (file)
@@ -688,6 +688,7 @@ GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
     case IrOpcode::kInt32LessThanOrEqual:
     case IrOpcode::kUint32Div:
     case IrOpcode::kUint32Mod:
+    case IrOpcode::kUint32MulHigh:
     case IrOpcode::kUint32LessThan:
     case IrOpcode::kUint32LessThanOrEqual:
     case IrOpcode::kInt64Add:
index b684bdf7434dba23c0667812236068fc61954874..bb02441ff5c373a55a36754772a766165395cfaa 100644 (file)
@@ -289,7 +289,18 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       ASSEMBLE_MULT(imulq);
       break;
     case kX64ImulHigh32:
-      __ imull(i.InputRegister(1));
+      if (instr->InputAt(1)->IsRegister()) {
+        __ imull(i.InputRegister(1));
+      } else {
+        __ imull(i.InputOperand(1));
+      }
+      break;
+    case kX64UmulHigh32:
+      if (instr->InputAt(1)->IsRegister()) {
+        __ mull(i.InputRegister(1));
+      } else {
+        __ mull(i.InputOperand(1));
+      }
       break;
     case kX64Idiv32:
       __ cdq();
index 807fe1480f2f387c3607df4c20377da292a820e4..9d4f59ca778b75ae3af612c34b2e43ac065d16db 100644 (file)
@@ -29,6 +29,7 @@ namespace compiler {
   V(X64Imul)                       \
   V(X64Imul32)                     \
   V(X64ImulHigh32)                 \
+  V(X64UmulHigh32)                 \
   V(X64Idiv)                       \
   V(X64Idiv32)                     \
   V(X64Udiv)                       \
index 432b21cef93290389332bc4360e8115248498a1b..cd039ed2882299f51798fdf7530db84e22d8d7f0 100644 (file)
@@ -405,6 +405,36 @@ void VisitMul(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
   }
 }
 
+
+void VisitMulHigh(InstructionSelector* selector, Node* node,
+                  ArchOpcode opcode) {
+  X64OperandGenerator g(selector);
+  Node* left = node->InputAt(0);
+  Node* right = node->InputAt(1);
+  if (selector->IsLive(left) && !selector->IsLive(right)) {
+    std::swap(left, right);
+  }
+  selector->Emit(opcode, g.DefineAsFixed(node, rdx), g.UseFixed(left, rax),
+                 g.UseUnique(right));
+}
+
+
+void VisitDiv(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
+  X64OperandGenerator g(selector);
+  InstructionOperand* temps[] = {g.TempRegister(rdx)};
+  selector->Emit(
+      opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
+      g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
+}
+
+
+void VisitMod(InstructionSelector* selector, Node* node, ArchOpcode opcode) {
+  X64OperandGenerator g(selector);
+  selector->Emit(opcode, g.DefineAsFixed(node, rdx),
+                 g.UseFixed(node->InputAt(0), rax),
+                 g.UseUniqueRegister(node->InputAt(1)));
+}
+
 }  // namespace
 
 
@@ -419,20 +449,7 @@ void InstructionSelector::VisitInt64Mul(Node* node) {
 
 
 void InstructionSelector::VisitInt32MulHigh(Node* node) {
-  X64OperandGenerator g(this);
-  Emit(kX64ImulHigh32, g.DefineAsFixed(node, rdx),
-       g.UseFixed(node->InputAt(0), rax),
-       g.UseUniqueRegister(node->InputAt(1)));
-}
-
-
-static void VisitDiv(InstructionSelector* selector, Node* node,
-                     ArchOpcode opcode) {
-  X64OperandGenerator g(selector);
-  InstructionOperand* temps[] = {g.TempRegister(rdx)};
-  selector->Emit(
-      opcode, g.DefineAsFixed(node, rax), g.UseFixed(node->InputAt(0), rax),
-      g.UseUniqueRegister(node->InputAt(1)), arraysize(temps), temps);
+  VisitMulHigh(this, node, kX64ImulHigh32);
 }
 
 
@@ -456,15 +473,6 @@ void InstructionSelector::VisitUint64Div(Node* node) {
 }
 
 
-static void VisitMod(InstructionSelector* selector, Node* node,
-                     ArchOpcode opcode) {
-  X64OperandGenerator g(selector);
-  selector->Emit(opcode, g.DefineAsFixed(node, rdx),
-                 g.UseFixed(node->InputAt(0), rax),
-                 g.UseUniqueRegister(node->InputAt(1)));
-}
-
-
 void InstructionSelector::VisitInt32Mod(Node* node) {
   VisitMod(this, node, kX64Idiv32);
 }
@@ -485,6 +493,11 @@ void InstructionSelector::VisitUint64Mod(Node* node) {
 }
 
 
+void InstructionSelector::VisitUint32MulHigh(Node* node) {
+  VisitMulHigh(this, node, kX64UmulHigh32);
+}
+
+
 void InstructionSelector::VisitChangeFloat32ToFloat64(Node* node) {
   X64OperandGenerator g(this);
   Emit(kSSECvtss2sd, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
@@ -544,7 +557,8 @@ void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
     case IrOpcode::kUint32Div:
     case IrOpcode::kUint32LessThan:
     case IrOpcode::kUint32LessThanOrEqual:
-    case IrOpcode::kUint32Mod: {
+    case IrOpcode::kUint32Mod:
+    case IrOpcode::kUint32MulHigh: {
       // These 32-bit operations implicitly zero-extend to 64-bit on x64, so the
       // zero-extension is a no-op.
       Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
index 6e12458f963a81a66597ad5d319d91fdacc1e521..dfd51a4bedfc4990778778e3b36bbc2bebb77e14 100644 (file)
@@ -935,6 +935,14 @@ void Assembler::emit_imul(Register src, int size) {
 }
 
 
+void Assembler::emit_imul(const Operand& src, int size) {
+  EnsureSpace ensure_space(this);
+  emit_rex(src, size);
+  emit(0xF7);
+  emit_operand(0x5, src);
+}
+
+
 void Assembler::emit_imul(Register dst, Register src, int size) {
   EnsureSpace ensure_space(this);
   emit_rex(dst, src, size);
@@ -1499,7 +1507,23 @@ void Assembler::emit_repmovs(int size) {
 }
 
 
-void Assembler::mul(Register src) {
+void Assembler::mull(Register src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(src);
+  emit(0xF7);
+  emit_modrm(0x4, src);
+}
+
+
+void Assembler::mull(const Operand& src) {
+  EnsureSpace ensure_space(this);
+  emit_optional_rex_32(src);
+  emit(0xF7);
+  emit_operand(0x4, src);
+}
+
+
+void Assembler::mulq(Register src) {
   EnsureSpace ensure_space(this);
   emit_rex_64(src);
   emit(0xF7);
index d938046b1c91dd7e09919ef9c23363371911d657..3b55396c14877163b50e63cc86a1a70681ca476a 100644 (file)
@@ -810,8 +810,11 @@ class Assembler : public AssemblerBase {
   // Sign-extends eax into edx:eax.
   void cdq();
 
+  // Multiply eax by src, put the result in edx:eax.
+  void mull(Register src);
+  void mull(const Operand& src);
   // Multiply rax by src, put the result in rdx:rax.
-  void mul(Register src);
+  void mulq(Register src);
 
 #define DECLARE_SHIFT_INSTRUCTION(instruction, subcode)                       \
   void instruction##p(Register dst, Immediate imm8) {                         \
@@ -1473,6 +1476,7 @@ class Assembler : public AssemblerBase {
   // Signed multiply instructions.
   // rdx:rax = rax * src when size is 64 or edx:eax = eax * src when size is 32.
   void emit_imul(Register src, int size);
+  void emit_imul(const Operand& src, int size);
   void emit_imul(Register dst, Register src, int size);
   void emit_imul(Register dst, const Operand& src, int size);
   void emit_imul(Register dst, Register src, Immediate imm, int size);
index 271967d7c89df4ff05f18274903a2abff6741677..9eb67537382a5f8fb3afa4a4a2c9379545ee8f32 100644 (file)
@@ -61,16 +61,16 @@ TEST(CodeGenInt32Binop) {
   RawMachineAssemblerTester<void> m;
 
   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()};
+      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()->Uint32MulHigh(),
+      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++) {
@@ -1500,6 +1500,20 @@ TEST(RunInt32MulAndInt32SubP) {
 }
 
 
+TEST(RunUint32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Uint32MulHigh(bt.param0, bt.param1));
+  FOR_UINT32_INPUTS(i) {
+    FOR_UINT32_INPUTS(j) {
+      int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(
+          (static_cast<uint64_t>(*i) * static_cast<uint64_t>(*j)) >> 32));
+      CHECK_EQ(expected, bt.call(bit_cast<int32_t>(*i), bit_cast<int32_t>(*j)));
+    }
+  }
+}
+
+
 TEST(RunInt32DivP) {
   {
     RawMachineAssemblerTester<int32_t> m;
@@ -2812,16 +2826,17 @@ TEST(RunDeadInt32Binops) {
   RawMachineAssemblerTester<int32_t> m;
 
   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()};
+      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()->Uint32MulHigh(),        m.machine()->Int32LessThan(),
+      m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(),
+      m.machine()->Uint32LessThanOrEqual()};
 
   for (size_t i = 0; i < arraysize(kOps); ++i) {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
index 4ae36089394e503fbd7f378f3ecdb36e7f8290cf..fac9226279d7833fa72e386d05c5ebb7d4fe6d03 100644 (file)
@@ -179,7 +179,8 @@ TEST(DisasmX64) {
 
   __ nop();
   __ idivq(rdx);
-  __ mul(rdx);
+  __ mull(rdx);
+  __ mulq(rdx);
   __ negq(rdx);
   __ notq(rdx);
   __ testq(Operand(rbx, rcx, times_4, 10000), rdx);
diff --git a/test/mjsunit/asm/uint32div.js b/test/mjsunit/asm/uint32div.js
new file mode 100644 (file)
index 0000000..54a2138
--- /dev/null
@@ -0,0 +1,29 @@
+// 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 Uint32Div(divisor) {
+  var name = "div_";
+  name += 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 = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Uint32Div(divisor);
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend / divisor) >>> 0, mod(dividend));
+  }
+}
diff --git a/test/mjsunit/asm/uint32mod.js b/test/mjsunit/asm/uint32mod.js
new file mode 100644 (file)
index 0000000..4ba94da
--- /dev/null
@@ -0,0 +1,29 @@
+// 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 Uint32Mod(divisor) {
+  var name = "mod_";
+  name += 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 = [0, 1, 3, 4, 10, 42, 64, 100, 1024, 2147483647, 4294967295];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Uint32Mod(divisor);
+  for (var dividend = 0; dividend < 4294967296; dividend += 3999773) {
+    assertEquals((dividend % divisor) >>> 0, mod(dividend));
+  }
+}
index 08a23e9f75a058fd86665704d2de7b6a729f5296..6e4306de05d0d08e3d0bc1920500cfe45a494aae 100644 (file)
@@ -1765,6 +1765,23 @@ TEST_F(InstructionSelectorTest, Int32MulHighWithParameters) {
 }
 
 
+TEST_F(InstructionSelectorTest, Uint32MulHighWithParameters) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Uint32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArmUmull, 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(2U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->OutputAt(1)));
+}
+
+
 TEST_F(InstructionSelectorTest, Uint32DivWithParameters) {
   StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32);
   m.Return(m.Uint32Div(m.Parameter(0), m.Parameter(1)));
index bfee7562d3cf65bcfe1f9524373e60e3fe13464c..5f14b8efc77316e0807528bb96f1f417ab68a952 100644 (file)
@@ -456,7 +456,7 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeUint32ToTagged) {
           IsMerge(
               IsIfTrue(AllOf(CaptureEq(&branch),
                              IsBranch(IsUint32LessThanOrEqual(
-                                          val, IsInt64Constant(SmiMaxValue())),
+                                          val, IsInt32Constant(SmiMaxValue())),
                                       graph()->start()))),
               AllOf(CaptureEq(&if_false), IsIfFalse(CaptureEq(&branch))))));
 }
index be22bfdb3c841560c2d679411979dee4c2ee2ed6..51697163ae6f17fda9213e0adf7b98f34c9cbb7c 100644 (file)
@@ -680,26 +680,26 @@ TEST_F(MachineOperatorReducerTest, Word32ShlWithWord32Shr) {
 TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
   Node* const p0 = Parameter(0);
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(0)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(0), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(1)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(1), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_EQ(r.replacement(), p0);
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(-1)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(-1), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Sub(IsInt32Constant(0), p0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(2)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(2), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(
         r.replacement(),
@@ -707,8 +707,8 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
                     IsInt32Constant(1)));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(-2)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Div(), p0, Int32Constant(-2), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(
         r.replacement(),
@@ -718,8 +718,9 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
                         IsInt32Constant(1))));
   }
   TRACED_FORRANGE(int32_t, shift, 2, 30) {
-    Reduction const r = Reduce(
-        graph()->NewNode(machine()->Int32Div(), p0, Int32Constant(1 << shift)));
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Div(), p0,
+                                Int32Constant(1 << shift), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(
         r.replacement(),
@@ -731,7 +732,8 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
   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)));
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
+        graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(
         r.replacement(),
@@ -746,15 +748,15 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
   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)));
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
       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)));
+      Reduction const r = Reduce(graph()->NewNode(
+          machine()->Int32Div(), p0, Int32Constant(divisor), graph()->start()));
       ASSERT_TRUE(r.Changed());
       EXPECT_THAT(r.replacement(), IsTruncatingDiv(p0, divisor));
     }
@@ -764,7 +766,8 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithConstant) {
 
 TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
   Node* const p0 = Parameter(0);
-  Reduction const r = Reduce(graph()->NewNode(machine()->Int32Div(), p0, p0));
+  Reduction const r =
+      Reduce(graph()->NewNode(machine()->Int32Div(), p0, p0, graph()->start()));
   ASSERT_TRUE(r.Changed());
   EXPECT_THAT(
       r.replacement(),
@@ -779,28 +782,28 @@ TEST_F(MachineOperatorReducerTest, Int32DivWithParameters) {
 TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
   Node* const p0 = Parameter(0);
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Uint32Div(), Int32Constant(0), p0));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), Int32Constant(0), p0, graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Uint32Div(), p0, Int32Constant(0)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), p0, Int32Constant(0), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Uint32Div(), p0, Int32Constant(1)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Div(), p0, Int32Constant(1), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_EQ(r.replacement(), p0);
   }
   TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
     TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
-      Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(),
-                                                  Uint32Constant(dividend),
-                                                  Uint32Constant(divisor)));
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Uint32Div(), Uint32Constant(dividend),
+                           Uint32Constant(divisor), graph()->start()));
       ASSERT_TRUE(r.Changed());
       EXPECT_THAT(r.replacement(),
                   IsInt32Constant(bit_cast<int32_t>(
@@ -808,8 +811,9 @@ TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
     }
   }
   TRACED_FORRANGE(uint32_t, shift, 1, 31) {
-    Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
-                                                Uint32Constant(1u << shift)));
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Uint32Div(), p0,
+                                Uint32Constant(1u << shift), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(),
                 IsWord32Shr(p0, IsInt32Constant(bit_cast<int32_t>(shift))));
@@ -819,7 +823,8 @@ TEST_F(MachineOperatorReducerTest, Uint32DivWithConstant) {
 
 TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
   Node* const p0 = Parameter(0);
-  Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Div(), p0, p0));
+  Reduction const r = Reduce(
+      graph()->NewNode(machine()->Uint32Div(), p0, p0, graph()->start()));
   ASSERT_TRUE(r.Changed());
   EXPECT_THAT(
       r.replacement(),
@@ -834,42 +839,43 @@ TEST_F(MachineOperatorReducerTest, Uint32DivWithParameters) {
 TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
   Node* const p0 = Parameter(0);
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Mod(), Int32Constant(0), p0));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), Int32Constant(0), p0, graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(0)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(0), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(1), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(-1)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(-1), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   TRACED_FOREACH(int32_t, dividend, kInt32Values) {
     TRACED_FOREACH(int32_t, divisor, kInt32Values) {
-      Reduction const r = Reduce(graph()->NewNode(machine()->Int32Mod(),
-                                                  Int32Constant(dividend),
-                                                  Int32Constant(divisor)));
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Int32Mod(), Int32Constant(dividend),
+                           Int32Constant(divisor), graph()->start()));
       ASSERT_TRUE(r.Changed());
       EXPECT_THAT(r.replacement(),
                   IsInt32Constant(base::bits::SignedMod32(dividend, divisor)));
     }
   }
   TRACED_FORRANGE(int32_t, shift, 1, 30) {
-    Reduction const r = Reduce(
-        graph()->NewNode(machine()->Int32Mod(), p0, Int32Constant(1 << shift)));
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Int32Mod(), p0,
+                                Int32Constant(1 << shift), graph()->start()));
     ASSERT_TRUE(r.Changed());
 
     Capture<Node*> branch;
@@ -890,7 +896,8 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
   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)));
+        Uint32Constant(bit_cast<uint32_t, int32_t>(-1) << shift),
+        graph()->start()));
     ASSERT_TRUE(r.Changed());
 
     Capture<Node*> branch;
@@ -910,8 +917,8 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
   }
   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)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Int32Mod(), p0, Int32Constant(divisor), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(),
                 IsInt32Sub(p0, IsInt32Mul(IsTruncatingDiv(p0, Abs(divisor)),
@@ -922,7 +929,8 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithConstant) {
 
 TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
   Node* const p0 = Parameter(0);
-  Reduction const r = Reduce(graph()->NewNode(machine()->Int32Mod(), p0, p0));
+  Reduction const r =
+      Reduce(graph()->NewNode(machine()->Int32Mod(), p0, p0, graph()->start()));
   ASSERT_TRUE(r.Changed());
   EXPECT_THAT(r.replacement(), IsInt32Constant(0));
 }
@@ -935,28 +943,28 @@ TEST_F(MachineOperatorReducerTest, Int32ModWithParameters) {
 TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
   Node* const p0 = Parameter(0);
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Uint32Mod(), p0, Int32Constant(0)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), p0, Int32Constant(0), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Uint32Mod(), Int32Constant(0), p0));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), Int32Constant(0), p0, graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   {
-    Reduction const r =
-        Reduce(graph()->NewNode(machine()->Uint32Mod(), p0, Int32Constant(1)));
+    Reduction const r = Reduce(graph()->NewNode(
+        machine()->Uint32Mod(), p0, Int32Constant(1), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(), IsInt32Constant(0));
   }
   TRACED_FOREACH(uint32_t, dividend, kUint32Values) {
     TRACED_FOREACH(uint32_t, divisor, kUint32Values) {
-      Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(),
-                                                  Uint32Constant(dividend),
-                                                  Uint32Constant(divisor)));
+      Reduction const r = Reduce(
+          graph()->NewNode(machine()->Uint32Mod(), Uint32Constant(dividend),
+                           Uint32Constant(divisor), graph()->start()));
       ASSERT_TRUE(r.Changed());
       EXPECT_THAT(r.replacement(),
                   IsInt32Constant(bit_cast<int32_t>(
@@ -964,8 +972,9 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
     }
   }
   TRACED_FORRANGE(uint32_t, shift, 1, 31) {
-    Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
-                                                Uint32Constant(1u << shift)));
+    Reduction const r =
+        Reduce(graph()->NewNode(machine()->Uint32Mod(), p0,
+                                Uint32Constant(1u << shift), graph()->start()));
     ASSERT_TRUE(r.Changed());
     EXPECT_THAT(r.replacement(),
                 IsWord32And(p0, IsInt32Constant(
@@ -976,7 +985,8 @@ TEST_F(MachineOperatorReducerTest, Uint32ModWithConstant) {
 
 TEST_F(MachineOperatorReducerTest, Uint32ModWithParameters) {
   Node* const p0 = Parameter(0);
-  Reduction const r = Reduce(graph()->NewNode(machine()->Uint32Mod(), p0, p0));
+  Reduction const r = Reduce(
+      graph()->NewNode(machine()->Uint32Mod(), p0, p0, graph()->start()));
   ASSERT_TRUE(r.Changed());
   EXPECT_THAT(r.replacement(), IsInt32Constant(0));
 }
index e51c86b4061aeccfc3d16c4ca0c67bfa7c8623a6..fe50ca5e35b542b2d0b8b39f38aa774f431a0d89 100644 (file)
@@ -298,7 +298,27 @@ TEST_F(InstructionSelectorTest, Int32MulHigh) {
   EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
   EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
   EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
-  ASSERT_EQ(1U, s[0]->OutputCount());
+  ASSERT_LE(1U, s[0]->OutputCount());
+  EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
+  EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
+}
+
+
+TEST_F(InstructionSelectorTest, Uint32MulHigh) {
+  StreamBuilder m(this, kMachUint32, kMachUint32, kMachUint32);
+  Node* const p0 = m.Parameter(0);
+  Node* const p1 = m.Parameter(1);
+  Node* const n = m.Uint32MulHigh(p0, p1);
+  m.Return(n);
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64UmulHigh32, s[0]->arch_opcode());
+  ASSERT_EQ(2U, s[0]->InputCount());
+  EXPECT_EQ(s.ToVreg(p0), s.ToVreg(s[0]->InputAt(0)));
+  EXPECT_TRUE(s.IsFixed(s[0]->InputAt(0), rax));
+  EXPECT_EQ(s.ToVreg(p1), s.ToVreg(s[0]->InputAt(1)));
+  EXPECT_TRUE(!s.IsUsedAtStart(s[0]->InputAt(1)));
+  ASSERT_LE(1U, s[0]->OutputCount());
   EXPECT_EQ(s.ToVreg(n), s.ToVreg(s[0]->Output()));
   EXPECT_TRUE(s.IsFixed(s[0]->OutputAt(0), rdx));
 }