#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 =
}
-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);
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);
}
-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);
}
-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
#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
}
+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(
cache_(zone()) {}
// Canonicalized global constants.
+ Node* CEntryStubConstant();
Node* UndefinedConstant();
Node* TheHoleConstant();
Node* TrueConstant();
CommonOperatorBuilder* common() { return common_; }
Graph* graph() { return graph_; }
Zone* zone() { return graph()->zone(); }
+ Isolate* isolate() { return zone()->isolate(); }
private:
Graph* graph_;
JSOperatorBuilder javascript_;
Typer* typer_;
+ SetOncePointer<Node> c_entry_stub_constant_;
SetOncePointer<Node> undefined_constant_;
SetOncePointer<Node> the_hole_constant_;
SetOncePointer<Node> true_constant_;
Node* NumberConstant(double value);
Node* NewNode(Operator* op);
- Factory* factory() { return zone()->isolate()->factory(); }
+ Factory* factory() { return isolate()->factory(); }
};
} // namespace compiler
} // namespace internal
"+testing/gtest",
"+testing/gtest-support.h",
"+testing/gmock",
+ "+testing/gmock-support.h",
]
// 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:
}
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() {
}
private:
- Graph graph_;
- CommonOperatorBuilder common_;
SimplifiedOperatorBuilder simplified_;
};
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)))));
}
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),
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);
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)))));
}
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);
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
--- /dev/null
+// 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
--- /dev/null
+// 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_
// 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"
CompilerTest::~CompilerTest() {}
+Factory* CompilerTest::factory() const { return isolate()->factory(); }
+
+
// static
void CompilerTest::SetUpTestCase() {
Test::SetUpTestCase();
],
'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"', {
CompilerTest();
virtual ~CompilerTest();
+ Factory* factory() const;
Isolate* isolate() const { return reinterpret_cast<Isolate*>(isolate_); }
Zone* zone() { return &zone_; }
// 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)
namespace compiler {
+GraphTest::GraphTest(int num_parameters) : graph_(zone()) {
+ graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
+}
+
+
+GraphTest::~GraphTest() {}
+
+
namespace {
template <typename T>
};
+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:
private:
const Matcher<Node*> input_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));
// 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 {
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);
} // namespace internal
} // namespace v8
-#endif // V8_COMPILER_UNITTESTS_NODE_MATCHERS_H_
+#endif // V8_COMPILER_UNITTESTS_GRAPH_UNITTEST_H_
// 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:
return reducer.Reduce(node);
}
- Graph* graph() { return &graph_; }
- CommonOperatorBuilder* common() { return &common_; }
MachineOperatorBuilder* machine() { return &machine_; }
private:
- Graph graph_;
- CommonOperatorBuilder common_;
MachineOperatorBuilder machine_;
};
--- /dev/null
+// 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_
'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.