[turbofan] Fix the node matchers.

E.g. make sure that Int32Matcher matches only int32 constants, and
Float64Matcher matches only float64 constants.

Also remove the confusing CommonOperatorTraits, which are too easy
to use in a wrong way.

TEST=compiler-unittests,cctest
R=mstarzinger@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23768 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
bmeurer@chromium.org 2014-09-08 09:16:11 +00:00
parent dab61bc310
commit 2bbeb652ee
22 changed files with 184 additions and 311 deletions

View File

@ -24,15 +24,9 @@ class ArmOperandGenerator FINAL : public OperandGenerator {
}
bool CanBeImmediate(Node* node, InstructionCode opcode) {
int32_t value;
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
case IrOpcode::kNumberConstant:
value = ValueOf<int32_t>(node->op());
break;
default:
return false;
}
Int32Matcher m(node);
if (!m.HasValue()) return false;
int32_t value = m.Value();
switch (ArchOpcodeField::decode(opcode)) {
case kArmAnd:
case kArmMov:

View File

@ -324,7 +324,7 @@ TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
{
// 64-bit subtract.
StreamBuilder m(this, kMachInt64, kMachInt64, kMachInt64);
m.Return(m.Int64Sub(m.Int32Constant(0), m.Parameter(0)));
m.Return(m.Int64Sub(m.Int64Constant(0), m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());

View File

@ -34,15 +34,9 @@ class Arm64OperandGenerator FINAL : public OperandGenerator {
}
bool CanBeImmediate(Node* node, ImmediateMode mode) {
int64_t value;
switch (node->opcode()) {
// TODO(turbofan): SMI number constants as immediates.
case IrOpcode::kInt32Constant:
value = ValueOf<int32_t>(node->op());
break;
default:
return false;
}
Int32Matcher m(node);
if (!m.HasValue()) return false;
int64_t value = m.Value();
unsigned ignored;
switch (mode) {
case kLogical32Imm:
@ -259,27 +253,25 @@ void InstructionSelector::VisitWord64Or(Node* node) {
}
template <typename T>
static void VisitXor(InstructionSelector* selector, Node* node,
ArchOpcode xor_opcode, ArchOpcode not_opcode) {
Arm64OperandGenerator g(selector);
BinopMatcher<IntMatcher<T>, IntMatcher<T> > m(node);
void InstructionSelector::VisitWord32Xor(Node* node) {
Arm64OperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.right().Is(-1)) {
selector->Emit(not_opcode, g.DefineAsRegister(node),
g.UseRegister(m.left().node()));
Emit(kArm64Not32, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
} else {
VisitBinop(selector, node, xor_opcode, kLogical32Imm);
VisitBinop(this, node, kArm64Xor32, kLogical32Imm);
}
}
void InstructionSelector::VisitWord32Xor(Node* node) {
VisitXor<int32_t>(this, node, kArm64Xor32, kArm64Not32);
}
void InstructionSelector::VisitWord64Xor(Node* node) {
VisitXor<int64_t>(this, node, kArm64Xor, kArm64Not);
Arm64OperandGenerator g(this);
Int64BinopMatcher m(node);
if (m.right().Is(-1)) {
Emit(kArm64Not, g.DefineAsRegister(node), g.UseRegister(m.left().node()));
} else {
VisitBinop(this, node, kArm64Xor, kLogical32Imm);
}
}
@ -333,27 +325,26 @@ void InstructionSelector::VisitInt64Add(Node* node) {
}
template <typename T>
static void VisitSub(InstructionSelector* selector, Node* node,
ArchOpcode sub_opcode, ArchOpcode neg_opcode) {
Arm64OperandGenerator g(selector);
BinopMatcher<IntMatcher<T>, IntMatcher<T> > m(node);
void InstructionSelector::VisitInt32Sub(Node* node) {
Arm64OperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.left().Is(0)) {
selector->Emit(neg_opcode, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
Emit(kArm64Neg32, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
} else {
VisitBinop(selector, node, sub_opcode, kArithimeticImm);
VisitBinop(this, node, kArm64Sub32, kArithimeticImm);
}
}
void InstructionSelector::VisitInt32Sub(Node* node) {
VisitSub<int32_t>(this, node, kArm64Sub32, kArm64Neg32);
}
void InstructionSelector::VisitInt64Sub(Node* node) {
VisitSub<int64_t>(this, node, kArm64Sub, kArm64Neg);
Arm64OperandGenerator g(this);
Int64BinopMatcher m(node);
if (m.left().Is(0)) {
Emit(kArm64Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
} else {
VisitBinop(this, node, kArm64Sub, kArithimeticImm);
}
}

View File

@ -187,134 +187,6 @@ class CommonOperatorBuilder {
Zone* zone_;
};
template <typename T>
struct CommonOperatorTraits {
static inline bool Equals(T a, T b);
static inline bool HasValue(const Operator* op);
static inline T ValueOf(const Operator* op);
};
template <>
struct CommonOperatorTraits<int32_t> {
static inline bool Equals(int32_t a, int32_t b) { return a == b; }
static inline bool HasValue(const Operator* op) {
return op->opcode() == IrOpcode::kInt32Constant ||
op->opcode() == IrOpcode::kNumberConstant;
}
static inline int32_t ValueOf(const Operator* op) {
if (op->opcode() == IrOpcode::kNumberConstant) {
// TODO(titzer): cache the converted int32 value in NumberConstant.
return FastD2I(OpParameter<double>(op));
}
CHECK_EQ(IrOpcode::kInt32Constant, op->opcode());
return OpParameter<int32_t>(op);
}
};
template <>
struct CommonOperatorTraits<uint32_t> {
static inline bool Equals(uint32_t a, uint32_t b) { return a == b; }
static inline bool HasValue(const Operator* op) {
return CommonOperatorTraits<int32_t>::HasValue(op);
}
static inline uint32_t ValueOf(const Operator* op) {
if (op->opcode() == IrOpcode::kNumberConstant) {
// TODO(titzer): cache the converted uint32 value in NumberConstant.
return FastD2UI(OpParameter<double>(op));
}
return static_cast<uint32_t>(CommonOperatorTraits<int32_t>::ValueOf(op));
}
};
template <>
struct CommonOperatorTraits<int64_t> {
static inline bool Equals(int64_t a, int64_t b) { return a == b; }
static inline bool HasValue(const Operator* op) {
return op->opcode() == IrOpcode::kInt32Constant ||
op->opcode() == IrOpcode::kInt64Constant ||
op->opcode() == IrOpcode::kNumberConstant;
}
static inline int64_t ValueOf(const Operator* op) {
if (op->opcode() == IrOpcode::kInt32Constant) {
return static_cast<int64_t>(CommonOperatorTraits<int32_t>::ValueOf(op));
}
CHECK_EQ(IrOpcode::kInt64Constant, op->opcode());
return OpParameter<int64_t>(op);
}
};
template <>
struct CommonOperatorTraits<uint64_t> {
static inline bool Equals(uint64_t a, uint64_t b) { return a == b; }
static inline bool HasValue(const Operator* op) {
return CommonOperatorTraits<int64_t>::HasValue(op);
}
static inline uint64_t ValueOf(const Operator* op) {
return static_cast<uint64_t>(CommonOperatorTraits<int64_t>::ValueOf(op));
}
};
template <>
struct CommonOperatorTraits<double> {
static inline bool Equals(double a, double b) {
return DoubleRepresentation(a).bits == DoubleRepresentation(b).bits;
}
static inline bool HasValue(const Operator* op) {
return op->opcode() == IrOpcode::kFloat64Constant ||
op->opcode() == IrOpcode::kInt32Constant ||
op->opcode() == IrOpcode::kNumberConstant;
}
static inline double ValueOf(const Operator* op) {
if (op->opcode() == IrOpcode::kFloat64Constant ||
op->opcode() == IrOpcode::kNumberConstant) {
return OpParameter<double>(op);
}
return static_cast<double>(CommonOperatorTraits<int32_t>::ValueOf(op));
}
};
template <>
struct CommonOperatorTraits<ExternalReference> {
static inline bool Equals(ExternalReference a, ExternalReference b) {
return a == b;
}
static inline bool HasValue(const Operator* op) {
return op->opcode() == IrOpcode::kExternalConstant;
}
static inline ExternalReference ValueOf(const Operator* op) {
CHECK_EQ(IrOpcode::kExternalConstant, op->opcode());
return OpParameter<ExternalReference>(op);
}
};
template <typename T>
struct CommonOperatorTraits<Unique<T> > {
static inline bool HasValue(const Operator* op) {
return op->opcode() == IrOpcode::kHeapConstant;
}
static inline Unique<T> ValueOf(const Operator* op) {
CHECK_EQ(IrOpcode::kHeapConstant, op->opcode());
return OpParameter<Unique<T> >(op);
}
};
template <typename T>
struct CommonOperatorTraits<Handle<T> > {
static inline bool HasValue(const Operator* op) {
return CommonOperatorTraits<Unique<T> >::HasValue(op);
}
static inline Handle<T> ValueOf(const Operator* op) {
return CommonOperatorTraits<Unique<T> >::ValueOf(op).handle();
}
};
template <typename T>
inline T ValueOf(const Operator* op) {
return CommonOperatorTraits<T>::ValueOf(op);
}
} // namespace compiler
} // namespace internal
} // namespace v8

View File

@ -30,8 +30,8 @@ class IA32OperandGenerator FINAL : public OperandGenerator {
case IrOpcode::kHeapConstant: {
// Constants in new space cannot be used as immediates in V8 because
// the GC does not scan code objects when collecting the new generation.
Handle<HeapObject> value = ValueOf<Handle<HeapObject> >(node->op());
return !isolate()->heap()->InNewSpace(*value);
Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node);
return !isolate()->heap()->InNewSpace(*value.handle());
}
default:
return false;

View File

@ -143,16 +143,16 @@ class OperandGenerator {
static Constant ToConstant(const Node* node) {
switch (node->opcode()) {
case IrOpcode::kInt32Constant:
return Constant(ValueOf<int32_t>(node->op()));
return Constant(OpParameter<int32_t>(node));
case IrOpcode::kInt64Constant:
return Constant(ValueOf<int64_t>(node->op()));
return Constant(OpParameter<int64_t>(node));
case IrOpcode::kNumberConstant:
case IrOpcode::kFloat64Constant:
return Constant(ValueOf<double>(node->op()));
return Constant(OpParameter<double>(node));
case IrOpcode::kExternalConstant:
return Constant(ValueOf<ExternalReference>(node->op()));
return Constant(OpParameter<ExternalReference>(node));
case IrOpcode::kHeapConstant:
return Constant(ValueOf<Handle<HeapObject> >(node->op()));
return Constant(OpParameter<Unique<HeapObject> >(node).handle());
default:
break;
}

View File

@ -61,16 +61,16 @@ void JSContextSpecializer::SpecializeToContext() {
Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadContext, node->opcode());
ValueMatcher<Handle<Context> > match(NodeProperties::GetValueInput(node, 0));
HeapObjectMatcher<Context> m(NodeProperties::GetValueInput(node, 0));
// If the context is not constant, no reduction can occur.
if (!match.HasValue()) {
if (!m.HasValue()) {
return Reducer::NoChange();
}
ContextAccess access = OpParameter<ContextAccess>(node);
// Find the right parent context.
Context* context = *match.Value();
Context* context = *m.Value().handle();
for (int i = access.depth(); i > 0; --i) {
context = context->previous();
}
@ -109,9 +109,9 @@ Reduction JSContextSpecializer::ReduceJSLoadContext(Node* node) {
Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) {
DCHECK_EQ(IrOpcode::kJSStoreContext, node->opcode());
ValueMatcher<Handle<Context> > match(NodeProperties::GetValueInput(node, 0));
HeapObjectMatcher<Context> m(NodeProperties::GetValueInput(node, 0));
// If the context is not constant, no reduction can occur.
if (!match.HasValue()) {
if (!m.HasValue()) {
return Reducer::NoChange();
}
@ -123,7 +123,7 @@ Reduction JSContextSpecializer::ReduceJSStoreContext(Node* node) {
}
// Find the right parent context.
Context* context = *match.Value();
Context* context = *m.Value().handle();
for (int i = access.depth(); i > 0; --i) {
context = context->previous();
}

View File

@ -237,12 +237,12 @@ void Inlinee::InlineAtCall(JSGraph* jsgraph, Node* call) {
void JSInliner::TryInlineCall(Node* node) {
DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
ValueMatcher<Handle<JSFunction> > match(node->InputAt(0));
HeapObjectMatcher<JSFunction> match(node->InputAt(0));
if (!match.HasValue()) {
return;
}
Handle<JSFunction> function = match.Value();
Handle<JSFunction> function = match.Value().handle();
if (function->shared()->native()) {
if (FLAG_trace_turbo_inlining) {

View File

@ -5,8 +5,8 @@
#ifndef V8_COMPILER_NODE_MATCHERS_H_
#define V8_COMPILER_NODE_MATCHERS_H_
#include "src/compiler/common-operator.h"
#include "src/compiler/node.h"
#include "src/compiler/operator.h"
namespace v8 {
namespace internal {
@ -36,27 +36,27 @@ struct NodeMatcher {
// A pattern matcher for abitrary value constants.
template <typename T>
template <typename T, IrOpcode::Value kOpcode>
struct ValueMatcher : public NodeMatcher {
explicit ValueMatcher(Node* node)
: NodeMatcher(node),
value_(),
has_value_(CommonOperatorTraits<T>::HasValue(node->op())) {
if (has_value_) value_ = CommonOperatorTraits<T>::ValueOf(node->op());
: NodeMatcher(node), value_(), has_value_(opcode() == kOpcode) {
if (has_value_) {
value_ = OpParameter<T>(node);
}
}
bool HasValue() const { return has_value_; }
T Value() const {
const T& Value() const {
DCHECK(HasValue());
return value_;
}
bool Is(T value) const {
return HasValue() && CommonOperatorTraits<T>::Equals(Value(), value);
bool Is(const T& value) const {
return this->HasValue() && this->Value() == value;
}
bool IsInRange(T low, T high) const {
return HasValue() && low <= value_ && value_ <= high;
bool IsInRange(const T& low, const T& high) const {
return this->HasValue() && low <= this->Value() && this->Value() <= high;
}
private:
@ -66,9 +66,9 @@ struct ValueMatcher : public NodeMatcher {
// A pattern matcher for integer constants.
template <typename T>
struct IntMatcher FINAL : public ValueMatcher<T> {
explicit IntMatcher(Node* node) : ValueMatcher<T>(node) {}
template <typename T, IrOpcode::Value kOpcode>
struct IntMatcher FINAL : public ValueMatcher<T, kOpcode> {
explicit IntMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
bool IsPowerOf2() const {
return this->HasValue() && this->Value() > 0 &&
@ -76,31 +76,30 @@ struct IntMatcher FINAL : public ValueMatcher<T> {
}
};
typedef IntMatcher<int32_t> Int32Matcher;
typedef IntMatcher<uint32_t> Uint32Matcher;
typedef IntMatcher<int64_t> Int64Matcher;
typedef IntMatcher<uint64_t> Uint64Matcher;
typedef IntMatcher<int32_t, IrOpcode::kInt32Constant> Int32Matcher;
typedef IntMatcher<uint32_t, IrOpcode::kInt32Constant> Uint32Matcher;
typedef IntMatcher<int64_t, IrOpcode::kInt64Constant> Int64Matcher;
typedef IntMatcher<uint64_t, IrOpcode::kInt64Constant> Uint64Matcher;
// A pattern matcher for floating point constants.
template <typename T>
struct FloatMatcher FINAL : public ValueMatcher<T> {
explicit FloatMatcher(Node* node) : ValueMatcher<T>(node) {}
template <typename T, IrOpcode::Value kOpcode>
struct FloatMatcher FINAL : public ValueMatcher<T, kOpcode> {
explicit FloatMatcher(Node* node) : ValueMatcher<T, kOpcode>(node) {}
bool IsNaN() const { return this->HasValue() && std::isnan(this->Value()); }
};
typedef FloatMatcher<double> Float64Matcher;
typedef FloatMatcher<double, IrOpcode::kFloat64Constant> Float64Matcher;
typedef FloatMatcher<double, IrOpcode::kNumberConstant> NumberMatcher;
// A pattern matcher for heap object constants.
struct HeapObjectMatcher FINAL : public ValueMatcher<Handle<HeapObject> > {
template <typename T>
struct HeapObjectMatcher FINAL
: public ValueMatcher<Unique<T>, IrOpcode::kHeapConstant> {
explicit HeapObjectMatcher(Node* node)
: ValueMatcher<Handle<HeapObject> >(node) {}
bool IsKnownGlobal(Handle<HeapObject> global) const {
return HasValue() && Value().is_identical_to(global);
}
: ValueMatcher<Unique<T>, IrOpcode::kHeapConstant>(node) {}
};
@ -138,8 +137,9 @@ typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher;
typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher;
typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher;
typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher;
}
}
} // namespace v8::internal::compiler
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_NODE_MATCHERS_H_

View File

@ -82,7 +82,7 @@ typedef Node::Inputs::iterator InputIter;
// Helper to extract parameters from Operator1<*> nodes.
template <typename T>
static inline T OpParameter(const Node* node) {
static inline const T& OpParameter(const Node* node) {
return OpParameter<T>(node->op());
}

View File

@ -266,7 +266,7 @@ typedef Operator1<Unique<Name> > NameOperator;
// Helper to extract parameters from Operator1<*> operator.
template <typename T>
static inline T OpParameter(const Operator* op) {
static inline const T& OpParameter(const Operator* op) {
return reinterpret_cast<const Operator1<T>*>(op)->parameter();
}

View File

@ -74,19 +74,19 @@ class RepresentationChanger {
return node; // No change necessary.
case IrOpcode::kInt32Constant:
if (output_type & kTypeUint32) {
uint32_t value = ValueOf<uint32_t>(node->op());
uint32_t value = OpParameter<uint32_t>(node);
return jsgraph()->Constant(static_cast<double>(value));
} else if (output_type & kTypeInt32) {
int32_t value = ValueOf<int32_t>(node->op());
int32_t value = OpParameter<int32_t>(node);
return jsgraph()->Constant(value);
} else if (output_type & kRepBit) {
return ValueOf<int32_t>(node->op()) == 0 ? jsgraph()->FalseConstant()
: jsgraph()->TrueConstant();
return OpParameter<int32_t>(node) == 0 ? jsgraph()->FalseConstant()
: jsgraph()->TrueConstant();
} else {
return TypeError(node, output_type, kRepTagged);
}
case IrOpcode::kFloat64Constant:
return jsgraph()->Constant(ValueOf<double>(node->op()));
return jsgraph()->Constant(OpParameter<double>(node));
default:
break;
}
@ -114,13 +114,13 @@ class RepresentationChanger {
// Eagerly fold representation changes for constants.
switch (node->opcode()) {
case IrOpcode::kNumberConstant:
return jsgraph()->Float64Constant(ValueOf<double>(node->op()));
return jsgraph()->Float64Constant(OpParameter<double>(node));
case IrOpcode::kInt32Constant:
if (output_type & kTypeUint32) {
uint32_t value = ValueOf<uint32_t>(node->op());
uint32_t value = OpParameter<uint32_t>(node);
return jsgraph()->Float64Constant(static_cast<double>(value));
} else {
int32_t value = ValueOf<int32_t>(node->op());
int32_t value = OpParameter<int32_t>(node);
return jsgraph()->Float64Constant(value);
}
case IrOpcode::kFloat64Constant:
@ -154,7 +154,7 @@ class RepresentationChanger {
return node; // No change necessary.
case IrOpcode::kNumberConstant:
case IrOpcode::kFloat64Constant: {
double value = ValueOf<double>(node->op());
double value = OpParameter<double>(node);
if (value < 0) {
DCHECK(IsInt32Double(value));
int32_t iv = static_cast<int32_t>(value);
@ -192,12 +192,12 @@ class RepresentationChanger {
// Eagerly fold representation changes for constants.
switch (node->opcode()) {
case IrOpcode::kInt32Constant: {
int32_t value = ValueOf<int32_t>(node->op());
int32_t value = OpParameter<int32_t>(node);
if (value == 0 || value == 1) return node;
return jsgraph()->OneConstant(); // value != 0
}
case IrOpcode::kHeapConstant: {
Handle<Object> handle = ValueOf<Handle<Object> >(node->op());
Handle<Object> handle = OpParameter<Unique<Object> >(node).handle();
DCHECK(*handle == isolate()->heap()->true_value() ||
*handle == isolate()->heap()->false_value());
return jsgraph()->Int32Constant(

View File

@ -18,11 +18,11 @@ SimplifiedOperatorReducer::~SimplifiedOperatorReducer() {}
Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
switch (node->opcode()) {
case IrOpcode::kBooleanNot: {
HeapObjectMatcher m(node->InputAt(0));
if (m.IsKnownGlobal(factory()->false_value())) {
HeapObjectMatcher<HeapObject> m(node->InputAt(0));
if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->false_value()))) {
return Replace(jsgraph()->TrueConstant());
}
if (m.IsKnownGlobal(factory()->true_value())) {
if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->true_value()))) {
return Replace(jsgraph()->FalseConstant());
}
if (m.IsBooleanNot()) return Replace(m.node()->InputAt(0));
@ -36,9 +36,13 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
break;
}
case IrOpcode::kChangeBoolToBit: {
HeapObjectMatcher m(node->InputAt(0));
if (m.IsKnownGlobal(factory()->false_value())) return ReplaceInt32(0);
if (m.IsKnownGlobal(factory()->true_value())) return ReplaceInt32(1);
HeapObjectMatcher<HeapObject> m(node->InputAt(0));
if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->false_value()))) {
return ReplaceInt32(0);
}
if (m.Is(Unique<HeapObject>::CreateImmovable(factory()->true_value()))) {
return ReplaceInt32(1);
}
if (m.IsChangeBitToBool()) return Replace(m.node()->InputAt(0));
break;
}
@ -53,7 +57,7 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
break;
}
case IrOpcode::kChangeTaggedToFloat64: {
Float64Matcher m(node->InputAt(0));
NumberMatcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceFloat64(m.Value());
if (m.IsChangeFloat64ToTagged()) return Replace(m.node()->InputAt(0));
if (m.IsChangeInt32ToTagged()) {
@ -67,7 +71,7 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
break;
}
case IrOpcode::kChangeTaggedToInt32: {
Float64Matcher m(node->InputAt(0));
NumberMatcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
if (m.IsChangeFloat64ToTagged()) {
return Change(node, machine()->ChangeFloat64ToInt32(),
@ -77,7 +81,7 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
break;
}
case IrOpcode::kChangeTaggedToUint32: {
Float64Matcher m(node->InputAt(0));
NumberMatcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceUint32(DoubleToUint32(m.Value()));
if (m.IsChangeFloat64ToTagged()) {
return Change(node, machine()->ChangeFloat64ToUint32(),

View File

@ -212,31 +212,31 @@ Bounds Typer::Visitor::TypeParameter(Node* node) {
Bounds Typer::Visitor::TypeInt32Constant(Node* node) {
// TODO(titzer): only call Type::Of() if the type is not already known.
return Bounds(Type::Of(ValueOf<int32_t>(node->op()), zone()));
return Bounds(Type::Of(OpParameter<int32_t>(node), zone()));
}
Bounds Typer::Visitor::TypeInt64Constant(Node* node) {
// TODO(titzer): only call Type::Of() if the type is not already known.
return Bounds(
Type::Of(static_cast<double>(ValueOf<int64_t>(node->op())), zone()));
Type::Of(static_cast<double>(OpParameter<int64_t>(node)), zone()));
}
Bounds Typer::Visitor::TypeFloat64Constant(Node* node) {
// TODO(titzer): only call Type::Of() if the type is not already known.
return Bounds(Type::Of(ValueOf<double>(node->op()), zone()));
return Bounds(Type::Of(OpParameter<double>(node), zone()));
}
Bounds Typer::Visitor::TypeNumberConstant(Node* node) {
// TODO(titzer): only call Type::Of() if the type is not already known.
return Bounds(Type::Of(ValueOf<double>(node->op()), zone()));
return Bounds(Type::Of(OpParameter<double>(node), zone()));
}
Bounds Typer::Visitor::TypeHeapConstant(Node* node) {
return Bounds(TypeConstant(ValueOf<Handle<Object> >(node->op())));
return Bounds(TypeConstant(OpParameter<Unique<Object> >(node).handle()));
}

View File

@ -45,8 +45,8 @@ class X64OperandGenerator FINAL : public OperandGenerator {
case IrOpcode::kHeapConstant: {
// Constants in new space cannot be used as immediates in V8 because
// the GC does not scan code objects when collecting the new generation.
Handle<HeapObject> value = ValueOf<Handle<HeapObject> >(node->op());
return !isolate()->heap()->InNewSpace(*value);
Unique<HeapObject> value = OpParameter<Unique<HeapObject> >(node);
return !isolate()->heap()->InNewSpace(*value.handle());
}
default:
return false;
@ -243,27 +243,25 @@ void InstructionSelector::VisitWord64Or(Node* node) {
}
template <typename T>
static void VisitXor(InstructionSelector* selector, Node* node,
ArchOpcode xor_opcode, ArchOpcode not_opcode) {
X64OperandGenerator g(selector);
BinopMatcher<IntMatcher<T>, IntMatcher<T> > m(node);
void InstructionSelector::VisitWord32Xor(Node* node) {
X64OperandGenerator g(this);
Uint32BinopMatcher m(node);
if (m.right().Is(-1)) {
selector->Emit(not_opcode, g.DefineSameAsFirst(node),
g.Use(m.left().node()));
Emit(kX64Not32, g.DefineSameAsFirst(node), g.Use(m.left().node()));
} else {
VisitBinop(selector, node, xor_opcode);
VisitBinop(this, node, kX64Xor32);
}
}
void InstructionSelector::VisitWord32Xor(Node* node) {
VisitXor<int32_t>(this, node, kX64Xor32, kX64Not32);
}
void InstructionSelector::VisitWord64Xor(Node* node) {
VisitXor<int64_t>(this, node, kX64Xor, kX64Not);
X64OperandGenerator g(this);
Uint64BinopMatcher m(node);
if (m.right().Is(-1)) {
Emit(kX64Not, g.DefineSameAsFirst(node), g.Use(m.left().node()));
} else {
VisitBinop(this, node, kX64Xor);
}
}
@ -369,27 +367,25 @@ void InstructionSelector::VisitInt64Add(Node* node) {
}
template <typename T>
static void VisitSub(InstructionSelector* selector, Node* node,
ArchOpcode sub_opcode, ArchOpcode neg_opcode) {
X64OperandGenerator g(selector);
BinopMatcher<IntMatcher<T>, IntMatcher<T> > m(node);
void InstructionSelector::VisitInt32Sub(Node* node) {
X64OperandGenerator g(this);
Int32BinopMatcher m(node);
if (m.left().Is(0)) {
selector->Emit(neg_opcode, g.DefineSameAsFirst(node),
g.Use(m.right().node()));
Emit(kX64Neg32, g.DefineSameAsFirst(node), g.Use(m.right().node()));
} else {
VisitBinop(selector, node, sub_opcode);
VisitBinop(this, node, kX64Sub32);
}
}
void InstructionSelector::VisitInt32Sub(Node* node) {
VisitSub<int32_t>(this, node, kX64Sub32, kX64Neg32);
}
void InstructionSelector::VisitInt64Sub(Node* node) {
VisitSub<int64_t>(this, node, kX64Sub, kX64Neg);
X64OperandGenerator g(this);
Int64BinopMatcher m(node);
if (m.left().Is(0)) {
Emit(kX64Neg, g.DefineSameAsFirst(node), g.Use(m.right().node()));
} else {
VisitBinop(this, node, kX64Sub);
}
}

View File

@ -32,6 +32,8 @@ class UniqueSet;
template <typename T>
class Unique {
public:
Unique<T>() : raw_address_(NULL) {}
// TODO(titzer): make private and introduce a uniqueness scope.
explicit Unique(Handle<T> handle) {
if (handle.is_null()) {
@ -120,8 +122,6 @@ class Unique {
friend class Unique; // For comparing raw_address values.
protected:
Unique<T>() : raw_address_(NULL) { }
Address raw_address_;
Handle<T> handle_;

View File

@ -36,7 +36,7 @@ class JSConstantCacheTester : public HandleAndZoneScope,
Handle<Object> handle(Node* node) {
CHECK_EQ(IrOpcode::kHeapConstant, node->opcode());
return ValueOf<Handle<Object> >(node->op());
return OpParameter<Unique<Object> >(node).handle();
}
Factory* factory() { return main_isolate()->factory(); }
@ -87,8 +87,8 @@ TEST(MinusZeroConstant) {
CHECK(!t->Is(Type::SignedSmall()));
CHECK(!t->Is(Type::UnsignedSmall()));
double zero_value = ValueOf<double>(zero->op());
double minus_zero_value = ValueOf<double>(minus_zero->op());
double zero_value = OpParameter<double>(zero);
double minus_zero_value = OpParameter<double>(minus_zero);
CHECK_EQ(0.0, zero_value);
CHECK_NE(-0.0, zero_value);

View File

@ -90,8 +90,8 @@ TEST(ReduceJSLoadContext) {
CHECK(r.Changed());
Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0);
CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode());
ValueMatcher<Handle<Context> > match(new_context_input);
CHECK_EQ(*native, *match.Value());
HeapObjectMatcher<Context> match(new_context_input);
CHECK_EQ(*native, *match.Value().handle());
ContextAccess access = OpParameter<ContextAccess>(r.replacement());
CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
CHECK_EQ(0, access.depth());
@ -106,9 +106,9 @@ TEST(ReduceJSLoadContext) {
CHECK(r.Changed());
CHECK(r.replacement() != load);
ValueMatcher<Handle<Object> > match(r.replacement());
HeapObjectMatcher<Object> match(r.replacement());
CHECK(match.HasValue());
CHECK_EQ(*expected, *match.Value());
CHECK_EQ(*expected, *match.Value().handle());
}
// TODO(titzer): test with other kinds of contexts, e.g. a function context.
@ -170,8 +170,8 @@ TEST(ReduceJSStoreContext) {
CHECK(r.Changed());
Node* new_context_input = NodeProperties::GetValueInput(r.replacement(), 0);
CHECK_EQ(IrOpcode::kHeapConstant, new_context_input->opcode());
ValueMatcher<Handle<Context> > match(new_context_input);
CHECK_EQ(*native, *match.Value());
HeapObjectMatcher<Context> match(new_context_input);
CHECK_EQ(*native, *match.Value().handle());
ContextAccess access = OpParameter<ContextAccess>(r.replacement());
CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
CHECK_EQ(0, access.depth());
@ -240,9 +240,9 @@ TEST(SpecializeToContext) {
CHECK_EQ(other_load, other_use->InputAt(0));
Node* replacement = value_use->InputAt(0);
ValueMatcher<Handle<Object> > match(replacement);
HeapObjectMatcher<Object> match(replacement);
CHECK(match.HasValue());
CHECK_EQ(*expected, *match.Value());
CHECK_EQ(*expected, *match.Value().handle());
}
// TODO(titzer): clean up above test and test more complicated effects.
}

View File

@ -108,17 +108,17 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
void CheckInt32Constant(int32_t expected, Node* result) {
CHECK_EQ(IrOpcode::kInt32Constant, result->opcode());
CHECK_EQ(expected, ValueOf<int32_t>(result->op()));
CHECK_EQ(expected, OpParameter<int32_t>(result));
}
void CheckNumberConstant(double expected, Node* result) {
CHECK_EQ(IrOpcode::kNumberConstant, result->opcode());
CHECK_EQ(expected, ValueOf<double>(result->op()));
CHECK_EQ(expected, OpParameter<double>(result));
}
void CheckNaN(Node* result) {
CHECK_EQ(IrOpcode::kNumberConstant, result->opcode());
double value = ValueOf<double>(result->op());
double value = OpParameter<double>(result);
CHECK(std::isnan(value));
}
@ -132,7 +132,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
void CheckHandle(Handle<Object> expected, Node* result) {
CHECK_EQ(IrOpcode::kHeapConstant, result->opcode());
Handle<Object> value = ValueOf<Handle<Object> >(result->op());
Handle<Object> value = OpParameter<Unique<Object> >(result).handle();
CHECK_EQ(*expected, *value);
}
};
@ -240,7 +240,7 @@ static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) {
CHECK_EQ(old_input, new_input);
} else if (new_input->opcode() == IrOpcode::kNumberConstant) {
CHECK(NodeProperties::GetBounds(new_input).upper->Is(expected_type));
double v = ValueOf<double>(new_input->op());
double v = OpParameter<double>(new_input);
double e = static_cast<double>(is_signed ? FastD2I(v) : FastD2UI(v));
CHECK_EQ(e, v);
} else {

View File

@ -30,6 +30,22 @@ Operator* NewConstantOperator<double>(CommonOperatorBuilder* common,
}
template <typename T>
T ValueOfOperator(const Operator* op);
template <>
int32_t ValueOfOperator<int32_t>(const Operator* op) {
CHECK_EQ(IrOpcode::kInt32Constant, op->opcode());
return OpParameter<int32_t>(op);
}
template <>
double ValueOfOperator<double>(const Operator* op) {
CHECK_EQ(IrOpcode::kFloat64Constant, op->opcode());
return OpParameter<double>(op);
}
class ReducerTester : public HandleAndZoneScope {
public:
explicit ReducerTester(int num_parameters = 0)
@ -61,6 +77,11 @@ class ReducerTester : public HandleAndZoneScope {
return graph.NewNode(NewConstantOperator<T>(&common, value));
}
template <typename T>
const T ValueOf(const Operator* op) {
return ValueOfOperator<T>(op);
}
// Check that the reduction of this binop applied to constants {a} and {b}
// yields the {expect} value.
template <typename T>

View File

@ -43,19 +43,19 @@ class RepresentationChangerTester : public HandleAndZoneScope,
// TODO(titzer): use ValueChecker / ValueUtil
void CheckInt32Constant(Node* n, int32_t expected) {
ValueMatcher<int32_t> m(n);
Int32Matcher m(n);
CHECK(m.HasValue());
CHECK_EQ(expected, m.Value());
}
void CheckHeapConstant(Node* n, Object* expected) {
ValueMatcher<Handle<Object> > m(n);
void CheckHeapConstant(Node* n, HeapObject* expected) {
HeapObjectMatcher<HeapObject> m(n);
CHECK(m.HasValue());
CHECK_EQ(expected, *m.Value());
CHECK_EQ(expected, *m.Value().handle());
}
void CheckNumberConstant(Node* n, double expected) {
ValueMatcher<double> m(n);
NumberMatcher m(n);
CHECK_EQ(IrOpcode::kNumberConstant, n->opcode());
CHECK(m.HasValue());
CHECK_EQ(expected, m.Value());

View File

@ -27,34 +27,29 @@ class ValueHelper {
ValueHelper() : isolate_(CcTest::InitIsolateOnce()) {}
template <typename T>
void CheckConstant(T expected, Node* node) {
CHECK_EQ(expected, ValueOf<T>(node->op()));
}
void CheckFloat64Constant(double expected, Node* node) {
CHECK_EQ(IrOpcode::kFloat64Constant, node->opcode());
CHECK_EQ(expected, ValueOf<double>(node->op()));
CHECK_EQ(expected, OpParameter<double>(node));
}
void CheckNumberConstant(double expected, Node* node) {
CHECK_EQ(IrOpcode::kNumberConstant, node->opcode());
CHECK_EQ(expected, ValueOf<double>(node->op()));
CHECK_EQ(expected, OpParameter<double>(node));
}
void CheckInt32Constant(int32_t expected, Node* node) {
CHECK_EQ(IrOpcode::kInt32Constant, node->opcode());
CHECK_EQ(expected, ValueOf<int32_t>(node->op()));
CHECK_EQ(expected, OpParameter<int32_t>(node));
}
void CheckUint32Constant(int32_t expected, Node* node) {
CHECK_EQ(IrOpcode::kInt32Constant, node->opcode());
CHECK_EQ(expected, ValueOf<uint32_t>(node->op()));
CHECK_EQ(expected, OpParameter<uint32_t>(node));
}
void CheckHeapConstant(Object* expected, Node* node) {
CHECK_EQ(IrOpcode::kHeapConstant, node->opcode());
CHECK_EQ(expected, *ValueOf<Handle<Object> >(node->op()));
CHECK_EQ(expected, *OpParameter<Unique<Object> >(node).handle());
}
void CheckTrue(Node* node) {