[turbofan] Support lowering of ChangeFloat64ToTagged/ChangeTaggedToInt32.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Aug 2014 04:54:06 +0000 (04:54 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 19 Aug 2014 04:54:06 +0000 (04:54 +0000)
Adds new ValueEffect operator to ensure proper scheduling of
AllocateHeapNumber call nodes.

Also includes some refactoring to reduce code duplication.

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

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

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

src/compiler/change-lowering.cc
src/compiler/change-lowering.h
src/compiler/common-operator.h
src/compiler/opcodes.h
src/compiler/operator-properties-inl.h
src/compiler/typer.cc
test/compiler-unittests/change-lowering-unittest.cc
test/compiler-unittests/common-operator-unittest.cc
test/compiler-unittests/compiler-unittests.h
test/compiler-unittests/graph-unittest.cc
test/compiler-unittests/graph-unittest.h

index 4863f8fee9d9693f6507b5f803f864d3c38b8a07..03eaa398ab5da20314fb726afc31e49004453959 100644 (file)
@@ -15,16 +15,19 @@ ChangeLowering::~ChangeLowering() {}
 
 Reduction ChangeLowering::Reduce(Node* node) {
   Node* control = graph()->start();
-  Node* effect = control;
   switch (node->opcode()) {
     case IrOpcode::kChangeBitToBool:
       return ChangeBitToBool(node->InputAt(0), control);
     case IrOpcode::kChangeBoolToBit:
       return ChangeBoolToBit(node->InputAt(0));
+    case IrOpcode::kChangeFloat64ToTagged:
+      return ChangeFloat64ToTagged(node->InputAt(0), control);
     case IrOpcode::kChangeInt32ToTagged:
-      return ChangeInt32ToTagged(node->InputAt(0), effect, control);
+      return ChangeInt32ToTagged(node->InputAt(0), control);
     case IrOpcode::kChangeTaggedToFloat64:
-      return ChangeTaggedToFloat64(node->InputAt(0), effect, control);
+      return ChangeTaggedToFloat64(node->InputAt(0), control);
+    case IrOpcode::kChangeTaggedToInt32:
+      return ChangeTaggedToInt32(node->InputAt(0), control);
     default:
       return NoChange();
   }
@@ -77,49 +80,67 @@ Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
 }
 
 
-Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* effect,
-                                              Node* control) {
+Reduction ChangeLowering::ChangeFloat64ToTagged(Node* val, Node* control) {
+  return Replace(AllocateHeapNumberWithValue(val, control));
+}
+
+
+Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* control) {
   if (machine()->is64()) {
     return Replace(
         graph()->NewNode(machine()->WordShl(), val, SmiShiftBitsConstant()));
   }
 
-  Node* context = jsgraph()->SmiConstant(0);
-
   Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
   Node* ovf = graph()->NewNode(common()->Projection(1), add);
 
   Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
 
   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-  Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(), val);
-
-  const Runtime::Function* fn =
-      Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
-  DCHECK_EQ(0, fn->nargs);
-  CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
-      fn->function_id, 0, Operator::kNoProperties);
-  Node* heap_number = graph()->NewNode(
-      common()->Call(desc), jsgraph()->CEntryStubConstant(),
-      jsgraph()->ExternalConstant(ExternalReference(fn, isolate())),
-      jsgraph()->Int32Constant(fn->nargs), context, effect, if_true);
-  Node* store = graph()->NewNode(
-      machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
-      HeapNumberValueIndexConstant(), number, heap_number, if_true);
-  Node* finish = graph()->NewNode(common()->Finish(1), heap_number, store);
+  Node* heap_number = AllocateHeapNumberWithValue(
+      graph()->NewNode(machine()->ChangeInt32ToFloat64(), val), if_true);
 
   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
   Node* smi = graph()->NewNode(common()->Projection(0), add);
 
   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Node* phi = graph()->NewNode(common()->Phi(2), finish, smi, merge);
+  Node* phi = graph()->NewNode(common()->Phi(2), heap_number, smi, merge);
 
   return Replace(phi);
 }
 
 
-Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* effect,
-                                                Node* control) {
+Reduction ChangeLowering::ChangeTaggedToInt32(Node* val, Node* control) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagMask == 1);
+
+  Node* tag = graph()->NewNode(machine()->WordAnd(), val,
+                               jsgraph()->Int32Constant(kSmiTagMask));
+  Node* branch = graph()->NewNode(common()->Branch(), tag, control);
+
+  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+  Node* load = graph()->NewNode(
+      machine()->Load(kMachFloat64), val, HeapNumberValueIndexConstant(),
+      graph()->NewNode(common()->ControlEffect(), if_true));
+  Node* change = graph()->NewNode(machine()->ChangeFloat64ToInt32(), load);
+
+  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* integer =
+      graph()->NewNode(machine()->WordSar(), val, SmiShiftBitsConstant());
+  Node* number =
+      machine()->is64()
+          ? graph()->NewNode(machine()->ConvertInt64ToInt32(), integer)
+          : integer;
+
+  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+  Node* phi = graph()->NewNode(common()->Phi(2), change, number, merge);
+
+  return Replace(phi);
+}
+
+
+Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* control) {
+  STATIC_ASSERT(kSmiTag == 0);
   STATIC_ASSERT(kSmiTagMask == 1);
 
   Node* tag = graph()->NewNode(machine()->WordAnd(), val,
@@ -157,6 +178,27 @@ CommonOperatorBuilder* ChangeLowering::common() const {
   return jsgraph()->common();
 }
 
+
+Node* ChangeLowering::AllocateHeapNumberWithValue(Node* value, Node* control) {
+  // The AllocateHeapNumber() runtime function does not use the context, so we
+  // can safely pass in Smi zero here.
+  Node* context = jsgraph()->ZeroConstant();
+  Node* effect = graph()->NewNode(common()->ValueEffect(1), value);
+  const Runtime::Function* function =
+      Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
+  DCHECK_EQ(0, function->nargs);
+  CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
+      function->function_id, 0, Operator::kNoProperties);
+  Node* heap_number = graph()->NewNode(
+      common()->Call(desc), jsgraph()->CEntryStubConstant(),
+      jsgraph()->ExternalConstant(ExternalReference(function, isolate())),
+      jsgraph()->Int32Constant(function->nargs), context, effect, control);
+  Node* store = graph()->NewNode(
+      machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
+      HeapNumberValueIndexConstant(), value, heap_number, control);
+  return graph()->NewNode(common()->Finish(1), heap_number, store);
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 93ba14206203aa754b89370f3a6b50c4a7c8a7c0..55496e6e1a16c7a26903b391624d3ce33161bb38 100644 (file)
@@ -32,8 +32,10 @@ class ChangeLowering V8_FINAL : public Reducer {
 
   Reduction ChangeBitToBool(Node* val, Node* control);
   Reduction ChangeBoolToBit(Node* val);
-  Reduction ChangeInt32ToTagged(Node* val, Node* effect, Node* control);
-  Reduction ChangeTaggedToFloat64(Node* val, Node* effect, Node* control);
+  Reduction ChangeFloat64ToTagged(Node* val, Node* control);
+  Reduction ChangeInt32ToTagged(Node* val, Node* control);
+  Reduction ChangeTaggedToFloat64(Node* val, Node* control);
+  Reduction ChangeTaggedToInt32(Node* val, Node* control);
 
   Graph* graph() const;
   Isolate* isolate() const;
@@ -43,6 +45,8 @@ class ChangeLowering V8_FINAL : public Reducer {
   MachineOperatorBuilder* machine() const { return machine_; }
 
  private:
+  Node* AllocateHeapNumberWithValue(Node* value, Node* control);
+
   JSGraph* jsgraph_;
   Linkage* linkage_;
   MachineOperatorBuilder* machine_;
index 2c5f1b66fc7dcc3d2174918c0aa8387d5954fa84..0b51088ca6967d2836f83a8c8ca92ba68efc5d44 100644 (file)
@@ -134,6 +134,11 @@ class CommonOperatorBuilder {
     return new (zone_) SimpleOperator(IrOpcode::kControlEffect, Operator::kPure,
                                       0, 0, "ControlEffect");
   }
+  Operator* ValueEffect(int arguments) {
+    DCHECK(arguments > 0);  // Disallow empty value effects.
+    return new (zone_) SimpleOperator(IrOpcode::kValueEffect, Operator::kPure,
+                                      arguments, 0, "ValueEffect");
+  }
   Operator* Finish(int arguments) {
     DCHECK(arguments > 0);  // Disallow empty finishes.
     return new (zone_) Operator1<int>(IrOpcode::kFinish, Operator::kPure, 1, 1,
index a3e1ba493ea1f2d6733cf33b469c410e7da4fe57..6c9fc0b944cbc13e2161a4b184aba5c6810e88ab 100644 (file)
@@ -34,6 +34,7 @@
   V(Phi)                 \
   V(EffectPhi)           \
   V(ControlEffect)       \
+  V(ValueEffect)         \
   V(Finish)              \
   V(FrameState)          \
   V(StateValues)         \
index 582d5e4ca7d416f3673b5e60c56c10b880f74ebb..d1b1b3c018b2b157d26a0ed1717ae4fbd318f590 100644 (file)
@@ -91,6 +91,7 @@ inline bool OperatorProperties::HasValueOutput(Operator* op) {
 inline bool OperatorProperties::HasEffectOutput(Operator* op) {
   return op->opcode() == IrOpcode::kStart ||
          op->opcode() == IrOpcode::kControlEffect ||
+         op->opcode() == IrOpcode::kValueEffect ||
          (op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) > 0);
 }
 
index 6a0127e608b680537bf7be1b2d51b7febcfaee74..73fe41d58291ff3dfbe0637b6dcc7c103b0041e9 100644 (file)
@@ -272,6 +272,11 @@ Bounds Typer::Visitor::TypeControlEffect(Node* node) {
 }
 
 
+Bounds Typer::Visitor::TypeValueEffect(Node* node) {
+  return Bounds(Type::None(zone()));
+}
+
+
 Bounds Typer::Visitor::TypeFinish(Node* node) { return OperandType(node, 0); }
 
 
index 329acfff1ef57dd83852ea854aef9afe590c0626..46c07fd1290641f03ee664a8d846e1122a31909c 100644 (file)
@@ -19,20 +19,52 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
-template <typename T>
+// TODO(bmeurer): Find a new home for these functions.
+inline std::ostream& operator<<(std::ostream& os, const MachineType& type) {
+  OStringStream ost;
+  ost << type;
+  return os << ost.c_str();
+}
+
+
 class ChangeLoweringTest : public GraphTest {
  public:
-  static const size_t kPointerSize = sizeof(T);
-  static const MachineType kWordRepresentation =
-      (kPointerSize == 4) ? kRepWord32 : kRepWord64;
-  STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
-  static const int kHeapNumberValueOffset = static_cast<int>(
-      (HeapNumber::kValueOffset / kApiPointerSize) * kPointerSize);
-
   ChangeLoweringTest() : simplified_(zone()) {}
   virtual ~ChangeLoweringTest() {}
 
+  virtual MachineType WordRepresentation() const = 0;
+
  protected:
+  int HeapNumberValueOffset() const {
+    STATIC_ASSERT(HeapNumber::kValueOffset % kApiPointerSize == 0);
+    return (HeapNumber::kValueOffset / kApiPointerSize) * PointerSize() -
+           kHeapObjectTag;
+  }
+  bool Is32() const { return WordRepresentation() == kRepWord32; }
+  int PointerSize() const {
+    switch (WordRepresentation()) {
+      case kRepWord32:
+        return 4;
+      case kRepWord64:
+        return 8;
+      default:
+        break;
+    }
+    UNREACHABLE();
+    return 0;
+  }
+  int SmiShiftAmount() const { return kSmiTagSize + SmiShiftSize(); }
+  int SmiShiftSize() const {
+    // TODO(turbofan): Work-around for weird GCC 4.6 linker issue:
+    // src/compiler/change-lowering.cc:46: undefined reference to
+    // `v8::internal::SmiTagging<4u>::kSmiShiftSize'
+    // src/compiler/change-lowering.cc:46: undefined reference to
+    // `v8::internal::SmiTagging<8u>::kSmiShiftSize'
+    STATIC_ASSERT(SmiTagging<4>::kSmiShiftSize == 0);
+    STATIC_ASSERT(SmiTagging<8>::kSmiShiftSize == 31);
+    return Is32() ? 0 : 31;
+  }
+
   Node* Parameter(int32_t index = 0) {
     return graph()->NewNode(common()->Parameter(index), graph()->start());
   }
@@ -42,20 +74,35 @@ class ChangeLoweringTest : public GraphTest {
     JSGraph jsgraph(graph(), common(), &typer);
     CompilationInfo info(isolate(), zone());
     Linkage linkage(&info);
-    MachineOperatorBuilder machine(zone(), kWordRepresentation);
+    MachineOperatorBuilder machine(zone(), WordRepresentation());
     ChangeLowering reducer(&jsgraph, &linkage, &machine);
     return reducer.Reduce(node);
   }
 
   SimplifiedOperatorBuilder* simplified() { return &simplified_; }
 
-  PrintableUnique<HeapObject> true_unique() {
-    return PrintableUnique<HeapObject>::CreateImmovable(
-        zone(), factory()->true_value());
+  Matcher<Node*> IsAllocateHeapNumber(const Matcher<Node*>& effect_matcher,
+                                      const Matcher<Node*>& control_matcher) {
+    return IsCall(
+        _, IsHeapConstant(PrintableUnique<HeapObject>::CreateImmovable(
+               zone(), CEntryStub(isolate(), 1).GetCode())),
+        IsExternalConstant(ExternalReference(
+            Runtime::FunctionForId(Runtime::kAllocateHeapNumber), isolate())),
+        IsInt32Constant(0), IsNumberConstant(0.0), effect_matcher,
+        control_matcher);
   }
-  PrintableUnique<HeapObject> false_unique() {
-    return PrintableUnique<HeapObject>::CreateImmovable(
-        zone(), factory()->false_value());
+  Matcher<Node*> IsFalse() {
+    return IsHeapConstant(PrintableUnique<HeapObject>::CreateImmovable(
+        zone(), factory()->false_value()));
+  }
+  Matcher<Node*> IsTrue() {
+    return IsHeapConstant(PrintableUnique<HeapObject>::CreateImmovable(
+        zone(), factory()->true_value()));
+  }
+  Matcher<Node*> IsWordEqual(const Matcher<Node*>& lhs_matcher,
+                             const Matcher<Node*>& rhs_matcher) {
+    return Is32() ? IsWord32Equal(lhs_matcher, rhs_matcher)
+                  : IsWord64Equal(lhs_matcher, rhs_matcher);
   }
 
  private:
@@ -63,53 +110,94 @@ class ChangeLoweringTest : public GraphTest {
 };
 
 
-typedef ::testing::Types<int32_t, int64_t> ChangeLoweringTypes;
-TYPED_TEST_CASE(ChangeLoweringTest, ChangeLoweringTypes);
+// -----------------------------------------------------------------------------
+// Common.
 
+namespace {
 
-TARGET_TYPED_TEST(ChangeLoweringTest, ChangeBitToBool) {
-  Node* val = this->Parameter(0);
-  Node* node =
-      this->graph()->NewNode(this->simplified()->ChangeBitToBool(), val);
-  Reduction reduction = this->Reduce(node);
+class Common : public ChangeLoweringTest,
+               public ::testing::WithParamInterface<MachineType> {
+ public:
+  virtual ~Common() {}
+
+  virtual MachineType WordRepresentation() const V8_FINAL V8_OVERRIDE {
+    return GetParam();
+  }
+};
+
+
+TARGET_TEST_P(Common, ChangeBitToBool) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeBitToBool(), val);
+  Reduction reduction = Reduce(node);
   ASSERT_TRUE(reduction.Changed());
 
   Node* phi = reduction.replacement();
   Capture<Node*> branch;
-  EXPECT_THAT(
-      phi, IsPhi(IsHeapConstant(this->true_unique()),
-                 IsHeapConstant(this->false_unique()),
-                 IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
-                                        IsBranch(val, this->graph()->start()))),
-                         IsIfFalse(CaptureEq(&branch)))));
+  EXPECT_THAT(phi,
+              IsPhi(IsTrue(), IsFalse(),
+                    IsMerge(IsIfTrue(AllOf(CaptureEq(&branch),
+                                           IsBranch(val, graph()->start()))),
+                            IsIfFalse(CaptureEq(&branch)))));
 }
 
 
-TARGET_TYPED_TEST(ChangeLoweringTest, StringAdd) {
-  Node* node = this->graph()->NewNode(this->simplified()->StringAdd(),
-                                      this->Parameter(0), this->Parameter(1));
-  Reduction reduction = this->Reduce(node);
-  EXPECT_FALSE(reduction.Changed());
-}
-
+TARGET_TEST_P(Common, ChangeBoolToBit) {
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
 
-class ChangeLowering32Test : public ChangeLoweringTest<int32_t> {
- public:
-  virtual ~ChangeLowering32Test() {}
-};
+  EXPECT_THAT(reduction.replacement(), IsWordEqual(val, IsTrue()));
+}
 
 
-TARGET_TEST_F(ChangeLowering32Test, ChangeBoolToBit) {
+TARGET_TEST_P(Common, ChangeFloat64ToTagged) {
   Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
+  Node* node = graph()->NewNode(simplified()->ChangeFloat64ToTagged(), val);
   Reduction reduction = Reduce(node);
   ASSERT_TRUE(reduction.Changed());
 
-  EXPECT_THAT(reduction.replacement(),
-              IsWord32Equal(val, IsHeapConstant(true_unique())));
+  Node* finish = reduction.replacement();
+  Capture<Node*> heap_number;
+  EXPECT_THAT(
+      finish,
+      IsFinish(
+          AllOf(CaptureEq(&heap_number),
+                IsAllocateHeapNumber(IsValueEffect(val), graph()->start())),
+          IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
+                  IsInt32Constant(HeapNumberValueOffset()), val,
+                  CaptureEq(&heap_number), graph()->start())));
 }
 
 
+TARGET_TEST_P(Common, StringAdd) {
+  Node* node =
+      graph()->NewNode(simplified()->StringAdd(), Parameter(0), Parameter(1));
+  Reduction reduction = Reduce(node);
+  EXPECT_FALSE(reduction.Changed());
+}
+
+}  // namespace
+
+
+INSTANTIATE_TEST_CASE_P(ChangeLoweringTest, Common,
+                        ::testing::Values(kRepWord32, kRepWord64));
+
+
+// -----------------------------------------------------------------------------
+// 32-bit
+
+
+class ChangeLowering32Test : public ChangeLoweringTest {
+ public:
+  virtual ~ChangeLowering32Test() {}
+  virtual MachineType WordRepresentation() const V8_FINAL V8_OVERRIDE {
+    return kRepWord32;
+  }
+};
+
+
 TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
   Node* val = Parameter(0);
   Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
@@ -118,32 +206,21 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
 
   Node* phi = reduction.replacement();
   Capture<Node*> add, branch, heap_number, if_true;
-  const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
   EXPECT_THAT(
       phi,
-      IsPhi(
-          IsFinish(
-              AllOf(
-                  CaptureEq(&heap_number),
-                  IsCall(
-                      _, IsHeapConstant(
-                             PrintableUnique<HeapObject>::CreateImmovable(
-                                 zone(), CEntryStub(isolate(), 1).GetCode())),
-                      IsExternalConstant(ExternalReference(
-                          Runtime::FunctionForId(Runtime::kAllocateHeapNumber),
-                          isolate())),
-                      IsInt32Constant(0), IsNumberConstant(0.0),
-                      graph()->start(), CaptureEq(&if_true))),
-              IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
-                      IsInt32Constant(kValueOffset),
-                      IsChangeInt32ToFloat64(val), CaptureEq(&heap_number),
-                      CaptureEq(&if_true))),
-          IsProjection(
-              0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))),
-          IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
-                  IsIfFalse(AllOf(CaptureEq(&branch),
-                                  IsBranch(IsProjection(1, CaptureEq(&add)),
-                                           graph()->start()))))));
+      IsPhi(IsFinish(
+                AllOf(CaptureEq(&heap_number),
+                      IsAllocateHeapNumber(_, CaptureEq(&if_true))),
+                IsStore(kMachFloat64, kNoWriteBarrier, CaptureEq(&heap_number),
+                        IsInt32Constant(HeapNumberValueOffset()),
+                        IsChangeInt32ToFloat64(val), CaptureEq(&heap_number),
+                        CaptureEq(&if_true))),
+            IsProjection(
+                0, AllOf(CaptureEq(&add), IsInt32AddWithOverflow(val, val))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(CaptureEq(&branch),
+                                    IsBranch(IsProjection(1, CaptureEq(&add)),
+                                             graph()->start()))))));
 }
 
 
@@ -156,18 +233,15 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
   Reduction reduction = Reduce(node);
   ASSERT_TRUE(reduction.Changed());
 
-  const int32_t kShiftAmount =
-      kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
-  const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
   Node* phi = reduction.replacement();
   Capture<Node*> branch, if_true;
   EXPECT_THAT(
       phi,
       IsPhi(
-          IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset),
+          IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
                  IsControlEffect(CaptureEq(&if_true))),
           IsChangeInt32ToFloat64(
-              IsWord32Sar(val, IsInt32Constant(kShiftAmount))),
+              IsWord32Sar(val, IsInt32Constant(SmiShiftAmount()))),
           IsMerge(
               AllOf(CaptureEq(&if_true),
                     IsIfTrue(AllOf(
@@ -178,33 +252,52 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
 }
 
 
-class ChangeLowering64Test : public ChangeLoweringTest<int64_t> {
- public:
-  virtual ~ChangeLowering64Test() {}
-};
-
+TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToInt32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
 
-TARGET_TEST_F(ChangeLowering64Test, ChangeBoolToBit) {
   Node* val = Parameter(0);
-  Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
   Reduction reduction = Reduce(node);
   ASSERT_TRUE(reduction.Changed());
 
-  EXPECT_THAT(reduction.replacement(),
-              IsWord64Equal(val, IsHeapConstant(true_unique())));
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(IsChangeFloat64ToInt32(IsLoad(
+                kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
+                IsControlEffect(CaptureEq(&if_true)))),
+            IsWord32Sar(val, IsInt32Constant(SmiShiftAmount())),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))))));
 }
 
 
+// -----------------------------------------------------------------------------
+// 64-bit
+
+
+class ChangeLowering64Test : public ChangeLoweringTest {
+ public:
+  virtual ~ChangeLowering64Test() {}
+  virtual MachineType WordRepresentation() const V8_FINAL V8_OVERRIDE {
+    return kRepWord64;
+  }
+};
+
+
 TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
   Node* val = Parameter(0);
   Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
   Reduction reduction = Reduce(node);
   ASSERT_TRUE(reduction.Changed());
 
-  const int32_t kShiftAmount =
-      kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
   EXPECT_THAT(reduction.replacement(),
-              IsWord64Shl(val, IsInt32Constant(kShiftAmount)));
+              IsWord64Shl(val, IsInt32Constant(SmiShiftAmount())));
 }
 
 
@@ -217,18 +310,15 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
   Reduction reduction = Reduce(node);
   ASSERT_TRUE(reduction.Changed());
 
-  const int32_t kShiftAmount =
-      kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
-  const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
   Node* phi = reduction.replacement();
   Capture<Node*> branch, if_true;
   EXPECT_THAT(
       phi,
       IsPhi(
-          IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset),
+          IsLoad(kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
                  IsControlEffect(CaptureEq(&if_true))),
           IsChangeInt32ToFloat64(IsConvertInt64ToInt32(
-              IsWord64Sar(val, IsInt32Constant(kShiftAmount)))),
+              IsWord64Sar(val, IsInt32Constant(SmiShiftAmount())))),
           IsMerge(
               AllOf(CaptureEq(&if_true),
                     IsIfTrue(AllOf(
@@ -238,6 +328,32 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
               IsIfFalse(CaptureEq(&branch)))));
 }
 
+
+TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToInt32) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
+  Node* val = Parameter(0);
+  Node* node = graph()->NewNode(simplified()->ChangeTaggedToInt32(), val);
+  Reduction reduction = Reduce(node);
+  ASSERT_TRUE(reduction.Changed());
+
+  Node* phi = reduction.replacement();
+  Capture<Node*> branch, if_true;
+  EXPECT_THAT(
+      phi,
+      IsPhi(IsChangeFloat64ToInt32(IsLoad(
+                kMachFloat64, val, IsInt32Constant(HeapNumberValueOffset()),
+                IsControlEffect(CaptureEq(&if_true)))),
+            IsConvertInt64ToInt32(
+                IsWord64Sar(val, IsInt32Constant(SmiShiftAmount()))),
+            IsMerge(AllOf(CaptureEq(&if_true), IsIfTrue(CaptureEq(&branch))),
+                    IsIfFalse(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))))));
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index f034127f92c00b841f41b1861e776e399f427dca..79a34df2a997c0e5d1c2f09f7e69fe364291d571 100644 (file)
@@ -10,6 +10,9 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+static const int kArguments[] = {1, 5, 6, 42, 100, 10000, kMaxInt};
+
+
 CommonOperatorTest::CommonOperatorTest() : common_(zone()) {}
 
 
@@ -26,8 +29,19 @@ TEST_F(CommonOperatorTest, ControlEffect) {
 }
 
 
+TEST_F(CommonOperatorTest, ValueEffect) {
+  TRACED_FOREACH(int, arguments, kArguments) {
+    Operator* op = common()->ValueEffect(arguments);
+    EXPECT_EQ(arguments, OperatorProperties::GetValueInputCount(op));
+    EXPECT_EQ(arguments, OperatorProperties::GetTotalInputCount(op));
+    EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+    EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
+    EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
+  }
+}
+
+
 TEST_F(CommonOperatorTest, Finish) {
-  static const int kArguments[] = {1, 5, 6, 42, 100, 10000, kMaxInt};
   TRACED_FOREACH(int, arguments, kArguments) {
     Operator* op = common()->Finish(arguments);
     EXPECT_EQ(1, OperatorProperties::GetValueInputCount(op));
index fef34cffd6808d943628102884690aa5713ce329..82e95794169690b76577437f03e3363ef8bde8ed 100644 (file)
@@ -33,6 +33,16 @@ namespace compiler {
 #endif
 
 
+// The TARGET_TEST_P(Case, Name) macro works just like
+// TEST_P(Case, Name), except that the test is disabled
+// if the platform is not a supported TurboFan target.
+#if V8_TURBOFAN_TARGET
+#define TARGET_TEST_P(Case, Name) TEST_P(Case, Name)
+#else
+#define TARGET_TEST_P(Case, Name) TEST_P(Case, DISABLED_##Name)
+#endif
+
+
 // The TARGET_TYPED_TEST(Case, Name) macro works just like
 // TYPED_TEST(Case, Name), except that the test is disabled
 // if the platform is not a supported TurboFan target.
index e5b413c545260c519d8697a1556702ec85a499c7..1d85e70f162e3bb1720007cc6abe727e86b62870 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "src/compiler/node-properties-inl.h"
 
+using testing::_;
 using testing::MakeMatcher;
 using testing::MatcherInterface;
 using testing::MatchResultListener;
@@ -567,6 +568,11 @@ Matcher<Node*> IsControlEffect(const Matcher<Node*>& control_matcher) {
 }
 
 
+Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher) {
+  return MakeMatcher(new IsUnopMatcher(IrOpcode::kValueEffect, value_matcher));
+}
+
+
 Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
                         const Matcher<Node*>& effect_matcher) {
   return MakeMatcher(new IsFinishMatcher(value_matcher, effect_matcher));
@@ -671,6 +677,7 @@ IS_BINOP_MATCHER(Int32AddWithOverflow)
     return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
   }
 IS_UNOP_MATCHER(ConvertInt64ToInt32)
+IS_UNOP_MATCHER(ChangeFloat64ToInt32)
 IS_UNOP_MATCHER(ChangeInt32ToFloat64)
 #undef IS_UNOP_MATCHER
 
index 37409198b56f36e1cacc4c6b73581415ba6b48f2..5bc2e7714a0c673a656d606a1b8c84199e4d3918 100644 (file)
@@ -35,6 +35,7 @@ class GraphTest : public CommonOperatorTest {
 
 using ::testing::Matcher;
 
+
 Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
                         const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
@@ -42,6 +43,7 @@ Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
 Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsControlEffect(const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher);
 Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
                         const Matcher<Node*>& effect_matcher);
 Matcher<Node*> IsExternalConstant(
@@ -93,6 +95,7 @@ Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_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);
 
 }  //  namespace compiler