[turbofan] Add TruncateFloat64ToInt32 machine operator.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Aug 2014 04:01:00 +0000 (04:01 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 20 Aug 2014 04:01:00 +0000 (04:01 +0000)
Fix ChangeLowering to use TruncateFloat64ToInt32.

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

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

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

18 files changed:
src/compiler/arm/code-generator-arm.cc
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/code-generator-arm64.cc
src/compiler/change-lowering.cc
src/compiler/ia32/code-generator-ia32.cc
src/compiler/instruction-codes.h
src/compiler/instruction-selector.cc
src/compiler/machine-node-factory.h
src/compiler/machine-operator.h
src/compiler/opcodes.h
src/compiler/x64/code-generator-x64.cc
test/cctest/cctest.status
test/cctest/compiler/test-run-machops.cc
test/compiler-unittests/change-lowering-unittest.cc
test/compiler-unittests/graph-unittest.cc
test/compiler-unittests/graph-unittest.h
test/compiler-unittests/instruction-selector-unittest.cc
test/compiler-unittests/machine-operator-unittest.cc

index b259ca9..3b971fa 100644 (file)
@@ -158,6 +158,10 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArchTruncateDoubleToI:
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmAdd:
       __ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
              i.OutputSBit());
index 7d28459..5bd1352 100644 (file)
@@ -74,6 +74,7 @@ class ArmOperandGenerator V8_FINAL : public OperandGenerator {
       case kArchNop:
       case kArchRet:
       case kArchDeoptimize:
+      case kArchTruncateDoubleToI:
       case kArmMul:
       case kArmMla:
       case kArmMls:
index 5127b10..0ea4f07 100644 (file)
@@ -149,6 +149,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
       break;
     }
+    case kArchTruncateDoubleToI:
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
     case kArm64Add:
       __ Add(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
       break;
index 8839828..5813be1 100644 (file)
@@ -124,7 +124,7 @@ Reduction ChangeLowering::ChangeTaggedToInt32(Node* val, Node* control) {
   Node* load = graph()->NewNode(
       machine()->Load(kMachFloat64), val, HeapNumberValueIndexConstant(),
       graph()->NewNode(common()->ControlEffect(), if_true));
-  Node* change = graph()->NewNode(machine()->ChangeFloat64ToInt32(), load);
+  Node* change = graph()->NewNode(machine()->TruncateFloat64ToInt32(), load);
 
   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
   Node* integer =
index ad80e49..7149b55 100644 (file)
@@ -129,6 +129,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
       break;
     }
+    case kArchTruncateDoubleToI:
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
     case kIA32Add:
       if (HasImmediateInput(instr, 1)) {
         __ add(i.InputOperand(0), i.InputImmediate(1));
index 35c8e31..16aa1db 100644 (file)
@@ -33,6 +33,7 @@ namespace compiler {
   V(ArchJmp)                \
   V(ArchNop)                \
   V(ArchRet)                \
+  V(ArchTruncateDoubleToI)  \
   TARGET_ARCH_OPCODE_LIST(V)
 
 enum ArchOpcode {
index 335d85a..bec9f5d 100644 (file)
@@ -587,6 +587,8 @@ void InstructionSelector::VisitNode(Node* node) {
       return VisitChangeInt32ToInt64(node);
     case IrOpcode::kChangeUint32ToUint64:
       return VisitChangeUint32ToUint64(node);
+    case IrOpcode::kTruncateFloat64ToInt32:
+      return VisitTruncateFloat64ToInt32(node);
     case IrOpcode::kTruncateInt64ToInt32:
       return VisitTruncateInt64ToInt32(node);
     case IrOpcode::kFloat64Add:
@@ -690,6 +692,13 @@ void InstructionSelector::VisitInt64LessThanOrEqual(Node* node) {
 }
 
 
+void InstructionSelector::VisitTruncateFloat64ToInt32(Node* node) {
+  OperandGenerator g(this);
+  Emit(kArchTruncateDoubleToI, g.DefineAsRegister(node),
+       g.UseDoubleRegister(node->InputAt(0)));
+}
+
+
 void InstructionSelector::VisitFloat64Equal(Node* node) {
   FlagsContinuation cont(kUnorderedEqual, node);
   VisitFloat64Compare(node, &cont);
index 014dbda..1d5b7fe 100644 (file)
@@ -358,6 +358,9 @@ class MachineNodeFactory {
   Node* ChangeUint32ToUint64(Node* a) {
     return NEW_NODE_1(MACHINE()->ChangeUint32ToUint64(), a);
   }
+  Node* TruncateFloat64ToInt32(Node* a) {
+    return NEW_NODE_1(MACHINE()->TruncateFloat64ToInt32(), a);
+  }
   Node* TruncateInt64ToInt32(Node* a) {
     return NEW_NODE_1(MACHINE()->TruncateInt64ToInt32(), a);
   }
index 4b2d341..402d489 100644 (file)
@@ -134,6 +134,9 @@ class MachineOperatorBuilder {
   Operator* ChangeInt32ToInt64() { UNOP(ChangeInt32ToInt64); }
   Operator* ChangeUint32ToUint64() { UNOP(ChangeUint32ToUint64); }
 
+  // Truncate double to int32 using JavaScript semantics.
+  Operator* TruncateFloat64ToInt32() { UNOP(TruncateFloat64ToInt32); }
+
   // Truncate the high order bits and convert the remaining bits to int32.
   Operator* TruncateInt64ToInt32() { UNOP(TruncateInt64ToInt32); }
 
index 49caf88..c89134f 100644 (file)
   V(StoreElement)
 
 // Opcodes for Machine-level operators.
-#define MACHINE_OP_LIST(V) \
-  V(Load)                  \
-  V(Store)                 \
-  V(Word32And)             \
-  V(Word32Or)              \
-  V(Word32Xor)             \
-  V(Word32Shl)             \
-  V(Word32Shr)             \
-  V(Word32Sar)             \
-  V(Word32Ror)             \
-  V(Word32Equal)           \
-  V(Word64And)             \
-  V(Word64Or)              \
-  V(Word64Xor)             \
-  V(Word64Shl)             \
-  V(Word64Shr)             \
-  V(Word64Sar)             \
-  V(Word64Ror)             \
-  V(Word64Equal)           \
-  V(Int32Add)              \
-  V(Int32AddWithOverflow)  \
-  V(Int32Sub)              \
-  V(Int32SubWithOverflow)  \
-  V(Int32Mul)              \
-  V(Int32Div)              \
-  V(Int32UDiv)             \
-  V(Int32Mod)              \
-  V(Int32UMod)             \
-  V(Int32LessThan)         \
-  V(Int32LessThanOrEqual)  \
-  V(Uint32LessThan)        \
-  V(Uint32LessThanOrEqual) \
-  V(Int64Add)              \
-  V(Int64Sub)              \
-  V(Int64Mul)              \
-  V(Int64Div)              \
-  V(Int64UDiv)             \
-  V(Int64Mod)              \
-  V(Int64UMod)             \
-  V(Int64LessThan)         \
-  V(Int64LessThanOrEqual)  \
-  V(ChangeInt32ToFloat64)  \
-  V(ChangeUint32ToFloat64) \
-  V(ChangeFloat64ToInt32)  \
-  V(ChangeFloat64ToUint32) \
-  V(ChangeInt32ToInt64)    \
-  V(ChangeUint32ToUint64)  \
-  V(TruncateInt64ToInt32)  \
-  V(Float64Add)            \
-  V(Float64Sub)            \
-  V(Float64Mul)            \
-  V(Float64Div)            \
-  V(Float64Mod)            \
-  V(Float64Equal)          \
-  V(Float64LessThan)       \
+#define MACHINE_OP_LIST(V)  \
+  V(Load)                   \
+  V(Store)                  \
+  V(Word32And)              \
+  V(Word32Or)               \
+  V(Word32Xor)              \
+  V(Word32Shl)              \
+  V(Word32Shr)              \
+  V(Word32Sar)              \
+  V(Word32Ror)              \
+  V(Word32Equal)            \
+  V(Word64And)              \
+  V(Word64Or)               \
+  V(Word64Xor)              \
+  V(Word64Shl)              \
+  V(Word64Shr)              \
+  V(Word64Sar)              \
+  V(Word64Ror)              \
+  V(Word64Equal)            \
+  V(Int32Add)               \
+  V(Int32AddWithOverflow)   \
+  V(Int32Sub)               \
+  V(Int32SubWithOverflow)   \
+  V(Int32Mul)               \
+  V(Int32Div)               \
+  V(Int32UDiv)              \
+  V(Int32Mod)               \
+  V(Int32UMod)              \
+  V(Int32LessThan)          \
+  V(Int32LessThanOrEqual)   \
+  V(Uint32LessThan)         \
+  V(Uint32LessThanOrEqual)  \
+  V(Int64Add)               \
+  V(Int64Sub)               \
+  V(Int64Mul)               \
+  V(Int64Div)               \
+  V(Int64UDiv)              \
+  V(Int64Mod)               \
+  V(Int64UMod)              \
+  V(Int64LessThan)          \
+  V(Int64LessThanOrEqual)   \
+  V(ChangeInt32ToFloat64)   \
+  V(ChangeUint32ToFloat64)  \
+  V(ChangeFloat64ToInt32)   \
+  V(ChangeFloat64ToUint32)  \
+  V(ChangeInt32ToInt64)     \
+  V(ChangeUint32ToUint64)   \
+  V(TruncateFloat64ToInt32) \
+  V(TruncateInt64ToInt32)   \
+  V(Float64Add)             \
+  V(Float64Sub)             \
+  V(Float64Mul)             \
+  V(Float64Div)             \
+  V(Float64Mod)             \
+  V(Float64Equal)           \
+  V(Float64LessThan)        \
   V(Float64LessThanOrEqual)
 
 #define VALUE_OP_LIST(V) \
index 2b539c8..abe954d 100644 (file)
@@ -222,6 +222,9 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
       __ call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
       break;
     }
+    case kArchTruncateDoubleToI:
+      __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
+      break;
     case kX64Add32:
       ASSEMBLE_BINOP(addl);
       break;
index d45e34f..fb40edd 100644 (file)
   'test-mark-compact/Promotion': [PASS, FAIL],
 
   # BUG(v8:3434).
-  ' test-api/LoadICFastApi_DirectCall_GCMoveStubWithProfiler': [SKIP]
+  ' test-api/LoadICFastApi_DirectCall_GCMoveStubWithProfiler': [SKIP],
+
+  # TODO(rodolph): Please investigate.
+  'test-run-machops/RunTruncateFloat64ToInt32P': [SKIP],
 }],  # 'arch == arm64'
 
 ['arch == arm64 and simulator_run == True', {
index 6f37e60..978842b 100644 (file)
@@ -4245,4 +4245,74 @@ TEST(RunTruncateInt64ToInt32P) {
   }
 }
 
+
+TEST(RunTruncateFloat64ToInt32P) {
+  struct {
+    double from;
+    double raw;
+  } kValues[] = {{0, 0},
+                 {0.5, 0},
+                 {-0.5, 0},
+                 {1.5, 1},
+                 {-1.5, -1},
+                 {5.5, 5},
+                 {-5.0, -5},
+                 {v8::base::OS::nan_value(), 0},
+                 {std::numeric_limits<double>::infinity(), 0},
+                 {-v8::base::OS::nan_value(), 0},
+                 {-std::numeric_limits<double>::infinity(), 0},
+                 {4.94065645841e-324, 0},
+                 {-4.94065645841e-324, 0},
+                 {0.9999999999999999, 0},
+                 {-0.9999999999999999, 0},
+                 {4294967296.0, 0},
+                 {-4294967296.0, 0},
+                 {9223372036854775000.0, 4294966272.0},
+                 {-9223372036854775000.0, -4294966272.0},
+                 {4.5036e+15, 372629504},
+                 {-4.5036e+15, -372629504},
+                 {287524199.5377777, 0x11234567},
+                 {-287524199.5377777, -0x11234567},
+                 {2300193596.302222, 2300193596.0},
+                 {-2300193596.302222, -2300193596.0},
+                 {4600387192.604444, 305419896},
+                 {-4600387192.604444, -305419896},
+                 {4823855600872397.0, 1737075661},
+                 {-4823855600872397.0, -1737075661},
+                 {4503603922337791.0, -1},
+                 {-4503603922337791.0, 1},
+                 {4503601774854143.0, 2147483647},
+                 {-4503601774854143.0, -2147483647},
+                 {9007207844675582.0, -2},
+                 {-9007207844675582.0, 2},
+                 {2.4178527921507624e+24, -536870912},
+                 {-2.4178527921507624e+24, 536870912},
+                 {2.417853945072267e+24, -536870912},
+                 {-2.417853945072267e+24, 536870912},
+                 {4.8357055843015248e+24, -1073741824},
+                 {-4.8357055843015248e+24, 1073741824},
+                 {4.8357078901445341e+24, -1073741824},
+                 {-4.8357078901445341e+24, 1073741824},
+                 {2147483647.0, 2147483647.0},
+                 {-2147483648.0, -2147483648.0},
+                 {9.6714111686030497e+24, -2147483648.0},
+                 {-9.6714111686030497e+24, -2147483648.0},
+                 {9.6714157802890681e+24, -2147483648.0},
+                 {-9.6714157802890681e+24, -2147483648.0},
+                 {1.9342813113834065e+25, 2147483648.0},
+                 {-1.9342813113834065e+25, 2147483648.0},
+                 {3.868562622766813e+25, 0},
+                 {-3.868562622766813e+25, 0},
+                 {1.7976931348623157e+308, 0},
+                 {-1.7976931348623157e+308, 0}};
+  double input = -1.0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.Return(m.TruncateFloat64ToInt32(m.LoadFromPointer(&input, kMachFloat64)));
+  for (size_t i = 0; i < ARRAY_SIZE(kValues); ++i) {
+    input = kValues[i].from;
+    uint64_t expected = static_cast<int64_t>(kValues[i].raw);
+    CHECK_EQ(static_cast<int>(expected), m.Call());
+  }
+}
+
 #endif  // V8_TURBOFAN_TARGET
index ddd1168..285ebbf 100644 (file)
@@ -263,7 +263,7 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
   Capture<Node*> branch, if_true;
   EXPECT_THAT(
       phi,
-      IsPhi(IsChangeFloat64ToInt32(IsLoad(
+      IsPhi(IsTruncateFloat64ToInt32(IsLoad(
                 kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
                 IsControlEffect(CaptureEq(&if_true)))),
             IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
@@ -341,7 +341,7 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
   Capture<Node*> branch, if_true;
   EXPECT_THAT(
       phi,
-      IsPhi(IsChangeFloat64ToInt32(IsLoad(
+      IsPhi(IsTruncateFloat64ToInt32(IsLoad(
                 kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
                 IsControlEffect(CaptureEq(&if_true)))),
             IsTruncateInt64ToInt32(
index 868faca..11fa6b3 100644 (file)
@@ -680,6 +680,7 @@ IS_UNOP_MATCHER(ChangeFloat64ToInt32)
 IS_UNOP_MATCHER(ChangeInt32ToFloat64)
 IS_UNOP_MATCHER(ChangeInt32ToInt64)
 IS_UNOP_MATCHER(ChangeUint32ToUint64)
+IS_UNOP_MATCHER(TruncateFloat64ToInt32)
 IS_UNOP_MATCHER(TruncateInt64ToInt32)
 #undef IS_UNOP_MATCHER
 
index 7a24257..46f67bb 100644 (file)
@@ -98,6 +98,7 @@ 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*> IsTruncateFloat64ToInt32(const Matcher<Node*>& input_matcher);
 Matcher<Node*> IsTruncateInt64ToInt32(const Matcher<Node*>& input_matcher);
 
 }  //  namespace compiler
index 91ae7cd..d6fef2e 100644 (file)
@@ -71,6 +71,10 @@ InstructionSelectorTest::Stream InstructionSelectorTest::StreamBuilder::Build(
 }
 
 
+// -----------------------------------------------------------------------------
+// Return.
+
+
 TARGET_TEST_F(InstructionSelectorTest, ReturnParameter) {
   StreamBuilder m(this, kMachInt32, kMachInt32);
   m.Return(m.Parameter(0));
@@ -96,6 +100,23 @@ TARGET_TEST_F(InstructionSelectorTest, ReturnZero) {
   EXPECT_EQ(1U, s[1]->InputCount());
 }
 
+
+// -----------------------------------------------------------------------------
+// Conversions.
+
+
+TARGET_TEST_F(InstructionSelectorTest, TruncateFloat64ToInt32WithParameter) {
+  StreamBuilder m(this, kMachInt32, kMachFloat64);
+  m.Return(m.TruncateFloat64ToInt32(m.Parameter(0)));
+  Stream s = m.Build(kAllInstructions);
+  ASSERT_EQ(3U, s.size());
+  EXPECT_EQ(kArchNop, s[0]->arch_opcode());
+  EXPECT_EQ(kArchTruncateDoubleToI, s[1]->arch_opcode());
+  EXPECT_EQ(1U, s[1]->InputCount());
+  EXPECT_EQ(1U, s[1]->OutputCount());
+  EXPECT_EQ(kArchRet, s[2]->arch_opcode());
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index d096658..84ffd34 100644 (file)
@@ -57,6 +57,16 @@ TEST_P(MachineOperatorCommonTest, ChangeUint32ToUint64) {
 }
 
 
+TEST_P(MachineOperatorCommonTest, TruncateFloat64ToInt32) {
+  Operator* op = machine()->TruncateFloat64ToInt32();
+  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));