[turbofan] Add proper conversion operators for int32<->int64.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Aug 2014 08:48:41 +0000 (08:48 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Aug 2014 08:48:41 +0000 (08:48 +0000)
This affects arm64 and x64. Note that we do not yet optimize
these conversions. Later we will add support for merging these
conversion operators into other operations during instruction
selection.

TEST=cctest,compiler-unittests
R=jarin@chromium.org

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

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

22 files changed:
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/instruction-selector.cc
src/compiler/machine-node-factory.h
src/compiler/machine-operator.h
src/compiler/opcodes.h
src/compiler/operator-properties-inl.h
src/compiler/simplified-lowering.cc
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/compiler-unittests/arm64/instruction-selector-arm64-unittest.cc
test/compiler-unittests/change-lowering-unittest.cc
test/compiler-unittests/compiler-unittests.gyp
test/compiler-unittests/compiler-unittests.h
test/compiler-unittests/graph-unittest.cc
test/compiler-unittests/graph-unittest.h
test/compiler-unittests/machine-operator-unittest.cc [new file with mode: 0644]
test/compiler-unittests/x64/instruction-selector-x64-unittest.cc [new file with mode: 0644]

index f21462e27f03ae3456c0c27441bfe597e7a628a6..5127b1012f3dff481ac67e43f3af87124e5b5598 100644 (file)
@@ -274,6 +274,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kArm64Ror32:
       ASSEMBLE_SHIFT(Ror, 32);
       break;
+    case kArm64Mov32:
+      __ Mov(i.OutputRegister32(), i.InputRegister32(0));
+      break;
+    case kArm64Sxtw:
+      __ Sxtw(i.OutputRegister(), i.InputRegister32(0));
+      break;
     case kArm64CallCodeObject: {
       if (instr->InputAt(0)->IsImmediate()) {
         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
@@ -383,14 +389,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
                        0, 2);
       break;
     }
-    case kArm64Int32ToInt64:
-      __ Sxtw(i.OutputRegister(), i.InputRegister(0));
-      break;
-    case kArm64Int64ToInt32:
-      if (!i.OutputRegister().is(i.InputRegister(0))) {
-        __ Mov(i.OutputRegister(), i.InputRegister(0));
-      }
-      break;
     case kArm64Float64ToInt32:
       __ Fcvtzs(i.OutputRegister32(), i.InputDoubleRegister(0));
       break;
index c13c4d429541a557fd4e7eb5fde609fd36540a6a..cb4d18e37b276a629d5b969f05947321f14f14e0 100644 (file)
@@ -48,6 +48,8 @@ namespace compiler {
   V(Arm64Sar32)                    \
   V(Arm64Ror)                      \
   V(Arm64Ror32)                    \
+  V(Arm64Mov32)                    \
+  V(Arm64Sxtw)                     \
   V(Arm64CallCodeObject)           \
   V(Arm64CallJSFunction)           \
   V(Arm64CallAddress)              \
@@ -62,8 +64,6 @@ namespace compiler {
   V(Arm64Float64Mul)               \
   V(Arm64Float64Div)               \
   V(Arm64Float64Mod)               \
-  V(Arm64Int32ToInt64)             \
-  V(Arm64Int64ToInt32)             \
   V(Arm64Float64ToInt32)           \
   V(Arm64Float64ToUint32)          \
   V(Arm64Int32ToFloat64)           \
index 9eca69610b3e3ce2a5964acca900b32725e3ee7d..b46906280ecf38bac2bb036b753a4f3f7766bf68 100644 (file)
@@ -71,14 +71,6 @@ class Arm64OperandGenerator V8_FINAL : public OperandGenerator {
 };
 
 
-static void VisitRR(InstructionSelector* selector, ArchOpcode opcode,
-                    Node* node) {
-  Arm64OperandGenerator g(selector);
-  selector->Emit(opcode, g.DefineAsRegister(node),
-                 g.UseRegister(node->InputAt(0)));
-}
-
-
 static void VisitRRR(InstructionSelector* selector, ArchOpcode opcode,
                      Node* node) {
   Arm64OperandGenerator g(selector);
@@ -426,16 +418,6 @@ void InstructionSelector::VisitInt64UMod(Node* node) {
 }
 
 
-void InstructionSelector::VisitConvertInt32ToInt64(Node* node) {
-  VisitRR(this, kArm64Int32ToInt64, node);
-}
-
-
-void InstructionSelector::VisitConvertInt64ToInt32(Node* node) {
-  VisitRR(this, kArm64Int64ToInt32, node);
-}
-
-
 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) {
   Arm64OperandGenerator g(this);
   Emit(kArm64Int32ToFloat64, g.DefineAsDoubleRegister(node),
@@ -464,6 +446,24 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
 }
 
 
+void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Sxtw, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
+  Arm64OperandGenerator g(this);
+  Emit(kArm64Mov32, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat64Add(Node* node) {
   VisitRRRFloat64(this, kArm64Float64Add, node);
 }
index 03eaa398ab5da20314fb726afc31e49004453959..88398286842bc09714dfbcf6bf81e31a74fec6fd 100644 (file)
@@ -88,7 +88,9 @@ Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
 Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* control) {
   if (machine()->is64()) {
     return Replace(
-        graph()->NewNode(machine()->WordShl(), val, SmiShiftBitsConstant()));
+        graph()->NewNode(machine()->Word64Shl(),
+                         graph()->NewNode(machine()->ChangeInt32ToInt64(), val),
+                         SmiShiftBitsConstant()));
   }
 
   Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
@@ -129,7 +131,7 @@ Reduction ChangeLowering::ChangeTaggedToInt32(Node* val, Node* control) {
       graph()->NewNode(machine()->WordSar(), val, SmiShiftBitsConstant());
   Node* number =
       machine()->is64()
-          ? graph()->NewNode(machine()->ConvertInt64ToInt32(), integer)
+          ? graph()->NewNode(machine()->TruncateInt64ToInt32(), integer)
           : integer;
 
   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
@@ -158,7 +160,7 @@ Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* control) {
   Node* number = graph()->NewNode(
       machine()->ChangeInt32ToFloat64(),
       machine()->is64()
-          ? graph()->NewNode(machine()->ConvertInt64ToInt32(), integer)
+          ? graph()->NewNode(machine()->TruncateInt64ToInt32(), integer)
           : integer);
 
   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
index 66355ffb6eced3917559b7ac57fbd304d295d982..335d85ad08fbee5772978d9a61752e5bc76b5af3 100644 (file)
@@ -575,10 +575,6 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitInt64LessThan(node);
     case IrOpcode::kInt64LessThanOrEqual:
       return VisitInt64LessThanOrEqual(node);
-    case IrOpcode::kConvertInt32ToInt64:
-      return VisitConvertInt32ToInt64(node);
-    case IrOpcode::kConvertInt64ToInt32:
-      return VisitConvertInt64ToInt32(node);
     case IrOpcode::kChangeInt32ToFloat64:
       return MarkAsDouble(node), VisitChangeInt32ToFloat64(node);
     case IrOpcode::kChangeUint32ToFloat64:
@@ -587,6 +583,12 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitChangeFloat64ToInt32(node);
     case IrOpcode::kChangeFloat64ToUint32:
       return VisitChangeFloat64ToUint32(node);
+    case IrOpcode::kChangeInt32ToInt64:
+      return VisitChangeInt32ToInt64(node);
+    case IrOpcode::kChangeUint32ToUint64:
+      return VisitChangeUint32ToUint64(node);
+    case IrOpcode::kTruncateInt64ToInt32:
+      return VisitTruncateInt64ToInt32(node);
     case IrOpcode::kFloat64Add:
       return MarkAsDouble(node), VisitFloat64Add(node);
     case IrOpcode::kFloat64Sub:
@@ -752,12 +754,17 @@ void InstructionSelector::VisitInt64Mod(Node* node) { UNIMPLEMENTED(); }
 void InstructionSelector::VisitInt64UMod(Node* node) { UNIMPLEMENTED(); }
 
 
-void InstructionSelector::VisitConvertInt64ToInt32(Node* node) {
+void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
   UNIMPLEMENTED();
 }
 
 
-void InstructionSelector::VisitConvertInt32ToInt64(Node* node) {
+void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
+  UNIMPLEMENTED();
+}
+
+
+void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
   UNIMPLEMENTED();
 }
 
index cc9d5d903596c472feb0841c756f224817f4600d..014dbda06ad8e1da93649bca26387b0293df5031 100644 (file)
@@ -280,12 +280,13 @@ class MachineNodeFactory {
     return Int64LessThanOrEqual(b, a);
   }
 
+  // TODO(turbofan): What is this used for?
   Node* ConvertIntPtrToInt32(Node* a) {
-    return kPointerSize == 8 ? NEW_NODE_1(MACHINE()->ConvertInt64ToInt32(), a)
+    return kPointerSize == 8 ? NEW_NODE_1(MACHINE()->TruncateInt64ToInt32(), a)
                              : a;
   }
   Node* ConvertInt32ToIntPtr(Node* a) {
-    return kPointerSize == 8 ? NEW_NODE_1(MACHINE()->ConvertInt32ToInt64(), a)
+    return kPointerSize == 8 ? NEW_NODE_1(MACHINE()->ChangeInt32ToInt64(), a)
                              : a;
   }
 
@@ -339,12 +340,6 @@ class MachineNodeFactory {
   }
 
   // Conversions.
-  Node* ConvertInt32ToInt64(Node* a) {
-    return NEW_NODE_1(MACHINE()->ConvertInt32ToInt64(), a);
-  }
-  Node* ConvertInt64ToInt32(Node* a) {
-    return NEW_NODE_1(MACHINE()->ConvertInt64ToInt32(), a);
-  }
   Node* ChangeInt32ToFloat64(Node* a) {
     return NEW_NODE_1(MACHINE()->ChangeInt32ToFloat64(), a);
   }
@@ -357,6 +352,15 @@ class MachineNodeFactory {
   Node* ChangeFloat64ToUint32(Node* a) {
     return NEW_NODE_1(MACHINE()->ChangeFloat64ToUint32(), a);
   }
+  Node* ChangeInt32ToInt64(Node* a) {
+    return NEW_NODE_1(MACHINE()->ChangeInt32ToInt64(), a);
+  }
+  Node* ChangeUint32ToUint64(Node* a) {
+    return NEW_NODE_1(MACHINE()->ChangeUint32ToUint64(), a);
+  }
+  Node* TruncateInt64ToInt32(Node* a) {
+    return NEW_NODE_1(MACHINE()->TruncateInt64ToInt32(), a);
+  }
 
 #ifdef MACHINE_ASSEMBLER_SUPPORTS_CALL_C
   // Call to C.
index 219831c0cfedd92986ed4c4d8dd84cf4f3ee5b17..4b2d3417613555748201384ae10cdfdec09db21f 100644 (file)
@@ -121,19 +121,22 @@ class MachineOperatorBuilder {
   Operator* Int64LessThan() { BINOP(Int64LessThan); }
   Operator* Int64LessThanOrEqual() { BINOP(Int64LessThanOrEqual); }
 
-  Operator* ConvertInt32ToInt64() { UNOP(ConvertInt32ToInt64); }
-  Operator* ConvertInt64ToInt32() { UNOP(ConvertInt64ToInt32); }
-
   // Convert representation of integers between float64 and int32/uint32.
   // The precise rounding mode and handling of out of range inputs are *not*
   // defined for these operators, since they are intended only for use with
   // integers.
-  // TODO(titzer): rename ConvertXXX to ChangeXXX in machine operators.
   Operator* ChangeInt32ToFloat64() { UNOP(ChangeInt32ToFloat64); }
   Operator* ChangeUint32ToFloat64() { UNOP(ChangeUint32ToFloat64); }
   Operator* ChangeFloat64ToInt32() { UNOP(ChangeFloat64ToInt32); }
   Operator* ChangeFloat64ToUint32() { UNOP(ChangeFloat64ToUint32); }
 
+  // Sign/zero extend int32/uint32 to int64/uint64.
+  Operator* ChangeInt32ToInt64() { UNOP(ChangeInt32ToInt64); }
+  Operator* ChangeUint32ToUint64() { UNOP(ChangeUint32ToUint64); }
+
+  // Truncate the high order bits and convert the remaining bits to int32.
+  Operator* TruncateInt64ToInt32() { UNOP(TruncateInt64ToInt32); }
+
   // Floating point operators always operate with IEEE 754 round-to-nearest.
   Operator* Float64Add() { BINOP_C(Float64Add); }
   Operator* Float64Sub() { BINOP(Float64Sub); }
index 6c9fc0b944cbc13e2161a4b184aba5c6810e88ab..49caf880b55d6a562055fe6e694a55f60f6c8cea 100644 (file)
   V(Int64UMod)             \
   V(Int64LessThan)         \
   V(Int64LessThanOrEqual)  \
-  V(ConvertInt64ToInt32)   \
-  V(ConvertInt32ToInt64)   \
   V(ChangeInt32ToFloat64)  \
   V(ChangeUint32ToFloat64) \
   V(ChangeFloat64ToInt32)  \
   V(ChangeFloat64ToUint32) \
+  V(ChangeInt32ToInt64)    \
+  V(ChangeUint32ToUint64)  \
+  V(TruncateInt64ToInt32)  \
   V(Float64Add)            \
   V(Float64Sub)            \
   V(Float64Mul)            \
index d1b1b3c018b2b157d26a0ed1717ae4fbd318f590..72e4b6112d96a140a9c9561906f5445e5f1dba36 100644 (file)
@@ -5,8 +5,7 @@
 #ifndef V8_COMPILER_OPERATOR_PROPERTIES_INL_H_
 #define V8_COMPILER_OPERATOR_PROPERTIES_INL_H_
 
-#include "src/v8.h"
-
+#include "src/compiler/common-operator.h"
 #include "src/compiler/js-operator.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator-properties.h"
index 00e007d54ef43d6de426954c9cce01ed66b8dac7..7645addc6971831a859401264bb3e2f0bad81962 100644 (file)
@@ -627,10 +627,13 @@ class RepresentationSelector {
       case IrOpcode::kWord64Equal:
         return VisitBinop(node, kRepWord64, kRepBit);
 
-      case IrOpcode::kConvertInt32ToInt64:
+      case IrOpcode::kChangeInt32ToInt64:
         return VisitUnop(node, kTypeInt32 | kRepWord32,
-                         kTypeInt32 | kRepWord64);
-      case IrOpcode::kConvertInt64ToInt32:
+                         kTypeInt64 | kRepWord64);
+      case IrOpcode::kChangeUint32ToUint64:
+        return VisitUnop(node, kTypeUint32 | kRepWord32,
+                         kTypeUint64 | kRepWord64);
+      case IrOpcode::kTruncateInt64ToInt32:
         return VisitUnop(node, kTypeInt64 | kRepWord64,
                          kTypeInt32 | kRepWord32);
 
index c501b5cd20adba6ae28200f19d20e628592d29c8..2b539c8057dc3b720bb3bd5f9cebf30081786a89 100644 (file)
@@ -388,6 +388,24 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
     case kX64PushI:
       __ pushq(i.InputImmediate(0));
       break;
+    case kX64Movl: {
+      RegisterOrOperand input = i.InputRegisterOrOperand(0);
+      if (input.type == kRegister) {
+        __ movl(i.OutputRegister(), input.reg);
+      } else {
+        __ movl(i.OutputRegister(), input.operand);
+      }
+      break;
+    }
+    case kX64Movsxlq: {
+      RegisterOrOperand input = i.InputRegisterOrOperand(0);
+      if (input.type == kRegister) {
+        __ movsxlq(i.OutputRegister(), input.reg);
+      } else {
+        __ movsxlq(i.OutputRegister(), input.operand);
+      }
+      break;
+    }
     case kX64CallCodeObject: {
       if (HasImmediateInput(instr, 0)) {
         Handle<Code> code = Handle<Code>::cast(i.InputHeapObject(0));
@@ -484,12 +502,6 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ addq(rsp, Immediate(kDoubleSize));
       break;
     }
-    case kX64Int32ToInt64:
-      __ movzxwq(i.OutputRegister(), i.InputRegister(0));
-      break;
-    case kX64Int64ToInt32:
-      __ Move(i.OutputRegister(), i.InputRegister(0));
-      break;
     case kSSEFloat64ToInt32: {
       RegisterOrOperand input = i.InputRegisterOrOperand(0);
       if (input.type == kDoubleRegister) {
index 10d9ad0dcb07c9ff942bebbf8258ae4ef5987ab5..1345ce7aa48ead9a04c2a4028d20f30440ab061d 100644 (file)
@@ -46,6 +46,8 @@ namespace compiler {
   V(X64Ror32)                      \
   V(X64Push)                       \
   V(X64PushI)                      \
+  V(X64Movsxlq)                    \
+  V(X64Movl)                       \
   V(X64CallCodeObject)             \
   V(X64CallAddress)                \
   V(PopStack)                      \
@@ -56,8 +58,6 @@ namespace compiler {
   V(SSEFloat64Mul)                 \
   V(SSEFloat64Div)                 \
   V(SSEFloat64Mod)                 \
-  V(X64Int32ToInt64)               \
-  V(X64Int64ToInt32)               \
   V(SSEFloat64ToInt32)             \
   V(SSEFloat64ToUint32)            \
   V(SSEInt32ToFloat64)             \
index 55c35da5027be85b7510e5f9c6723bba057cb157..bb4c03bd7e96c65bca7336d070b095e759fbcccb 100644 (file)
@@ -513,6 +513,24 @@ void InstructionSelector::VisitChangeFloat64ToUint32(Node* node) {
 }
 
 
+void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kX64Movsxlq, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitChangeUint32ToUint64(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
+void InstructionSelector::VisitTruncateInt64ToInt32(Node* node) {
+  X64OperandGenerator g(this);
+  Emit(kX64Movl, g.DefineAsRegister(node), g.Use(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat64Add(Node* node) {
   X64OperandGenerator g(this);
   Emit(kSSEFloat64Add, g.DefineSameAsFirst(node),
@@ -554,22 +572,6 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
 }
 
 
-void InstructionSelector::VisitConvertInt64ToInt32(Node* node) {
-  X64OperandGenerator g(this);
-  // TODO(dcarney): other modes
-  Emit(kX64Int64ToInt32, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
-}
-
-
-void InstructionSelector::VisitConvertInt32ToInt64(Node* node) {
-  X64OperandGenerator g(this);
-  // TODO(dcarney): other modes
-  Emit(kX64Int32ToInt64, g.DefineAsRegister(node),
-       g.UseRegister(node->InputAt(0)));
-}
-
-
 void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
                                                     FlagsContinuation* cont) {
   VisitBinop(this, node, kX64Add32, cont);
index b8c6b9393d0af1b996eddea82516f25ad732faa3..6f37e601f6def1e17630a9ebecbaacde8b3c22a2 100644 (file)
@@ -4202,4 +4202,47 @@ TEST(RunInt32SubWithOverflowInBranchP) {
   }
 }
 
+
+TEST(RunChangeInt32ToInt64P) {
+  if (kPointerSize < 8) return;
+  int64_t actual = -1;
+  RawMachineAssemblerTester<int32_t> m(kMachInt32);
+  m.StoreToPointer(&actual, kMachInt64, m.ChangeInt32ToInt64(m.Parameter(0)));
+  m.Return(m.Int32Constant(0));
+  FOR_INT32_INPUTS(i) {
+    int64_t expected = *i;
+    CHECK_EQ(0, m.Call(*i));
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunChangeUint32ToUint64P) {
+  if (kPointerSize < 8) return;
+  int64_t actual = -1;
+  RawMachineAssemblerTester<int32_t> m(kMachUint32);
+  m.StoreToPointer(&actual, kMachUint64,
+                   m.ChangeUint32ToUint64(m.Parameter(0)));
+  m.Return(m.Int32Constant(0));
+  FOR_UINT32_INPUTS(i) {
+    int64_t expected = static_cast<uint64_t>(*i);
+    CHECK_EQ(0, m.Call(*i));
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunTruncateInt64ToInt32P) {
+  if (kPointerSize < 8) return;
+  int64_t expected = -1;
+  RawMachineAssemblerTester<int32_t> m;
+  m.Return(m.TruncateInt64ToInt32(m.LoadFromPointer(&expected, kMachInt64)));
+  FOR_UINT32_INPUTS(i) {
+    FOR_UINT32_INPUTS(j) {
+      expected = (static_cast<uint64_t>(*j) << 32) | *i;
+      CHECK_UINT32_EQ(expected, m.Call());
+    }
+  }
+}
+
 #endif  // V8_TURBOFAN_TARGET
index 2a86924248054f530b32e426c2a8fd0857d9a453..e0de59060ae4aca8ab88a8cd841074dd74f61883 100644 (file)
@@ -6,8 +6,6 @@
 
 #include "test/compiler-unittests/instruction-selector-unittest.h"
 
-#include "test/cctest/compiler/instruction-selector-tester.h"
-
 namespace v8 {
 namespace internal {
 namespace compiler {
@@ -128,6 +126,37 @@ TEST_F(InstructionSelectorTest, MulDivWithParameter) {
   }
 }
 
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) {
+  StreamBuilder m(this, kMachInt64, kMachInt32);
+  m.Return(m.ChangeInt32ToInt64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Sxtw, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) {
+  StreamBuilder m(this, kMachUint64, kMachUint32);
+  m.Return(m.ChangeUint32ToUint64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Mov32, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  m.Return(m.TruncateInt64ToInt32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kArm64Mov32, s[0]->arch_opcode());
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index d4054d892ca6e4da8aeef41cac620da10ad8f907..ddd1168f4a53e21f11a21b2653907abd9a2c2314 100644 (file)
@@ -295,7 +295,8 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
   ASSERT_TRUE(reduction.Changed());
 
   EXPECT_THAT(reduction.replacement(),
-              IsWord64Shl(val, IsInt32Constant(SmiShiftAmount())));
+              IsWord64Shl(IsChangeInt32ToInt64(val),
+                          IsInt32Constant(SmiShiftAmount())));
 }
 
 
@@ -315,7 +316,7 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
       IsPhi(
           IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
                  IsControlEffect(CaptureEq(&if_true))),
-          IsChangeInt32ToFloat64(IsConvertInt64ToInt32(
+          IsChangeInt32ToFloat64(IsTruncateInt64ToInt32(
               IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))),
           IsMerge(
               AllOf(CaptureEq(&if_true),
@@ -343,7 +344,7 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
       IsPhi(IsChangeFloat64ToInt32(IsLoad(
                 kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
                 IsControlEffect(CaptureEq(&if_true)))),
-            IsConvertInt64ToInt32(
+            IsTruncateInt64ToInt32(
                 IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))),
             IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
                     IsIfFalse(AllOf(
index 13bc0c7c3aa63617dddbc136683662cbe5c8a484..e486fe32d6534a7848e7b9aeb650541525fe2bf2 100644 (file)
@@ -28,6 +28,7 @@
         'graph-unittest.h',
         'instruction-selector-unittest.cc',
         'machine-operator-reducer-unittest.cc',
+        'machine-operator-unittest.cc',
       ],
       'conditions': [
         ['v8_target_arch=="arm"', {
             'ia32/instruction-selector-ia32-unittest.cc',
           ],
         }],
+        ['v8_target_arch=="x64"', {
+          'sources': [  ### gcmole(arch:x64) ###
+            'x64/instruction-selector-x64-unittest.cc',
+          ],
+        }],
         ['component=="shared_library"', {
           # compiler-unittests can't be built against a shared library, so we
           # need to depend on the underlying static target in that case.
index 82e95794169690b76577437f03e3363ef8bde8ed..03541e73a2be1bb1d8ff5f136b551b16498969ce 100644 (file)
@@ -73,6 +73,11 @@ class CompilerTest : public ::testing::Test {
   Zone zone_;
 };
 
+
+template <typename T>
+class CompilerTestWithParam : public CompilerTest,
+                              public ::testing::WithParamInterface<T> {};
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 1d85e70f162e3bb1720007cc6abe727e86b62870..868faca4c94ce54c0d32c5c7dfef659b3784bb32 100644 (file)
@@ -676,9 +676,11 @@ IS_BINOP_MATCHER(Int32AddWithOverflow)
   Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) {             \
     return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
   }
-IS_UNOP_MATCHER(ConvertInt64ToInt32)
 IS_UNOP_MATCHER(ChangeFloat64ToInt32)
 IS_UNOP_MATCHER(ChangeInt32ToFloat64)
+IS_UNOP_MATCHER(ChangeInt32ToInt64)
+IS_UNOP_MATCHER(ChangeUint32ToUint64)
+IS_UNOP_MATCHER(TruncateInt64ToInt32)
 #undef IS_UNOP_MATCHER
 
 }  // namespace compiler
index 5bc2e7714a0c673a656d606a1b8c84199e4d3918..7a242574c919acd839a82521b22bd833565b4113 100644 (file)
@@ -94,9 +94,11 @@ 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*> IsConvertInt64ToInt32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsChangeFloat64ToInt32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeInt32ToInt64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsChangeUint32ToUint64(const Matcher<Node*>& input_matcher);
+Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
 
 }  //  namespace compiler
 }  //  namespace internal
diff --git a/test/compiler-unittests/machine-operator-unittest.cc b/test/compiler-unittests/machine-operator-unittest.cc
new file mode 100644 (file)
index 0000000..4662e20
--- /dev/null
@@ -0,0 +1,75 @@
+// 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.
+
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/operator-properties-inl.h"
+#include "test/compiler-unittests/compiler-unittests.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::IsNull;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class MachineOperatorCommonTest : public CompilerTestWithParam<MachineType> {
+ public:
+  MachineOperatorCommonTest() : machine_(NULL) {}
+  virtual ~MachineOperatorCommonTest() { EXPECT_THAT(machine_, IsNull()); }
+
+  virtual void SetUp() V8_OVERRIDE {
+    CompilerTestWithParam::SetUp();
+    machine_ = new MachineOperatorBuilder(zone(), GetParam());
+  }
+
+  virtual void TearDown() V8_OVERRIDE {
+    delete machine_;
+    machine_ = NULL;
+    CompilerTestWithParam::TearDown();
+  }
+
+ protected:
+  MachineOperatorBuilder* machine() const { return machine_; }
+
+ private:
+  MachineOperatorBuilder* machine_;
+};
+
+
+TEST_P(MachineOperatorCommonTest, ChangeInt32ToInt64) {
+  Operator* op = machine()->ChangeInt32ToInt64();
+  EXPECT_EQ(1, OperatorProperties::GetValueInputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
+}
+
+
+TEST_P(MachineOperatorCommonTest, ChangeUint32ToUint64) {
+  Operator* op = machine()->ChangeUint32ToUint64();
+  EXPECT_EQ(1, OperatorProperties::GetValueInputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
+}
+
+
+TEST_P(MachineOperatorCommonTest, TruncateInt64ToInt32) {
+  Operator* op = machine()->TruncateInt64ToInt32();
+  EXPECT_EQ(1, OperatorProperties::GetValueInputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetTotalInputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
+}
+
+
+INSTANTIATE_TEST_CASE_P(MachineOperatorTest, MachineOperatorCommonTest,
+                        ::testing::Values(kRepWord32, kRepWord64));
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/compiler-unittests/x64/instruction-selector-x64-unittest.cc b/test/compiler-unittests/x64/instruction-selector-x64-unittest.cc
new file mode 100644 (file)
index 0000000..4e5c655
--- /dev/null
@@ -0,0 +1,43 @@
+// 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.
+
+#include "test/compiler-unittests/instruction-selector-unittest.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TEST_F(InstructionSelectorTest, ChangeInt32ToInt64WithParameter) {
+  StreamBuilder m(this, kMachInt64, kMachInt32);
+  m.Return(m.ChangeInt32ToInt64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movsxlq, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, ChangeUint32ToUint64WithParameter) {
+  StreamBuilder m(this, kMachUint64, kMachUint32);
+  m.Return(m.ChangeUint32ToUint64(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
+}
+
+
+TEST_F(InstructionSelectorTest, TruncateInt64ToInt32WithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachInt64);
+  m.Return(m.TruncateInt64ToInt32(m.Parameter(0)));
+  Stream s = m.Build();
+  ASSERT_EQ(1U, s.size());
+  EXPECT_EQ(kX64Movl, s[0]->arch_opcode());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8