From d32fa64d337d782b894debcfedfd8b6189652be5 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Mon, 18 Aug 2014 06:54:07 +0000 Subject: [PATCH] Refactor ChangeLowering class to avoid template specialization. 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 --- src/compiler/change-lowering.cc | 226 ++++++--------------- src/compiler/change-lowering.h | 68 ++----- src/compiler/js-graph.cc | 9 + src/compiler/js-graph.h | 5 +- test/compiler-unittests/DEPS | 1 + .../compiler-unittests/change-lowering-unittest.cc | 132 +++++------- .../compiler-unittests/common-operator-unittest.cc | 20 ++ test/compiler-unittests/common-operator-unittest.h | 31 +++ test/compiler-unittests/compiler-unittests.cc | 4 + test/compiler-unittests/compiler-unittests.gyp | 6 +- test/compiler-unittests/compiler-unittests.h | 1 + .../{node-matchers.cc => graph-unittest.cc} | 107 +++++++++- .../{node-matchers.h => graph-unittest.h} | 28 ++- .../machine-operator-reducer-unittest.cc | 15 +- testing/gmock-support.h | 72 +++++++ testing/gmock.gyp | 2 +- 16 files changed, 416 insertions(+), 311 deletions(-) create mode 100644 test/compiler-unittests/common-operator-unittest.cc create mode 100644 test/compiler-unittests/common-operator-unittest.h rename test/compiler-unittests/{node-matchers.cc => graph-unittest.cc} (82%) rename test/compiler-unittests/{node-matchers.h => graph-unittest.h} (80%) create mode 100644 testing/gmock-support.h diff --git a/src/compiler/change-lowering.cc b/src/compiler/change-lowering.cc index e80adec..b07e548 100644 --- a/src/compiler/change-lowering.cc +++ b/src/compiler/change-lowering.cc @@ -4,100 +4,58 @@ #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 value) { - // TODO(bmeurer): Use common node cache. - return graph()->NewNode(common()->HeapConstant(value)); -} - - -Node* ChangeLoweringBase::ImmovableHeapConstant(Handle value) { - return HeapConstant( - PrintableUnique::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 -ChangeLowering::ChangeLowering(Graph* graph, Linkage* linkage) - : ChangeLoweringBase(graph, linkage, - new (graph->zone()) CommonNodeCache(graph->zone())) {} - - -template -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(); - } - 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 diff --git a/src/compiler/change-lowering.h b/src/compiler/change-lowering.h index 3e16d80..93ba142 100644 --- a/src/compiler/change-lowering.h +++ b/src/compiler/change-lowering.h @@ -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 value); - Node* ImmovableHeapConstant(Handle 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 c_entry_stub_constant_; - SetOncePointer true_constant_; - SetOncePointer false_constant_; -}; - - -template -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 diff --git a/src/compiler/js-graph.cc b/src/compiler/js-graph.cc index 2cebbc7..b229306 100644 --- a/src/compiler/js-graph.cc +++ b/src/compiler/js-graph.cc @@ -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( diff --git a/src/compiler/js-graph.h b/src/compiler/js-graph.h index 59a6b84..b016a82 100644 --- a/src/compiler/js-graph.h +++ b/src/compiler/js-graph.h @@ -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 c_entry_stub_constant_; SetOncePointer undefined_constant_; SetOncePointer the_hole_constant_; SetOncePointer 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 diff --git a/test/compiler-unittests/DEPS b/test/compiler-unittests/DEPS index 0dd664e..fabd1b2 100644 --- a/test/compiler-unittests/DEPS +++ b/test/compiler-unittests/DEPS @@ -3,4 +3,5 @@ include_rules = [ "+testing/gtest", "+testing/gtest-support.h", "+testing/gmock", + "+testing/gmock-support.h", ] diff --git a/test/compiler-unittests/change-lowering-unittest.cc b/test/compiler-unittests/change-lowering-unittest.cc index b2359d5..45e001b 100644 --- a/test/compiler-unittests/change-lowering-unittest.cc +++ b/test/compiler-unittests/change-lowering-unittest.cc @@ -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 -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( + (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 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 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 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::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 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::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 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 index 0000000..fa5af1e --- /dev/null +++ b/test/compiler-unittests/common-operator-unittest.cc @@ -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 index 0000000..9cfeb87 --- /dev/null +++ b/test/compiler-unittests/common-operator-unittest.h @@ -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_ diff --git a/test/compiler-unittests/compiler-unittests.cc b/test/compiler-unittests/compiler-unittests.cc index 2ce4c93..86d1240 100644 --- a/test/compiler-unittests/compiler-unittests.cc +++ b/test/compiler-unittests/compiler-unittests.cc @@ -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(); diff --git a/test/compiler-unittests/compiler-unittests.gyp b/test/compiler-unittests/compiler-unittests.gyp index f2c4fac..13bc0c7 100644 --- a/test/compiler-unittests/compiler-unittests.gyp +++ b/test/compiler-unittests/compiler-unittests.gyp @@ -21,11 +21,13 @@ ], '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"', { diff --git a/test/compiler-unittests/compiler-unittests.h b/test/compiler-unittests/compiler-unittests.h index f0955a6..fef34cf 100644 --- a/test/compiler-unittests/compiler-unittests.h +++ b/test/compiler-unittests/compiler-unittests.h @@ -48,6 +48,7 @@ class CompilerTest : public ::testing::Test { CompilerTest(); virtual ~CompilerTest(); + Factory* factory() const; Isolate* isolate() const { return reinterpret_cast(isolate_); } Zone* zone() { return &zone_; } diff --git a/test/compiler-unittests/node-matchers.cc b/test/compiler-unittests/graph-unittest.cc similarity index 82% rename from test/compiler-unittests/node-matchers.cc rename to test/compiler-unittests/graph-unittest.cc index afff34a..6c946de 100644 --- a/test/compiler-unittests/node-matchers.cc +++ b/test/compiler-unittests/graph-unittest.cc @@ -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 // 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 @@ -101,6 +109,86 @@ class IsBranchMatcher V8_FINAL : public NodeMatcher { }; +class IsMergeMatcher V8_FINAL : public NodeMatcher { + public: + IsMergeMatcher(const Matcher& control0_matcher, + const Matcher& 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 control0_matcher_; + const Matcher control1_matcher_; +}; + + +class IsIfTrueMatcher V8_FINAL : public NodeMatcher { + public: + explicit IsIfTrueMatcher(const Matcher& 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 control_matcher_; +}; + + +class IsIfFalseMatcher V8_FINAL : public NodeMatcher { + public: + explicit IsIfFalseMatcher(const Matcher& 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 control_matcher_; +}; + + template class IsConstantMatcher V8_FINAL : public NodeMatcher { public: @@ -366,7 +454,6 @@ class IsUnopMatcher V8_FINAL : public NodeMatcher { private: const Matcher input_matcher_; }; - } @@ -376,6 +463,22 @@ Matcher IsBranch(const Matcher& value_matcher, } +Matcher IsMerge(const Matcher& control0_matcher, + const Matcher& control1_matcher) { + return MakeMatcher(new IsMergeMatcher(control0_matcher, control1_matcher)); +} + + +Matcher IsIfTrue(const Matcher& control_matcher) { + return MakeMatcher(new IsIfTrueMatcher(control_matcher)); +} + + +Matcher IsIfFalse(const Matcher& control_matcher) { + return MakeMatcher(new IsIfFalseMatcher(control_matcher)); +} + + Matcher IsInt32Constant(const Matcher& value_matcher) { return MakeMatcher( new IsConstantMatcher(IrOpcode::kInt32Constant, value_matcher)); diff --git a/test/compiler-unittests/node-matchers.h b/test/compiler-unittests/graph-unittest.h similarity index 80% rename from test/compiler-unittests/node-matchers.h rename to test/compiler-unittests/graph-unittest.h index f51e3af..a411738 100644 --- a/test/compiler-unittests/node-matchers.h +++ b/test/compiler-unittests/graph-unittest.h @@ -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 IsBranch(const Matcher& value_matcher, const Matcher& control_matcher); +Matcher IsMerge(const Matcher& control0_matcher, + const Matcher& control1_matcher); +Matcher IsIfTrue(const Matcher& control_matcher); +Matcher IsIfFalse(const Matcher& control_matcher); Matcher IsHeapConstant( const Matcher >& value_matcher); Matcher IsInt32Constant(const Matcher& value_matcher); @@ -70,4 +86,4 @@ Matcher IsChangeInt32ToFloat64(const Matcher& input_matcher); } // namespace internal } // namespace v8 -#endif // V8_COMPILER_UNITTESTS_NODE_MATCHERS_H_ +#endif // V8_COMPILER_UNITTESTS_GRAPH_UNITTEST_H_ diff --git a/test/compiler-unittests/machine-operator-reducer-unittest.cc b/test/compiler-unittests/machine-operator-reducer-unittest.cc index 0edab12..75c8562 100644 --- a/test/compiler-unittests/machine-operator-reducer-unittest.cc +++ b/test/compiler-unittests/machine-operator-reducer-unittest.cc @@ -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 index 0000000..44348b6 --- /dev/null +++ b/testing/gmock-support.h @@ -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 +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 +class CaptureEqMatcher : public MatcherInterface { + public: + explicit CaptureEqMatcher(Capture* capture) : capture_(capture) {} + + virtual void DescribeTo(std::ostream* os) const { + *os << "captured by " << static_cast(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* 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 +Matcher CaptureEq(Capture* capture) { + return MakeMatcher(new internal::CaptureEqMatcher(capture)); +} + +} // namespace testing + +#endif // V8_TESTING_GMOCK_SUPPORT_H_ diff --git a/testing/gmock.gyp b/testing/gmock.gyp index a36584d..f423bd0 100644 --- a/testing/gmock.gyp +++ b/testing/gmock.gyp @@ -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. -- 2.7.4