Refactor ChangeLowering class to avoid template specialization.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Aug 2014 06:54:07 +0000 (06:54 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 18 Aug 2014 06:54:07 +0000 (06:54 +0000)
Also refactor the unit tests and add support to easily
match DAGs using CaptureEq() matcher.

TEST=compiler-unittests
BUG=v8:3489
LOG=n
R=jarin@chromium.org

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

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

16 files changed:
src/compiler/change-lowering.cc
src/compiler/change-lowering.h
src/compiler/js-graph.cc
src/compiler/js-graph.h
test/compiler-unittests/DEPS
test/compiler-unittests/change-lowering-unittest.cc
test/compiler-unittests/common-operator-unittest.cc [new file with mode: 0644]
test/compiler-unittests/common-operator-unittest.h [new file with mode: 0644]
test/compiler-unittests/compiler-unittests.cc
test/compiler-unittests/compiler-unittests.gyp
test/compiler-unittests/compiler-unittests.h
test/compiler-unittests/graph-unittest.cc [moved from test/compiler-unittests/node-matchers.cc with 82% similarity]
test/compiler-unittests/graph-unittest.h [moved from test/compiler-unittests/node-matchers.h with 80% similarity]
test/compiler-unittests/machine-operator-reducer-unittest.cc
testing/gmock-support.h [new file with mode: 0644]
testing/gmock.gyp

index e80adec..b07e548 100644 (file)
 
 #include "src/compiler/change-lowering.h"
 
-#include "src/compiler/common-node-cache.h"
-#include "src/compiler/graph.h"
+#include "src/compiler/js-graph.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-ChangeLoweringBase::ChangeLoweringBase(Graph* graph, Linkage* linkage,
-                                       CommonNodeCache* cache)
-    : graph_(graph),
-      isolate_(graph->zone()->isolate()),
-      linkage_(linkage),
-      cache_(cache),
-      common_(graph->zone()),
-      machine_(graph->zone()) {}
+ChangeLowering::~ChangeLowering() {}
 
 
-ChangeLoweringBase::~ChangeLoweringBase() {}
-
-
-Node* ChangeLoweringBase::ExternalConstant(ExternalReference reference) {
-  Node** loc = cache()->FindExternalConstant(reference);
-  if (*loc == NULL) {
-    *loc = graph()->NewNode(common()->ExternalConstant(reference));
-  }
-  return *loc;
-}
-
-
-Node* ChangeLoweringBase::HeapConstant(PrintableUnique<HeapObject> value) {
-  // TODO(bmeurer): Use common node cache.
-  return graph()->NewNode(common()->HeapConstant(value));
-}
-
-
-Node* ChangeLoweringBase::ImmovableHeapConstant(Handle<HeapObject> value) {
-  return HeapConstant(
-      PrintableUnique<HeapObject>::CreateImmovable(graph()->zone(), value));
-}
-
-
-Node* ChangeLoweringBase::Int32Constant(int32_t value) {
-  Node** loc = cache()->FindInt32Constant(value);
-  if (*loc == NULL) {
-    *loc = graph()->NewNode(common()->Int32Constant(value));
-  }
-  return *loc;
-}
-
-
-Node* ChangeLoweringBase::NumberConstant(double value) {
-  Node** loc = cache()->FindNumberConstant(value);
-  if (*loc == NULL) {
-    *loc = graph()->NewNode(common()->NumberConstant(value));
-  }
-  return *loc;
-}
-
-
-Node* ChangeLoweringBase::CEntryStubConstant() {
-  if (!c_entry_stub_constant_.is_set()) {
-    c_entry_stub_constant_.set(
-        ImmovableHeapConstant(CEntryStub(isolate(), 1).GetCode()));
+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::kChangeInt32ToTagged:
+      return ChangeInt32ToTagged(node->InputAt(0), effect, control);
+    case IrOpcode::kChangeTaggedToFloat64:
+      return ChangeTaggedToFloat64(node->InputAt(0), effect, control);
+    default:
+      return NoChange();
   }
-  return c_entry_stub_constant_.get();
+  UNREACHABLE();
+  return NoChange();
 }
 
 
-Node* ChangeLoweringBase::TrueConstant() {
-  if (!true_constant_.is_set()) {
-    true_constant_.set(
-        ImmovableHeapConstant(isolate()->factory()->true_value()));
-  }
-  return true_constant_.get();
+Node* ChangeLowering::HeapNumberValueIndexConstant() {
+  STATIC_ASSERT(HeapNumber::kValueOffset % kPointerSize == 0);
+  const int heap_number_value_offset =
+      ((HeapNumber::kValueOffset / kPointerSize) * (machine()->is64() ? 8 : 4));
+  return jsgraph()->Int32Constant(heap_number_value_offset - kHeapObjectTag);
 }
 
 
-Node* ChangeLoweringBase::FalseConstant() {
-  if (!false_constant_.is_set()) {
-    false_constant_.set(
-        ImmovableHeapConstant(isolate()->factory()->false_value()));
-  }
-  return false_constant_.get();
+Node* ChangeLowering::SmiShiftBitsConstant() {
+  const int smi_shift_size = (machine()->is64() ? SmiTagging<8>::kSmiShiftSize
+                                                : SmiTagging<4>::kSmiShiftSize);
+  return jsgraph()->Int32Constant(smi_shift_size + kSmiTagSize);
 }
 
 
-Reduction ChangeLoweringBase::ChangeBitToBool(Node* val, Node* control) {
+Reduction ChangeLowering::ChangeBitToBool(Node* val, Node* control) {
   Node* branch = graph()->NewNode(common()->Branch(), val, control);
 
   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-  Node* true_value = TrueConstant();
+  Node* true_value = jsgraph()->TrueConstant();
 
   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-  Node* false_value = FalseConstant();
+  Node* false_value = jsgraph()->FalseConstant();
 
   Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
   Node* phi =
@@ -107,51 +65,20 @@ Reduction ChangeLoweringBase::ChangeBitToBool(Node* val, Node* control) {
 }
 
 
-template <size_t kPointerSize>
-ChangeLowering<kPointerSize>::ChangeLowering(Graph* graph, Linkage* linkage)
-    : ChangeLoweringBase(graph, linkage,
-                         new (graph->zone()) CommonNodeCache(graph->zone())) {}
-
-
-template <size_t kPointerSize>
-Reduction ChangeLowering<kPointerSize>::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::kChangeInt32ToTagged:
-      return ChangeInt32ToTagged(node->InputAt(0), effect, control);
-    case IrOpcode::kChangeTaggedToFloat64:
-      return ChangeTaggedToFloat64(node->InputAt(0), effect, control);
-    default:
-      return NoChange();
-  }
-  UNREACHABLE();
-  return NoChange();
-}
-
-
-template <>
-Reduction ChangeLowering<4>::ChangeBoolToBit(Node* val) {
+Reduction ChangeLowering::ChangeBoolToBit(Node* val) {
   return Replace(
-      graph()->NewNode(machine()->Word32Equal(), val, TrueConstant()));
+      graph()->NewNode(machine()->WordEqual(), val, jsgraph()->TrueConstant()));
 }
 
 
-template <>
-Reduction ChangeLowering<8>::ChangeBoolToBit(Node* val) {
-  return Replace(
-      graph()->NewNode(machine()->Word64Equal(), val, TrueConstant()));
-}
-
+Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* effect,
+                                              Node* control) {
+  if (machine()->is64()) {
+    return Replace(
+        graph()->NewNode(machine()->WordShl(), val, SmiShiftBitsConstant()));
+  }
 
-template <>
-Reduction ChangeLowering<4>::ChangeInt32ToTagged(Node* val, Node* effect,
-                                                 Node* control) {
-  Node* context = NumberConstant(0);
+  Node* context = jsgraph()->SmiConstant(0);
 
   Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
   Node* ovf = graph()->NewNode(common()->Projection(1), add);
@@ -167,15 +94,14 @@ Reduction ChangeLowering<4>::ChangeInt32ToTagged(Node* val, Node* effect,
   DCHECK_EQ(0, fn->nargs);
   CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
       fn->function_id, 0, Operator::kNoProperties);
-  Node* heap_number =
-      graph()->NewNode(common()->Call(desc), CEntryStubConstant(),
-                       ExternalConstant(ExternalReference(fn, isolate())),
-                       Int32Constant(0), context, effect, if_true);
+  Node* heap_number = graph()->NewNode(
+      common()->Call(desc), jsgraph()->CEntryStubConstant(),
+      jsgraph()->ExternalConstant(ExternalReference(fn, isolate())),
+      jsgraph()->ZeroConstant(), context, effect, if_true);
 
   Node* store = graph()->NewNode(
       machine()->Store(kMachFloat64, kNoWriteBarrier), heap_number,
-      Int32Constant(HeapNumber::kValueOffset - kHeapObjectTag), number, effect,
-      heap_number);
+      HeapNumberValueIndexConstant(), number, effect, heap_number);
 
   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
   Node* smi = graph()->NewNode(common()->Projection(0), add);
@@ -187,34 +113,26 @@ Reduction ChangeLowering<4>::ChangeInt32ToTagged(Node* val, Node* effect,
 }
 
 
-template <>
-Reduction ChangeLowering<8>::ChangeInt32ToTagged(Node* val, Node* effect,
-                                                 Node* control) {
-  return Replace(graph()->NewNode(
-      machine()->Word64Shl(), val,
-      Int32Constant(SmiTagging<8>::kSmiShiftSize + kSmiTagSize)));
-}
-
+Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* effect,
+                                                Node* control) {
+  STATIC_ASSERT(kSmiTagMask == 1);
 
-template <>
-Reduction ChangeLowering<4>::ChangeTaggedToFloat64(Node* val, Node* effect,
-                                                   Node* control) {
-  Node* branch = graph()->NewNode(
-      common()->Branch(),
-      graph()->NewNode(machine()->Word32And(), val, Int32Constant(kSmiTagMask)),
-      control);
+  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,
-      Int32Constant(HeapNumber::kValueOffset - kHeapObjectTag), if_true);
+  Node* load = graph()->NewNode(machine()->Load(kMachFloat64), val,
+                                HeapNumberValueIndexConstant(), if_true);
 
   Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+  Node* integer =
+      graph()->NewNode(machine()->WordSar(), val, SmiShiftBitsConstant());
   Node* number = graph()->NewNode(
       machine()->ChangeInt32ToFloat64(),
-      graph()->NewNode(
-          machine()->Word32Sar(), val,
-          Int32Constant(SmiTagging<4>::kSmiShiftSize + kSmiTagSize)));
+      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), load, number, merge);
@@ -223,38 +141,16 @@ Reduction ChangeLowering<4>::ChangeTaggedToFloat64(Node* val, Node* effect,
 }
 
 
-template <>
-Reduction ChangeLowering<8>::ChangeTaggedToFloat64(Node* val, Node* effect,
-                                                   Node* control) {
-  Node* branch = graph()->NewNode(
-      common()->Branch(),
-      graph()->NewNode(machine()->Word64And(), val, Int32Constant(kSmiTagMask)),
-      control);
+Isolate* ChangeLowering::isolate() const { return jsgraph()->isolate(); }
 
-  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-  Node* load = graph()->NewNode(
-      machine()->Load(kMachFloat64), val,
-      Int32Constant(HeapNumber::kValueOffset - kHeapObjectTag), if_true);
 
-  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-  Node* number = graph()->NewNode(
-      machine()->ChangeInt32ToFloat64(),
-      graph()->NewNode(
-          machine()->ConvertInt64ToInt32(),
-          graph()->NewNode(
-              machine()->Word64Sar(), val,
-              Int32Constant(SmiTagging<8>::kSmiShiftSize + kSmiTagSize))));
+Graph* ChangeLowering::graph() const { return jsgraph()->graph(); }
 
-  Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-  Node* phi = graph()->NewNode(common()->Phi(2), load, number, merge);
 
-  return Replace(phi);
+CommonOperatorBuilder* ChangeLowering::common() const {
+  return jsgraph()->common();
 }
 
-
-template class ChangeLowering<4>;
-template class ChangeLowering<8>;
-
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 3e16d80..93ba142 100644 (file)
@@ -5,71 +5,47 @@
 #ifndef V8_COMPILER_CHANGE_LOWERING_H_
 #define V8_COMPILER_CHANGE_LOWERING_H_
 
-#include "include/v8.h"
-#include "src/compiler/common-operator.h"
 #include "src/compiler/graph-reducer.h"
-#include "src/compiler/machine-operator.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
 // Forward declarations.
-class CommonNodeCache;
+class CommonOperatorBuilder;
+class JSGraph;
 class Linkage;
+class MachineOperatorBuilder;
 
-class ChangeLoweringBase : public Reducer {
+class ChangeLowering V8_FINAL : public Reducer {
  public:
-  ChangeLoweringBase(Graph* graph, Linkage* linkage, CommonNodeCache* cache);
-  virtual ~ChangeLoweringBase();
+  ChangeLowering(JSGraph* jsgraph, Linkage* linkage,
+                 MachineOperatorBuilder* machine)
+      : jsgraph_(jsgraph), linkage_(linkage), machine_(machine) {}
+  virtual ~ChangeLowering();
+
+  virtual Reduction Reduce(Node* node) V8_OVERRIDE;
 
  protected:
-  Node* ExternalConstant(ExternalReference reference);
-  Node* HeapConstant(PrintableUnique<HeapObject> value);
-  Node* ImmovableHeapConstant(Handle<HeapObject> value);
-  Node* Int32Constant(int32_t value);
-  Node* NumberConstant(double value);
-  Node* CEntryStubConstant();
-  Node* TrueConstant();
-  Node* FalseConstant();
+  Node* HeapNumberValueIndexConstant();
+  Node* SmiShiftBitsConstant();
 
   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);
 
-  Graph* graph() const { return graph_; }
-  Isolate* isolate() const { return isolate_; }
+  Graph* graph() const;
+  Isolate* isolate() const;
+  JSGraph* jsgraph() const { return jsgraph_; }
   Linkage* linkage() const { return linkage_; }
-  CommonNodeCache* cache() const { return cache_; }
-  CommonOperatorBuilder* common() { return &common_; }
-  MachineOperatorBuilder* machine() { return &machine_; }
+  CommonOperatorBuilder* common() const;
+  MachineOperatorBuilder* machine() const { return machine_; }
 
  private:
-  Graph* graph_;
-  Isolate* isolate_;
+  JSGraph* jsgraph_;
   Linkage* linkage_;
-  CommonNodeCache* cache_;
-  CommonOperatorBuilder common_;
-  MachineOperatorBuilder machine_;
-
-  SetOncePointer<Node> c_entry_stub_constant_;
-  SetOncePointer<Node> true_constant_;
-  SetOncePointer<Node> false_constant_;
-};
-
-
-template <size_t kPointerSize = kApiPointerSize>
-class ChangeLowering V8_FINAL : public ChangeLoweringBase {
- public:
-  ChangeLowering(Graph* graph, Linkage* linkage);
-  ChangeLowering(Graph* graph, Linkage* linkage, CommonNodeCache* cache)
-      : ChangeLoweringBase(graph, linkage, cache) {}
-  virtual ~ChangeLowering() {}
-
-  virtual Reduction Reduce(Node* node) V8_OVERRIDE;
-
- private:
-  Reduction ChangeBoolToBit(Node* val);
-  Reduction ChangeInt32ToTagged(Node* val, Node* effect, Node* control);
-  Reduction ChangeTaggedToFloat64(Node* val, Node* effect, Node* control);
+  MachineOperatorBuilder* machine_;
 };
 
 }  // namespace compiler
index 2cebbc7..b229306 100644 (file)
@@ -24,6 +24,15 @@ Node* JSGraph::NewNode(Operator* op) {
 }
 
 
+Node* JSGraph::CEntryStubConstant() {
+  if (!c_entry_stub_constant_.is_set()) {
+    c_entry_stub_constant_.set(
+        ImmovableHeapConstant(CEntryStub(isolate(), 1).GetCode()));
+  }
+  return c_entry_stub_constant_.get();
+}
+
+
 Node* JSGraph::UndefinedConstant() {
   if (!undefined_constant_.is_set()) {
     undefined_constant_.set(
index 59a6b84..b016a82 100644 (file)
@@ -30,6 +30,7 @@ class JSGraph : public ZoneObject {
         cache_(zone()) {}
 
   // Canonicalized global constants.
+  Node* CEntryStubConstant();
   Node* UndefinedConstant();
   Node* TheHoleConstant();
   Node* TrueConstant();
@@ -76,6 +77,7 @@ class JSGraph : public ZoneObject {
   CommonOperatorBuilder* common() { return common_; }
   Graph* graph() { return graph_; }
   Zone* zone() { return graph()->zone(); }
+  Isolate* isolate() { return zone()->isolate(); }
 
  private:
   Graph* graph_;
@@ -83,6 +85,7 @@ class JSGraph : public ZoneObject {
   JSOperatorBuilder javascript_;
   Typer* typer_;
 
+  SetOncePointer<Node> c_entry_stub_constant_;
   SetOncePointer<Node> undefined_constant_;
   SetOncePointer<Node> the_hole_constant_;
   SetOncePointer<Node> true_constant_;
@@ -98,7 +101,7 @@ class JSGraph : public ZoneObject {
   Node* NumberConstant(double value);
   Node* NewNode(Operator* op);
 
-  Factory* factory() { return zone()->isolate()->factory(); }
+  Factory* factory() { return isolate()->factory(); }
 };
 }  // namespace compiler
 }  // namespace internal
index 0dd664e..fabd1b2 100644 (file)
@@ -3,4 +3,5 @@ include_rules = [
   "+testing/gtest",
   "+testing/gtest-support.h",
   "+testing/gmock",
+  "+testing/gmock-support.h",
 ]
index b2359d5..45e001b 100644 (file)
@@ -3,29 +3,33 @@
 // found in the LICENSE file.
 
 #include "src/compiler/change-lowering.h"
-#include "src/compiler/common-operator.h"
-#include "src/compiler/graph.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/simplified-operator.h"
-#include "src/factory.h"
-#include "test/compiler-unittests/compiler-unittests.h"
-#include "test/compiler-unittests/node-matchers.h"
+#include "src/compiler/typer.h"
+#include "test/compiler-unittests/graph-unittest.h"
+#include "testing/gmock-support.h"
 
 using testing::_;
+using testing::AllOf;
+using testing::Capture;
+using testing::CaptureEq;
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
 template <typename T>
-class ChangeLoweringTest : public CompilerTest {
+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);
 
-  explicit ChangeLoweringTest(int num_parameters = 1)
-      : graph_(zone()), common_(zone()), simplified_(zone()) {
-    graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
-  }
+  ChangeLoweringTest() : simplified_(zone()) {}
   virtual ~ChangeLoweringTest() {}
 
  protected:
@@ -34,15 +38,15 @@ class ChangeLoweringTest : public CompilerTest {
   }
 
   Reduction Reduce(Node* node) {
+    Typer typer(zone());
+    JSGraph jsgraph(graph(), common(), &typer);
     CompilationInfo info(isolate(), zone());
     Linkage linkage(&info);
-    ChangeLowering<kPointerSize> reducer(graph(), &linkage);
+    MachineOperatorBuilder machine(zone(), kWordRepresentation);
+    ChangeLowering reducer(&jsgraph, &linkage, &machine);
     return reducer.Reduce(node);
   }
 
-  Graph* graph() { return &graph_; }
-  Factory* factory() const { return isolate()->factory(); }
-  CommonOperatorBuilder* common() { return &common_; }
   SimplifiedOperatorBuilder* simplified() { return &simplified_; }
 
   PrintableUnique<HeapObject> true_unique() {
@@ -55,8 +59,6 @@ class ChangeLoweringTest : public CompilerTest {
   }
 
  private:
-  Graph graph_;
-  CommonOperatorBuilder common_;
   SimplifiedOperatorBuilder simplified_;
 };
 
@@ -73,21 +75,13 @@ TARGET_TYPED_TEST(ChangeLoweringTest, ChangeBitToBool) {
   ASSERT_TRUE(reduction.Changed());
 
   Node* phi = reduction.replacement();
-  EXPECT_THAT(phi, IsPhi(IsHeapConstant(this->true_unique()),
-                         IsHeapConstant(this->false_unique()), _));
-
-  Node* merge = NodeProperties::GetControlInput(phi);
-  ASSERT_EQ(IrOpcode::kMerge, merge->opcode());
-
-  Node* if_true = NodeProperties::GetControlInput(merge, 0);
-  ASSERT_EQ(IrOpcode::kIfTrue, if_true->opcode());
-
-  Node* if_false = NodeProperties::GetControlInput(merge, 1);
-  ASSERT_EQ(IrOpcode::kIfFalse, if_false->opcode());
-
-  Node* branch = NodeProperties::GetControlInput(if_true);
-  EXPECT_EQ(branch, NodeProperties::GetControlInput(if_false));
-  EXPECT_THAT(branch, IsBranch(val, this->graph()->start()));
+  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)))));
 }
 
 
@@ -134,7 +128,7 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
   Node* merge = NodeProperties::GetControlInput(phi);
   ASSERT_EQ(IrOpcode::kMerge, merge->opcode());
 
-  const int32_t kValueOffset = HeapNumber::kValueOffset - kHeapObjectTag;
+  const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
   EXPECT_THAT(NodeProperties::GetControlInput(merge, 0),
               IsStore(kMachFloat64, kNoWriteBarrier, heap_number,
                       IsInt32Constant(kValueOffset),
@@ -155,6 +149,9 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
 
 
 TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
   Node* val = Parameter(0);
   Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
   Reduction reduction = Reduce(node);
@@ -162,29 +159,19 @@ TARGET_TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
 
   const int32_t kShiftAmount =
       kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
-  const int32_t kValueOffset = HeapNumber::kValueOffset - kHeapObjectTag;
+  const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
   Node* phi = reduction.replacement();
-  ASSERT_THAT(phi,
-              IsPhi(IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset), _),
-                    IsChangeInt32ToFloat64(
-                        IsWord32Sar(val, IsInt32Constant(kShiftAmount))),
-                    _));
-
-  Node* merge = NodeProperties::GetControlInput(phi);
-  ASSERT_EQ(IrOpcode::kMerge, merge->opcode());
-
-  Node* if_true = NodeProperties::GetControlInput(merge, 0);
-  ASSERT_EQ(IrOpcode::kIfTrue, if_true->opcode());
-
-  Node* if_false = NodeProperties::GetControlInput(merge, 1);
-  ASSERT_EQ(IrOpcode::kIfFalse, if_false->opcode());
-
-  Node* branch = NodeProperties::GetControlInput(if_true);
-  EXPECT_EQ(branch, NodeProperties::GetControlInput(if_false));
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-  EXPECT_THAT(branch, IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
-                               graph()->start()));
+  Capture<Node*> branch;
+  EXPECT_THAT(
+      phi,
+      IsPhi(IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset), _),
+            IsChangeInt32ToFloat64(
+                IsWord32Sar(val, IsInt32Constant(kShiftAmount))),
+            IsMerge(IsIfTrue(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord32And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))),
+                    IsIfFalse(CaptureEq(&branch)))));
 }
 
 
@@ -219,6 +206,9 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
 
 
 TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
+  STATIC_ASSERT(kSmiTag == 0);
+  STATIC_ASSERT(kSmiTagSize == 1);
+
   Node* val = Parameter(0);
   Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
   Reduction reduction = Reduce(node);
@@ -226,29 +216,19 @@ TARGET_TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
 
   const int32_t kShiftAmount =
       kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
-  const int32_t kValueOffset = HeapNumber::kValueOffset - kHeapObjectTag;
+  const int32_t kValueOffset = kHeapNumberValueOffset - kHeapObjectTag;
   Node* phi = reduction.replacement();
-  ASSERT_THAT(phi,
-              IsPhi(IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset), _),
-                    IsChangeInt32ToFloat64(IsConvertInt64ToInt32(
-                        IsWord64Sar(val, IsInt32Constant(kShiftAmount)))),
-                    _));
-
-  Node* merge = NodeProperties::GetControlInput(phi);
-  ASSERT_EQ(IrOpcode::kMerge, merge->opcode());
-
-  Node* if_true = NodeProperties::GetControlInput(merge, 0);
-  ASSERT_EQ(IrOpcode::kIfTrue, if_true->opcode());
-
-  Node* if_false = NodeProperties::GetControlInput(merge, 1);
-  ASSERT_EQ(IrOpcode::kIfFalse, if_false->opcode());
-
-  Node* branch = NodeProperties::GetControlInput(if_true);
-  EXPECT_EQ(branch, NodeProperties::GetControlInput(if_false));
-  STATIC_ASSERT(kSmiTag == 0);
-  STATIC_ASSERT(kSmiTagSize == 1);
-  EXPECT_THAT(branch, IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
-                               graph()->start()));
+  Capture<Node*> branch;
+  EXPECT_THAT(
+      phi,
+      IsPhi(IsLoad(kMachFloat64, val, IsInt32Constant(kValueOffset), _),
+            IsChangeInt32ToFloat64(IsConvertInt64ToInt32(
+                IsWord64Sar(val, IsInt32Constant(kShiftAmount)))),
+            IsMerge(IsIfTrue(AllOf(
+                        CaptureEq(&branch),
+                        IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
+                                 graph()->start()))),
+                    IsIfFalse(CaptureEq(&branch)))));
 }
 
 }  // namespace compiler
diff --git a/test/compiler-unittests/common-operator-unittest.cc b/test/compiler-unittests/common-operator-unittest.cc
new file mode 100644 (file)
index 0000000..fa5af1e
--- /dev/null
@@ -0,0 +1,20 @@
+// 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/common-operator-unittest.h"
+
+#include "src/compiler/operator-properties-inl.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+CommonOperatorTest::CommonOperatorTest() : common_(zone()) {}
+
+
+CommonOperatorTest::~CommonOperatorTest() {}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/compiler-unittests/common-operator-unittest.h b/test/compiler-unittests/common-operator-unittest.h
new file mode 100644 (file)
index 0000000..9cfeb87
--- /dev/null
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef V8_COMPILER_UNITTESTS_COMMON_OPERATOR_UNITTEST_H_
+#define V8_COMPILER_UNITTESTS_COMMON_OPERATOR_UNITTEST_H_
+
+#include "src/compiler/common-operator.h"
+#include "test/compiler-unittests/compiler-unittests.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+class CommonOperatorTest : public CompilerTest {
+ public:
+  CommonOperatorTest();
+  virtual ~CommonOperatorTest();
+
+ protected:
+  CommonOperatorBuilder* common() { return &common_; }
+
+ private:
+  CommonOperatorBuilder common_;
+};
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
+
+#endif  // V8_COMPILER_UNITTESTS_COMMON_OPERATOR_UNITTEST_H_
index 2ce4c93..86d1240 100644 (file)
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "include/libplatform/libplatform.h"
+#include "src/isolate-inl.h"
 #include "test/compiler-unittests/compiler-unittests.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -27,6 +28,9 @@ CompilerTest::CompilerTest()
 CompilerTest::~CompilerTest() {}
 
 
+Factory* CompilerTest::factory() const { return isolate()->factory(); }
+
+
 // static
 void CompilerTest::SetUpTestCase() {
   Test::SetUpTestCase();
index f2c4fac..13bc0c7 100644 (file)
       ],
       'sources': [  ### gcmole(all) ###
         'change-lowering-unittest.cc',
+        'common-operator-unittest.cc',
+        'common-operator-unittest.h',
         'compiler-unittests.cc',
+        'graph-unittest.cc',
+        'graph-unittest.h',
         'instruction-selector-unittest.cc',
         'machine-operator-reducer-unittest.cc',
-        'node-matchers.cc',
-        'node-matchers.h',
       ],
       'conditions': [
         ['v8_target_arch=="arm"', {
index f0955a6..fef34cf 100644 (file)
@@ -48,6 +48,7 @@ class CompilerTest : public ::testing::Test {
   CompilerTest();
   virtual ~CompilerTest();
 
+  Factory* factory() const;
   Isolate* isolate() const { return reinterpret_cast<Isolate*>(isolate_); }
   Zone* zone() { return &zone_; }
 
similarity index 82%
rename from test/compiler-unittests/node-matchers.cc
rename to test/compiler-unittests/graph-unittest.cc
index afff34a..6c946de 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "test/compiler-unittests/node-matchers.h"
+#include "test/compiler-unittests/graph-unittest.h"
 
 #include <ostream>  // NOLINT(readability/streams)
 
@@ -25,6 +25,14 @@ inline std::ostream& operator<<(std::ostream& os,
 
 namespace compiler {
 
+GraphTest::GraphTest(int num_parameters) : graph_(zone()) {
+  graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
+}
+
+
+GraphTest::~GraphTest() {}
+
+
 namespace {
 
 template <typename T>
@@ -101,6 +109,86 @@ class IsBranchMatcher V8_FINAL : public NodeMatcher {
 };
 
 
+class IsMergeMatcher V8_FINAL : public NodeMatcher {
+ public:
+  IsMergeMatcher(const Matcher<Node*>& control0_matcher,
+                 const Matcher<Node*>& control1_matcher)
+      : NodeMatcher(IrOpcode::kMerge),
+        control0_matcher_(control0_matcher),
+        control1_matcher_(control1_matcher) {}
+
+  virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose control0 (";
+    control0_matcher_.DescribeTo(os);
+    *os << ") and control1 (";
+    control1_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
+      V8_OVERRIDE {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 0),
+                                 "control0", control0_matcher_, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node, 1),
+                                 "control1", control1_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> control0_matcher_;
+  const Matcher<Node*> control1_matcher_;
+};
+
+
+class IsIfTrueMatcher V8_FINAL : public NodeMatcher {
+ public:
+  explicit IsIfTrueMatcher(const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kIfTrue), control_matcher_(control_matcher) {}
+
+  virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
+      V8_OVERRIDE {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> control_matcher_;
+};
+
+
+class IsIfFalseMatcher V8_FINAL : public NodeMatcher {
+ public:
+  explicit IsIfFalseMatcher(const Matcher<Node*>& control_matcher)
+      : NodeMatcher(IrOpcode::kIfFalse), control_matcher_(control_matcher) {}
+
+  virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
+    NodeMatcher::DescribeTo(os);
+    *os << " whose control (";
+    control_matcher_.DescribeTo(os);
+    *os << ")";
+  }
+
+  virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
+      V8_OVERRIDE {
+    return (NodeMatcher::MatchAndExplain(node, listener) &&
+            PrintMatchAndExplain(NodeProperties::GetControlInput(node),
+                                 "control", control_matcher_, listener));
+  }
+
+ private:
+  const Matcher<Node*> control_matcher_;
+};
+
+
 template <typename T>
 class IsConstantMatcher V8_FINAL : public NodeMatcher {
  public:
@@ -366,7 +454,6 @@ class IsUnopMatcher V8_FINAL : public NodeMatcher {
  private:
   const Matcher<Node*> input_matcher_;
 };
-
 }
 
 
@@ -376,6 +463,22 @@ Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
 }
 
 
+Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
+                       const Matcher<Node*>& control1_matcher) {
+  return MakeMatcher(new IsMergeMatcher(control0_matcher, control1_matcher));
+}
+
+
+Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsIfTrueMatcher(control_matcher));
+}
+
+
+Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher) {
+  return MakeMatcher(new IsIfFalseMatcher(control_matcher));
+}
+
+
 Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) {
   return MakeMatcher(
       new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher));
similarity index 80%
rename from test/compiler-unittests/node-matchers.h
rename to test/compiler-unittests/graph-unittest.h
index f51e3af..a411738 100644 (file)
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef V8_COMPILER_UNITTESTS_NODE_MATCHERS_H_
-#define V8_COMPILER_UNITTESTS_NODE_MATCHERS_H_
+#ifndef V8_COMPILER_UNITTESTS_GRAPH_UNITTEST_H_
+#define V8_COMPILER_UNITTESTS_GRAPH_UNITTEST_H_
 
+#include "src/compiler/graph.h"
 #include "src/compiler/machine-operator.h"
+#include "test/compiler-unittests/common-operator-unittest.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace v8 {
@@ -18,13 +20,27 @@ class PrintableUnique;
 
 namespace compiler {
 
-// Forward declarations.
-class Node;
+class GraphTest : public CommonOperatorTest {
+ public:
+  explicit GraphTest(int parameters = 1);
+  virtual ~GraphTest();
+
+ protected:
+  Graph* graph() { return &graph_; }
+
+ private:
+  Graph graph_;
+};
+
 
-using testing::Matcher;
+using ::testing::Matcher;
 
 Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
                         const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
+                       const Matcher<Node*>& control1_matcher);
+Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
+Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
 Matcher<Node*> IsHeapConstant(
     const Matcher<PrintableUnique<HeapObject> >& value_matcher);
 Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
@@ -70,4 +86,4 @@ Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
 }  //  namespace internal
 }  //  namespace v8
 
-#endif  // V8_COMPILER_UNITTESTS_NODE_MATCHERS_H_
+#endif  // V8_COMPILER_UNITTESTS_GRAPH_UNITTEST_H_
index 0edab12..75c8562 100644 (file)
@@ -3,22 +3,17 @@
 // found in the LICENSE file.
 
 #include "src/base/bits.h"
-#include "src/compiler/common-operator.h"
-#include "src/compiler/graph.h"
 #include "src/compiler/machine-operator-reducer.h"
-#include "test/compiler-unittests/compiler-unittests.h"
-#include "test/compiler-unittests/node-matchers.h"
+#include "test/compiler-unittests/graph-unittest.h"
 
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-class MachineOperatorReducerTest : public CompilerTest {
+class MachineOperatorReducerTest : public GraphTest {
  public:
   explicit MachineOperatorReducerTest(int num_parameters = 2)
-      : graph_(zone()), common_(zone()), machine_(zone()) {
-    graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
-  }
+      : GraphTest(num_parameters), machine_(zone()) {}
   virtual ~MachineOperatorReducerTest() {}
 
  protected:
@@ -34,13 +29,9 @@ class MachineOperatorReducerTest : public CompilerTest {
     return reducer.Reduce(node);
   }
 
-  Graph* graph() { return &graph_; }
-  CommonOperatorBuilder* common() { return &common_; }
   MachineOperatorBuilder* machine() { return &machine_; }
 
  private:
-  Graph graph_;
-  CommonOperatorBuilder common_;
   MachineOperatorBuilder machine_;
 };
 
diff --git a/testing/gmock-support.h b/testing/gmock-support.h
new file mode 100644 (file)
index 0000000..44348b6
--- /dev/null
@@ -0,0 +1,72 @@
+// 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.
+
+#ifndef V8_TESTING_GMOCK_SUPPORT_H_
+#define V8_TESTING_GMOCK_SUPPORT_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace testing {
+
+template <typename T>
+class Capture {
+ public:
+  Capture() : value_(), has_value_(false) {}
+
+  const T& value() const { return value_; }
+  bool has_value() const { return has_value_; }
+
+  void SetValue(const T& value) {
+    DCHECK(!has_value());
+    value_ = value;
+    has_value_ = true;
+  }
+
+ private:
+  T value_;
+  bool has_value_;
+};
+
+
+namespace internal {
+
+template <typename T>
+class CaptureEqMatcher : public MatcherInterface<T> {
+ public:
+  explicit CaptureEqMatcher(Capture<T>* capture) : capture_(capture) {}
+
+  virtual void DescribeTo(std::ostream* os) const {
+    *os << "captured by " << static_cast<const void*>(capture_);
+    if (capture_->has_value()) *os << " which has value " << capture_->value();
+  }
+
+  virtual bool MatchAndExplain(T value, MatchResultListener* listener) const {
+    if (!capture_->has_value()) {
+      capture_->SetValue(value);
+      return true;
+    }
+    if (value != capture_->value()) {
+      *listener << "which is not equal to " << capture_->value();
+      return false;
+    }
+    return true;
+  }
+
+ private:
+  Capture<T>* capture_;
+};
+
+}  // namespace internal
+
+
+// CaptureEq(capture) captures the value passed in during matching as long as it
+// is unset, and once set, compares the value for equality with the argument.
+template <typename T>
+Matcher<T> CaptureEq(Capture<T>* capture) {
+  return MakeMatcher(new internal::CaptureEqMatcher<T>(capture));
+}
+
+}  // namespace testing
+
+#endif  // V8_TESTING_GMOCK_SUPPORT_H_
index a36584d..f423bd0 100644 (file)
@@ -30,7 +30,7 @@
         'gmock/src/gmock-matchers.cc',
         'gmock/src/gmock-spec-builders.cc',
         'gmock/src/gmock.cc',
-        'gmock_mutant.h',  # gMock helpers
+        'gmock-support.h',  # gMock helpers
       ],
       'sources!': [
         'gmock/src/gmock-all.cc',  # Not needed by our build.