Commit d32fa64d authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

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
parent e5a24048
......@@ -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<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) {
Reduction ChangeLowering::ChangeInt32ToTagged(Node* val, Node* effect,
Node* control) {
if (machine()->is64()) {
return Replace(
graph()->NewNode(machine()->Word64Equal(), val, TrueConstant()));
}
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,
Reduction ChangeLowering::ChangeTaggedToFloat64(Node* val, Node* effect,
Node* control) {
return Replace(graph()->NewNode(
machine()->Word64Shl(), val,
Int32Constant(SmiTagging<8>::kSmiShiftSize + kSmiTagSize)));
}
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
......@@ -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
......
......@@ -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(
......
......@@ -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
......
......@@ -3,4 +3,5 @@ include_rules = [
"+testing/gtest",
"+testing/gtest-support.h",
"+testing/gmock",
"+testing/gmock-support.h",
]
......@@ -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,
Capture<Node*> branch;
EXPECT_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()));
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,
Capture<Node*> branch;
EXPECT_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()));
IsMerge(IsIfTrue(AllOf(
CaptureEq(&branch),
IsBranch(IsWord64And(val, IsInt32Constant(kSmiTagMask)),
graph()->start()))),
IsIfFalse(CaptureEq(&branch)))));
}
} // namespace compiler
......
// 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
// 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_
......@@ -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();
......
......@@ -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"', {
......
......@@ -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_; }
......
......@@ -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));
......
......@@ -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_
......@@ -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_;
};
......
// 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_
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment