Initial import of ChangeLowering.
ChangeLowering is a Reducer to lower simplified change operators to machine subgraphs. This initial version supports ChangeBitToBool, ChangeBoolToBit, ChangeTaggedToFloat64 and ChangeInt32ToTagged. TEST=compiler-unittests/change-lowering-unittest BUG=v8:3489 LOG=n R=jarin@chromium.org Review URL: https://codereview.chromium.org/460593003 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23068 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
81047ea644
commit
51846f64db
260
src/compiler/change-lowering.cc
Normal file
260
src/compiler/change-lowering.cc
Normal file
@ -0,0 +1,260 @@
|
||||
// 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 "src/compiler/change-lowering.h"
|
||||
|
||||
#include "src/compiler/common-node-cache.h"
|
||||
#include "src/compiler/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()) {}
|
||||
|
||||
|
||||
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()));
|
||||
}
|
||||
return c_entry_stub_constant_.get();
|
||||
}
|
||||
|
||||
|
||||
Node* ChangeLoweringBase::TrueConstant() {
|
||||
if (!true_constant_.is_set()) {
|
||||
true_constant_.set(
|
||||
ImmovableHeapConstant(isolate()->factory()->true_value()));
|
||||
}
|
||||
return true_constant_.get();
|
||||
}
|
||||
|
||||
|
||||
Node* ChangeLoweringBase::FalseConstant() {
|
||||
if (!false_constant_.is_set()) {
|
||||
false_constant_.set(
|
||||
ImmovableHeapConstant(isolate()->factory()->false_value()));
|
||||
}
|
||||
return false_constant_.get();
|
||||
}
|
||||
|
||||
|
||||
Reduction ChangeLoweringBase::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* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Node* false_value = FalseConstant();
|
||||
|
||||
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
||||
Node* phi =
|
||||
graph()->NewNode(common()->Phi(2), true_value, false_value, merge);
|
||||
|
||||
return Replace(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) {
|
||||
return Replace(
|
||||
graph()->NewNode(machine()->Word32Equal(), val, TrueConstant()));
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
Reduction ChangeLowering<8>::ChangeBoolToBit(Node* val) {
|
||||
return Replace(
|
||||
graph()->NewNode(machine()->Word64Equal(), val, TrueConstant()));
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
Reduction ChangeLowering<4>::ChangeInt32ToTagged(Node* val, Node* effect,
|
||||
Node* control) {
|
||||
Node* context = NumberConstant(0);
|
||||
|
||||
Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
|
||||
Node* ovf = graph()->NewNode(common()->Projection(1), add);
|
||||
|
||||
Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
|
||||
|
||||
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* number = graph()->NewNode(machine()->ChangeInt32ToFloat64(), val);
|
||||
|
||||
// TODO(bmeurer): Inline allocation if possible.
|
||||
const Runtime::Function* fn =
|
||||
Runtime::FunctionForId(Runtime::kAllocateHeapNumber);
|
||||
DCHECK_EQ(0, fn->nargs);
|
||||
CallDescriptor* desc = linkage()->GetRuntimeCallDescriptor(
|
||||
fn->function_id, 0, Operator::kNoProperties);
|
||||
Node* heap_number =
|
||||
graph()->NewNode(common()->Call(desc), CEntryStubConstant(),
|
||||
ExternalConstant(ExternalReference(fn, isolate())),
|
||||
Int32Constant(0), context, effect, if_true);
|
||||
|
||||
Node* store = graph()->NewNode(
|
||||
machine()->Store(kMachineFloat64, kNoWriteBarrier), heap_number,
|
||||
Int32Constant(HeapNumber::kValueOffset - kHeapObjectTag), number, effect,
|
||||
heap_number);
|
||||
|
||||
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Node* smi = graph()->NewNode(common()->Projection(0), add);
|
||||
|
||||
Node* merge = graph()->NewNode(common()->Merge(2), store, if_false);
|
||||
Node* phi = graph()->NewNode(common()->Phi(2), heap_number, smi, merge);
|
||||
|
||||
return Replace(phi);
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
Reduction ChangeLowering<8>::ChangeInt32ToTagged(Node* val, Node* effect,
|
||||
Node* control) {
|
||||
return Replace(graph()->NewNode(
|
||||
machine()->Word64Shl(), val,
|
||||
Int32Constant(SmiTagging<8>::kSmiShiftSize + kSmiTagSize)));
|
||||
}
|
||||
|
||||
|
||||
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* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* load = graph()->NewNode(
|
||||
machine()->Load(kMachineFloat64), val,
|
||||
Int32Constant(HeapNumber::kValueOffset - kHeapObjectTag), if_true);
|
||||
|
||||
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Node* number = graph()->NewNode(
|
||||
machine()->ChangeInt32ToFloat64(),
|
||||
graph()->NewNode(
|
||||
machine()->Word32Sar(), val,
|
||||
Int32Constant(SmiTagging<4>::kSmiShiftSize + kSmiTagSize)));
|
||||
|
||||
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
||||
Node* phi = graph()->NewNode(common()->Phi(2), load, number, merge);
|
||||
|
||||
return Replace(phi);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* load = graph()->NewNode(
|
||||
machine()->Load(kMachineFloat64), 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))));
|
||||
|
||||
Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
||||
Node* phi = graph()->NewNode(common()->Phi(2), load, number, merge);
|
||||
|
||||
return Replace(phi);
|
||||
}
|
||||
|
||||
|
||||
template class ChangeLowering<4>;
|
||||
template class ChangeLowering<8>;
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
79
src/compiler/change-lowering.h
Normal file
79
src/compiler/change-lowering.h
Normal file
@ -0,0 +1,79 @@
|
||||
// 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_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 Linkage;
|
||||
|
||||
class ChangeLoweringBase : public Reducer {
|
||||
public:
|
||||
ChangeLoweringBase(Graph* graph, Linkage* linkage, CommonNodeCache* cache);
|
||||
virtual ~ChangeLoweringBase();
|
||||
|
||||
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();
|
||||
|
||||
Reduction ChangeBitToBool(Node* val, Node* control);
|
||||
|
||||
Graph* graph() const { return graph_; }
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
Linkage* linkage() const { return linkage_; }
|
||||
CommonNodeCache* cache() const { return cache_; }
|
||||
CommonOperatorBuilder* common() { return &common_; }
|
||||
MachineOperatorBuilder* machine() { return &machine_; }
|
||||
|
||||
private:
|
||||
Graph* graph_;
|
||||
Isolate* isolate_;
|
||||
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);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_CHANGE_LOWERING_H_
|
@ -5,15 +5,13 @@
|
||||
#ifndef V8_COMPILER_NODE_PROPERTIES_H_
|
||||
#define V8_COMPILER_NODE_PROPERTIES_H_
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/compiler/node.h"
|
||||
#include "src/types.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
class Node;
|
||||
class Operator;
|
||||
|
||||
// A facade that simplifies access to the different kinds of inputs to a node.
|
||||
@ -50,8 +48,9 @@ class NodeProperties {
|
||||
|
||||
static inline bool IsInputRange(Node::Edge edge, int first, int count);
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace v8::internal::compiler
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_NODE_PROPERTIES_H_
|
||||
|
@ -174,7 +174,7 @@ class PrintableUnique : public Unique<T> {
|
||||
return PrintableUnique<T>(zone, reinterpret_cast<Address>(*handle), handle);
|
||||
}
|
||||
|
||||
const char* string() { return string_; }
|
||||
const char* string() const { return string_; }
|
||||
|
||||
private:
|
||||
const char* string_;
|
||||
|
@ -1,5 +1,6 @@
|
||||
include_rules = [
|
||||
"+src",
|
||||
"+testing/gmock",
|
||||
"+testing/gtest",
|
||||
"+testing/gtest-type-names.h",
|
||||
"+testing/gmock",
|
||||
]
|
||||
|
257
test/compiler-unittests/change-lowering-unittest.cc
Normal file
257
test/compiler-unittests/change-lowering-unittest.cc
Normal file
@ -0,0 +1,257 @@
|
||||
// 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 "src/compiler/change-lowering.h"
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/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 "testing/gtest-type-names.h"
|
||||
|
||||
using testing::_;
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
template <typename T>
|
||||
class ChangeLoweringTest : public CompilerTest {
|
||||
public:
|
||||
static const size_t kPointerSize = sizeof(T);
|
||||
|
||||
explicit ChangeLoweringTest(int num_parameters = 1)
|
||||
: graph_(zone()), common_(zone()), simplified_(zone()) {
|
||||
graph()->SetStart(graph()->NewNode(common()->Start(num_parameters)));
|
||||
}
|
||||
virtual ~ChangeLoweringTest() {}
|
||||
|
||||
protected:
|
||||
Node* Parameter(int32_t index = 0) {
|
||||
return graph()->NewNode(common()->Parameter(index), graph()->start());
|
||||
}
|
||||
|
||||
Reduction Reduce(Node* node) {
|
||||
CompilationInfo info(isolate(), zone());
|
||||
Linkage linkage(&info);
|
||||
ChangeLowering<kPointerSize> reducer(graph(), &linkage);
|
||||
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() {
|
||||
return PrintableUnique<HeapObject>::CreateImmovable(
|
||||
zone(), factory()->true_value());
|
||||
}
|
||||
PrintableUnique<HeapObject> false_unique() {
|
||||
return PrintableUnique<HeapObject>::CreateImmovable(
|
||||
zone(), factory()->false_value());
|
||||
}
|
||||
|
||||
private:
|
||||
Graph graph_;
|
||||
CommonOperatorBuilder common_;
|
||||
SimplifiedOperatorBuilder simplified_;
|
||||
};
|
||||
|
||||
|
||||
typedef ::testing::Types<int32_t, int64_t> ChangeLoweringTypes;
|
||||
TYPED_TEST_CASE(ChangeLoweringTest, ChangeLoweringTypes);
|
||||
|
||||
|
||||
TYPED_TEST(ChangeLoweringTest, ChangeBitToBool) {
|
||||
Node* val = this->Parameter(0);
|
||||
Node* node =
|
||||
this->graph()->NewNode(this->simplified()->ChangeBitToBool(), val);
|
||||
Reduction reduction = this->Reduce(node);
|
||||
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()));
|
||||
}
|
||||
|
||||
|
||||
TYPED_TEST(ChangeLoweringTest, StringAdd) {
|
||||
Node* node = this->graph()->NewNode(this->simplified()->StringAdd(),
|
||||
this->Parameter(0), this->Parameter(1));
|
||||
Reduction reduction = this->Reduce(node);
|
||||
EXPECT_FALSE(reduction.Changed());
|
||||
}
|
||||
|
||||
|
||||
class ChangeLowering32Test : public ChangeLoweringTest<int32_t> {
|
||||
public:
|
||||
virtual ~ChangeLowering32Test() {}
|
||||
};
|
||||
|
||||
|
||||
TEST_F(ChangeLowering32Test, ChangeBoolToBit) {
|
||||
Node* val = Parameter(0);
|
||||
Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
|
||||
Reduction reduction = Reduce(node);
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
|
||||
EXPECT_THAT(reduction.replacement(),
|
||||
IsWord32Equal(val, IsHeapConstant(true_unique())));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ChangeLowering32Test, ChangeInt32ToTagged) {
|
||||
Node* val = Parameter(0);
|
||||
Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
|
||||
Reduction reduction = Reduce(node);
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
|
||||
Node* phi = reduction.replacement();
|
||||
ASSERT_EQ(IrOpcode::kPhi, phi->opcode());
|
||||
|
||||
Node* smi = NodeProperties::GetValueInput(phi, 1);
|
||||
ASSERT_THAT(smi, IsProjection(0, IsInt32AddWithOverflow(val, val)));
|
||||
|
||||
Node* heap_number = NodeProperties::GetValueInput(phi, 0);
|
||||
ASSERT_EQ(IrOpcode::kCall, heap_number->opcode());
|
||||
|
||||
Node* merge = NodeProperties::GetControlInput(phi);
|
||||
ASSERT_EQ(IrOpcode::kMerge, merge->opcode());
|
||||
|
||||
const int32_t kValueOffset = HeapNumber::kValueOffset - kHeapObjectTag;
|
||||
EXPECT_THAT(NodeProperties::GetControlInput(merge, 0),
|
||||
IsStore(kMachineFloat64, kNoWriteBarrier, heap_number,
|
||||
IsInt32Constant(kValueOffset),
|
||||
IsChangeInt32ToFloat64(val), _, heap_number));
|
||||
|
||||
Node* if_true = NodeProperties::GetControlInput(heap_number);
|
||||
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(IsProjection(1, IsInt32AddWithOverflow(val, val)),
|
||||
graph()->start()));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ChangeLowering32Test, ChangeTaggedToFloat64) {
|
||||
Node* val = Parameter(0);
|
||||
Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
|
||||
Reduction reduction = Reduce(node);
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
|
||||
const int32_t kShiftAmount =
|
||||
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
|
||||
const int32_t kValueOffset = HeapNumber::kValueOffset - kHeapObjectTag;
|
||||
Node* phi = reduction.replacement();
|
||||
ASSERT_THAT(
|
||||
phi, IsPhi(IsLoad(kMachineFloat64, 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()));
|
||||
}
|
||||
|
||||
|
||||
class ChangeLowering64Test : public ChangeLoweringTest<int64_t> {
|
||||
public:
|
||||
virtual ~ChangeLowering64Test() {}
|
||||
};
|
||||
|
||||
|
||||
TEST_F(ChangeLowering64Test, ChangeBoolToBit) {
|
||||
Node* val = Parameter(0);
|
||||
Node* node = graph()->NewNode(simplified()->ChangeBoolToBit(), val);
|
||||
Reduction reduction = Reduce(node);
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
|
||||
EXPECT_THAT(reduction.replacement(),
|
||||
IsWord64Equal(val, IsHeapConstant(true_unique())));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ChangeLowering64Test, ChangeInt32ToTagged) {
|
||||
Node* val = Parameter(0);
|
||||
Node* node = graph()->NewNode(simplified()->ChangeInt32ToTagged(), val);
|
||||
Reduction reduction = Reduce(node);
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
|
||||
const int32_t kShiftAmount =
|
||||
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
|
||||
EXPECT_THAT(reduction.replacement(),
|
||||
IsWord64Shl(val, IsInt32Constant(kShiftAmount)));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ChangeLowering64Test, ChangeTaggedToFloat64) {
|
||||
Node* val = Parameter(0);
|
||||
Node* node = graph()->NewNode(simplified()->ChangeTaggedToFloat64(), val);
|
||||
Reduction reduction = Reduce(node);
|
||||
ASSERT_TRUE(reduction.Changed());
|
||||
|
||||
const int32_t kShiftAmount =
|
||||
kSmiTagSize + SmiTagging<kPointerSize>::kSmiShiftSize;
|
||||
const int32_t kValueOffset = HeapNumber::kValueOffset - kHeapObjectTag;
|
||||
Node* phi = reduction.replacement();
|
||||
ASSERT_THAT(
|
||||
phi, IsPhi(IsLoad(kMachineFloat64, 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()));
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -20,8 +20,11 @@
|
||||
'../..',
|
||||
],
|
||||
'sources': [ ### gcmole(all) ###
|
||||
'change-lowering-unittest.cc',
|
||||
'compiler-unittests.cc',
|
||||
'instruction-selector-unittest.cc',
|
||||
'node-matchers.cc',
|
||||
'node-matchers.h',
|
||||
],
|
||||
'conditions': [
|
||||
['v8_target_arch=="arm"', {
|
||||
|
@ -41,7 +41,6 @@ class CompilerTest : public ::testing::Test {
|
||||
Isolate* isolate() const { return reinterpret_cast<Isolate*>(isolate_); }
|
||||
Zone* zone() { return &zone_; }
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
|
453
test/compiler-unittests/node-matchers.cc
Normal file
453
test/compiler-unittests/node-matchers.cc
Normal file
@ -0,0 +1,453 @@
|
||||
// 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/node-matchers.h"
|
||||
|
||||
#include <ostream> // NOLINT(readability/streams)
|
||||
|
||||
#include "src/compiler/node-properties-inl.h"
|
||||
|
||||
using testing::MatcherInterface;
|
||||
using testing::MatchResultListener;
|
||||
using testing::StringMatchResultListener;
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// TODO(bmeurer): Find a new home for these functions.
|
||||
template <typename T>
|
||||
inline std::ostream& operator<<(std::ostream& os,
|
||||
const PrintableUnique<T>& value) {
|
||||
return os << value.string();
|
||||
}
|
||||
|
||||
namespace compiler {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
bool PrintMatchAndExplain(const T& value, const char* value_name,
|
||||
const Matcher<T>& value_matcher,
|
||||
MatchResultListener* listener) {
|
||||
StringMatchResultListener value_listener;
|
||||
if (!value_matcher.MatchAndExplain(value, &value_listener)) {
|
||||
*listener << "whose " << value_name << " " << value << " doesn't match";
|
||||
if (value_listener.str() != "") {
|
||||
*listener << ", " << value_listener.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class NodeMatcher : public MatcherInterface<Node*> {
|
||||
public:
|
||||
explicit NodeMatcher(IrOpcode::Value opcode) : opcode_(opcode) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
*os << "is a " << IrOpcode::Mnemonic(opcode_) << " node";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
if (node == NULL) {
|
||||
*listener << "which is NULL";
|
||||
return false;
|
||||
}
|
||||
if (node->opcode() != opcode_) {
|
||||
*listener << "whose opcode is " << IrOpcode::Mnemonic(node->opcode());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const IrOpcode::Value opcode_;
|
||||
};
|
||||
|
||||
|
||||
class IsBranchMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsBranchMatcher(const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& control_matcher)
|
||||
: NodeMatcher(IrOpcode::kBranch),
|
||||
value_matcher_(value_matcher),
|
||||
control_matcher_(control_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose value (";
|
||||
value_matcher_.DescribeTo(os);
|
||||
*os << ") and control (";
|
||||
control_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
|
||||
"value", value_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
|
||||
"control", control_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<Node*> value_matcher_;
|
||||
const Matcher<Node*> control_matcher_;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class IsConstantMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsConstantMatcher(IrOpcode::Value opcode, const Matcher<T>& value_matcher)
|
||||
: NodeMatcher(opcode), value_matcher_(value_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose value (";
|
||||
value_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(OpParameter<T>(node), "value", value_matcher_,
|
||||
listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<T> value_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsPhiMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsPhiMatcher(const Matcher<Node*>& value0_matcher,
|
||||
const Matcher<Node*>& value1_matcher,
|
||||
const Matcher<Node*>& control_matcher)
|
||||
: NodeMatcher(IrOpcode::kPhi),
|
||||
value0_matcher_(value0_matcher),
|
||||
value1_matcher_(value1_matcher),
|
||||
control_matcher_(control_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose value0 (";
|
||||
value0_matcher_.DescribeTo(os);
|
||||
*os << "), value1 (";
|
||||
value1_matcher_.DescribeTo(os);
|
||||
*os << ") and control (";
|
||||
control_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
|
||||
"value0", value0_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
|
||||
"value1", value1_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
|
||||
"control", control_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<Node*> value0_matcher_;
|
||||
const Matcher<Node*> value1_matcher_;
|
||||
const Matcher<Node*> control_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsProjectionMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsProjectionMatcher(const Matcher<int32_t>& index_matcher,
|
||||
const Matcher<Node*>& base_matcher)
|
||||
: NodeMatcher(IrOpcode::kProjection),
|
||||
index_matcher_(index_matcher),
|
||||
base_matcher_(base_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose index (";
|
||||
index_matcher_.DescribeTo(os);
|
||||
*os << ") and base (";
|
||||
base_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(OpParameter<int32_t>(node), "index",
|
||||
index_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
|
||||
base_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<int32_t> index_matcher_;
|
||||
const Matcher<Node*> base_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsLoadMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsLoadMatcher(const Matcher<MachineType>& type_matcher,
|
||||
const Matcher<Node*>& base_matcher,
|
||||
const Matcher<Node*>& index_matcher,
|
||||
const Matcher<Node*>& effect_matcher)
|
||||
: NodeMatcher(IrOpcode::kLoad),
|
||||
type_matcher_(type_matcher),
|
||||
base_matcher_(base_matcher),
|
||||
index_matcher_(index_matcher),
|
||||
effect_matcher_(effect_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose type (";
|
||||
type_matcher_.DescribeTo(os);
|
||||
*os << "), base (";
|
||||
base_matcher_.DescribeTo(os);
|
||||
*os << "), index (";
|
||||
index_matcher_.DescribeTo(os);
|
||||
*os << ") and effect (";
|
||||
effect_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
|
||||
type_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
|
||||
base_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
|
||||
"index", index_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
|
||||
effect_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<MachineType> type_matcher_;
|
||||
const Matcher<Node*> base_matcher_;
|
||||
const Matcher<Node*> index_matcher_;
|
||||
const Matcher<Node*> effect_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsStoreMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsStoreMatcher(const Matcher<MachineType>& type_matcher,
|
||||
const Matcher<WriteBarrierKind> write_barrier_matcher,
|
||||
const Matcher<Node*>& base_matcher,
|
||||
const Matcher<Node*>& index_matcher,
|
||||
const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher)
|
||||
: NodeMatcher(IrOpcode::kStore),
|
||||
type_matcher_(type_matcher),
|
||||
write_barrier_matcher_(write_barrier_matcher),
|
||||
base_matcher_(base_matcher),
|
||||
index_matcher_(index_matcher),
|
||||
value_matcher_(value_matcher),
|
||||
effect_matcher_(effect_matcher),
|
||||
control_matcher_(control_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose type (";
|
||||
type_matcher_.DescribeTo(os);
|
||||
*os << "), write barrier (";
|
||||
write_barrier_matcher_.DescribeTo(os);
|
||||
*os << "), base (";
|
||||
base_matcher_.DescribeTo(os);
|
||||
*os << "), index (";
|
||||
index_matcher_.DescribeTo(os);
|
||||
*os << "), value (";
|
||||
value_matcher_.DescribeTo(os);
|
||||
*os << "), effect (";
|
||||
effect_matcher_.DescribeTo(os);
|
||||
*os << ") and control (";
|
||||
control_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(OpParameter<StoreRepresentation>(node).rep,
|
||||
"type", type_matcher_, listener) &&
|
||||
PrintMatchAndExplain(
|
||||
OpParameter<StoreRepresentation>(node).write_barrier_kind,
|
||||
"write barrier", write_barrier_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "base",
|
||||
base_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
|
||||
"index", index_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
|
||||
"value", value_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
|
||||
effect_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
|
||||
"control", control_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<MachineType> type_matcher_;
|
||||
const Matcher<WriteBarrierKind> write_barrier_matcher_;
|
||||
const Matcher<Node*> base_matcher_;
|
||||
const Matcher<Node*> index_matcher_;
|
||||
const Matcher<Node*> value_matcher_;
|
||||
const Matcher<Node*> effect_matcher_;
|
||||
const Matcher<Node*> control_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsBinopMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsBinopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher)
|
||||
: NodeMatcher(opcode),
|
||||
lhs_matcher_(lhs_matcher),
|
||||
rhs_matcher_(rhs_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose lhs (";
|
||||
lhs_matcher_.DescribeTo(os);
|
||||
*os << ") and rhs (";
|
||||
rhs_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0), "lhs",
|
||||
lhs_matcher_, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1), "rhs",
|
||||
rhs_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<Node*> lhs_matcher_;
|
||||
const Matcher<Node*> rhs_matcher_;
|
||||
};
|
||||
|
||||
|
||||
class IsUnopMatcher V8_FINAL : public NodeMatcher {
|
||||
public:
|
||||
IsUnopMatcher(IrOpcode::Value opcode, const Matcher<Node*>& input_matcher)
|
||||
: NodeMatcher(opcode), input_matcher_(input_matcher) {}
|
||||
|
||||
virtual void DescribeTo(std::ostream* os) const V8_OVERRIDE {
|
||||
NodeMatcher::DescribeTo(os);
|
||||
*os << " whose input (";
|
||||
input_matcher_.DescribeTo(os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
virtual bool MatchAndExplain(Node* node, MatchResultListener* listener) const
|
||||
V8_OVERRIDE {
|
||||
return (NodeMatcher::MatchAndExplain(node, listener) &&
|
||||
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
|
||||
"input", input_matcher_, listener));
|
||||
}
|
||||
|
||||
private:
|
||||
const Matcher<Node*> input_matcher_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& control_matcher) {
|
||||
return MakeMatcher(new IsBranchMatcher(value_matcher, control_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher) {
|
||||
return MakeMatcher(
|
||||
new IsConstantMatcher<int32_t>(IrOpcode::kInt32Constant, value_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsHeapConstant(
|
||||
const Matcher<PrintableUnique<HeapObject> >& value_matcher) {
|
||||
return MakeMatcher(new IsConstantMatcher<PrintableUnique<HeapObject> >(
|
||||
IrOpcode::kHeapConstant, value_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsPhi(const Matcher<Node*>& value0_matcher,
|
||||
const Matcher<Node*>& value1_matcher,
|
||||
const Matcher<Node*>& merge_matcher) {
|
||||
return MakeMatcher(
|
||||
new IsPhiMatcher(value0_matcher, value1_matcher, merge_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsProjection(const Matcher<int32_t>& index_matcher,
|
||||
const Matcher<Node*>& base_matcher) {
|
||||
return MakeMatcher(new IsProjectionMatcher(index_matcher, base_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsLoad(const Matcher<MachineType>& type_matcher,
|
||||
const Matcher<Node*>& base_matcher,
|
||||
const Matcher<Node*>& index_matcher,
|
||||
const Matcher<Node*>& effect_matcher) {
|
||||
return MakeMatcher(new IsLoadMatcher(type_matcher, base_matcher,
|
||||
index_matcher, effect_matcher));
|
||||
}
|
||||
|
||||
|
||||
Matcher<Node*> IsStore(const Matcher<MachineType>& type_matcher,
|
||||
const Matcher<WriteBarrierKind>& write_barrier_matcher,
|
||||
const Matcher<Node*>& base_matcher,
|
||||
const Matcher<Node*>& index_matcher,
|
||||
const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher) {
|
||||
return MakeMatcher(new IsStoreMatcher(
|
||||
type_matcher, write_barrier_matcher, base_matcher, index_matcher,
|
||||
value_matcher, effect_matcher, control_matcher));
|
||||
}
|
||||
|
||||
|
||||
#define IS_BINOP_MATCHER(Name) \
|
||||
Matcher<Node*> Is##Name(const Matcher<Node*>& lhs_matcher, \
|
||||
const Matcher<Node*>& rhs_matcher) { \
|
||||
return MakeMatcher( \
|
||||
new IsBinopMatcher(IrOpcode::k##Name, lhs_matcher, rhs_matcher)); \
|
||||
}
|
||||
IS_BINOP_MATCHER(Word32And)
|
||||
IS_BINOP_MATCHER(Word32Sar)
|
||||
IS_BINOP_MATCHER(Word32Equal)
|
||||
IS_BINOP_MATCHER(Word64And)
|
||||
IS_BINOP_MATCHER(Word64Sar)
|
||||
IS_BINOP_MATCHER(Word64Shl)
|
||||
IS_BINOP_MATCHER(Word64Equal)
|
||||
IS_BINOP_MATCHER(Int32AddWithOverflow)
|
||||
#undef IS_BINOP_MATCHER
|
||||
|
||||
|
||||
#define IS_UNOP_MATCHER(Name) \
|
||||
Matcher<Node*> Is##Name(const Matcher<Node*>& input_matcher) { \
|
||||
return MakeMatcher(new IsUnopMatcher(IrOpcode::k##Name, input_matcher)); \
|
||||
}
|
||||
IS_UNOP_MATCHER(ConvertInt64ToInt32)
|
||||
IS_UNOP_MATCHER(ChangeInt32ToFloat64)
|
||||
#undef IS_UNOP_MATCHER
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
71
test/compiler-unittests/node-matchers.h
Normal file
71
test/compiler-unittests/node-matchers.h
Normal file
@ -0,0 +1,71 @@
|
||||
// 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_NODE_MATCHERS_H_
|
||||
#define V8_COMPILER_UNITTESTS_NODE_MATCHERS_H_
|
||||
|
||||
#include "src/compiler/machine-operator.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Forward declarations.
|
||||
class HeapObject;
|
||||
template <class T>
|
||||
class PrintableUnique;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
// Forward declarations.
|
||||
class Node;
|
||||
|
||||
using testing::Matcher;
|
||||
|
||||
Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& control_matcher);
|
||||
Matcher<Node*> IsHeapConstant(
|
||||
const Matcher<PrintableUnique<HeapObject> >& value_matcher);
|
||||
Matcher<Node*> IsInt32Constant(const Matcher<int32_t>& value_matcher);
|
||||
Matcher<Node*> IsPhi(const Matcher<Node*>& value0_matcher,
|
||||
const Matcher<Node*>& value1_matcher,
|
||||
const Matcher<Node*>& merge_matcher);
|
||||
Matcher<Node*> IsProjection(const Matcher<int32_t>& index_matcher,
|
||||
const Matcher<Node*>& base_matcher);
|
||||
|
||||
Matcher<Node*> IsLoad(const Matcher<MachineType>& type_matcher,
|
||||
const Matcher<Node*>& base_matcher,
|
||||
const Matcher<Node*>& index_matcher,
|
||||
const Matcher<Node*>& effect_matcher);
|
||||
Matcher<Node*> IsStore(const Matcher<MachineType>& type_matcher,
|
||||
const Matcher<WriteBarrierKind>& write_barrier_matcher,
|
||||
const Matcher<Node*>& base_matcher,
|
||||
const Matcher<Node*>& index_matcher,
|
||||
const Matcher<Node*>& value_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
const Matcher<Node*>& control_matcher);
|
||||
Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsWord64Sar(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsWord64Equal(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsInt32AddWithOverflow(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsConvertInt64ToInt32(const Matcher<Node*>& input_matcher);
|
||||
Matcher<Node*> IsChangeInt32ToFloat64(const Matcher<Node*>& input_matcher);
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_UNITTESTS_NODE_MATCHERS_H_
|
34
testing/gtest-type-names.h
Normal file
34
testing/gtest-type-names.h
Normal file
@ -0,0 +1,34 @@
|
||||
// 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_GTEST_TYPE_NAMES_H_
|
||||
#define V8_TESTING_GTEST_TYPE_NAMES_H_
|
||||
|
||||
#include "include/v8stdint.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
#define GET_TYPE_NAME(type) \
|
||||
template <> \
|
||||
std::string GetTypeName<type>() { \
|
||||
return #type; \
|
||||
}
|
||||
GET_TYPE_NAME(int8_t)
|
||||
GET_TYPE_NAME(uint8_t)
|
||||
GET_TYPE_NAME(int16_t)
|
||||
GET_TYPE_NAME(uint16_t)
|
||||
GET_TYPE_NAME(int32_t)
|
||||
GET_TYPE_NAME(uint32_t)
|
||||
GET_TYPE_NAME(int64_t)
|
||||
GET_TYPE_NAME(uint64_t)
|
||||
GET_TYPE_NAME(float)
|
||||
GET_TYPE_NAME(double)
|
||||
#undef GET_TYPE_NAME
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // V8_TESTING_GTEST_TYPE_NAMES_H_
|
@ -37,6 +37,7 @@
|
||||
'gtest/src/gtest-test-part.cc',
|
||||
'gtest/src/gtest-typed-test.cc',
|
||||
'gtest/src/gtest.cc',
|
||||
'gtest-type-names.h',
|
||||
],
|
||||
'sources!': [
|
||||
'gtest/src/gtest-all.cc', # Not needed by our build.
|
||||
|
@ -344,6 +344,8 @@
|
||||
'../../src/compilation-cache.h',
|
||||
'../../src/compiler/ast-graph-builder.cc',
|
||||
'../../src/compiler/ast-graph-builder.h',
|
||||
'../../src/compiler/change-lowering.cc',
|
||||
'../../src/compiler/change-lowering.h',
|
||||
'../../src/compiler/code-generator-impl.h',
|
||||
'../../src/compiler/code-generator.cc',
|
||||
'../../src/compiler/code-generator.h',
|
||||
|
Loading…
Reference in New Issue
Block a user