Commit 78f3df63 authored by bmeurer@chromium.org's avatar bmeurer@chromium.org

[turbofan] Most simplified operators are globally shared singletons.

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

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23896 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 788c5354
......@@ -29,6 +29,7 @@
'machine-operator-reducer-unittest.cc',
'machine-operator-unittest.cc',
'simplified-operator-reducer-unittest.cc',
'simplified-operator-unittest.cc',
'value-numbering-reducer-unittest.cc',
],
'conditions': [
......
......@@ -166,7 +166,8 @@ TEST_P(SimplifiedUnaryOperatorTest, Parameter) {
}
INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedUnaryOperatorTest,
INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest,
SimplifiedUnaryOperatorTest,
::testing::ValuesIn(kUnaryOperators));
......
// 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/simplified-operator.h"
#include "src/compiler/operator-properties-inl.h"
#include "src/test/test-utils.h"
namespace v8 {
namespace internal {
namespace compiler {
// -----------------------------------------------------------------------------
// Pure operators.
namespace {
struct PureOperator {
const Operator* (SimplifiedOperatorBuilder::*constructor)() const;
IrOpcode::Value opcode;
Operator::Properties properties;
int value_input_count;
};
std::ostream& operator<<(std::ostream& os, const PureOperator& pop) {
return os << IrOpcode::Mnemonic(pop.opcode);
}
const PureOperator kPureOperators[] = {
#define PURE(Name, properties, input_count) \
{ \
&SimplifiedOperatorBuilder::Name, IrOpcode::k##Name, \
Operator::kPure | properties, input_count \
}
PURE(BooleanNot, Operator::kNoProperties, 1),
PURE(NumberEqual, Operator::kCommutative, 2),
PURE(NumberLessThan, Operator::kNoProperties, 2),
PURE(NumberLessThanOrEqual, Operator::kNoProperties, 2),
PURE(NumberAdd, Operator::kCommutative, 2),
PURE(NumberSubtract, Operator::kNoProperties, 2),
PURE(NumberMultiply, Operator::kCommutative, 2),
PURE(NumberDivide, Operator::kNoProperties, 2),
PURE(NumberModulus, Operator::kNoProperties, 2),
PURE(NumberToInt32, Operator::kNoProperties, 1),
PURE(NumberToUint32, Operator::kNoProperties, 1),
PURE(StringEqual, Operator::kCommutative, 2),
PURE(StringLessThan, Operator::kNoProperties, 2),
PURE(StringLessThanOrEqual, Operator::kNoProperties, 2),
PURE(StringAdd, Operator::kNoProperties, 2),
PURE(ChangeTaggedToInt32, Operator::kNoProperties, 1),
PURE(ChangeTaggedToUint32, Operator::kNoProperties, 1),
PURE(ChangeTaggedToFloat64, Operator::kNoProperties, 1),
PURE(ChangeInt32ToTagged, Operator::kNoProperties, 1),
PURE(ChangeUint32ToTagged, Operator::kNoProperties, 1),
PURE(ChangeFloat64ToTagged, Operator::kNoProperties, 1),
PURE(ChangeBoolToBit, Operator::kNoProperties, 1),
PURE(ChangeBitToBool, Operator::kNoProperties, 1)
#undef PURE
};
} // namespace
class SimplifiedPureOperatorTest
: public TestWithZone,
public ::testing::WithParamInterface<PureOperator> {};
TEST_P(SimplifiedPureOperatorTest, InstancesAreGloballyShared) {
const PureOperator& pop = GetParam();
SimplifiedOperatorBuilder simplified1(zone());
SimplifiedOperatorBuilder simplified2(zone());
EXPECT_EQ((simplified1.*pop.constructor)(), (simplified2.*pop.constructor)());
}
TEST_P(SimplifiedPureOperatorTest, NumberOfInputsAndOutputs) {
SimplifiedOperatorBuilder simplified(zone());
const PureOperator& pop = GetParam();
const Operator* op = (simplified.*pop.constructor)();
EXPECT_EQ(pop.value_input_count, OperatorProperties::GetValueInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetEffectInputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
EXPECT_EQ(pop.value_input_count, OperatorProperties::GetTotalInputCount(op));
EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
EXPECT_EQ(0, OperatorProperties::GetEffectOutputCount(op));
EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
}
TEST_P(SimplifiedPureOperatorTest, OpcodeIsCorrect) {
SimplifiedOperatorBuilder simplified(zone());
const PureOperator& pop = GetParam();
const Operator* op = (simplified.*pop.constructor)();
EXPECT_EQ(pop.opcode, op->opcode());
}
TEST_P(SimplifiedPureOperatorTest, Properties) {
SimplifiedOperatorBuilder simplified(zone());
const PureOperator& pop = GetParam();
const Operator* op = (simplified.*pop.constructor)();
EXPECT_EQ(pop.properties, op->properties() & pop.properties);
}
INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
::testing::ValuesIn(kPureOperators));
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -3,28 +3,145 @@
// found in the LICENSE file.
#include "src/compiler/simplified-operator.h"
#include "src/base/lazy-instance.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
#include "src/types-inl.h"
namespace v8 {
namespace internal {
namespace compiler {
// static
bool StaticParameterTraits<FieldAccess>::Equals(const FieldAccess& lhs,
const FieldAccess& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
lhs.machine_type == rhs.machine_type && lhs.type->Is(rhs.type);
const FieldAccess& FieldAccessOf(const Operator* op) {
DCHECK_NOT_NULL(op);
DCHECK(op->opcode() == IrOpcode::kLoadField ||
op->opcode() == IrOpcode::kStoreField);
return OpParameter<FieldAccess>(op);
}
const ElementAccess& ElementAccessOf(const Operator* op) {
DCHECK_NOT_NULL(op);
DCHECK(op->opcode() == IrOpcode::kLoadElement ||
op->opcode() == IrOpcode::kStoreElement);
return OpParameter<ElementAccess>(op);
}
// static
bool StaticParameterTraits<ElementAccess>::Equals(const ElementAccess& lhs,
const ElementAccess& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.header_size == rhs.header_size &&
lhs.machine_type == rhs.machine_type && lhs.type->Is(rhs.type);
// Specialization for static parameters of type {FieldAccess}.
template <>
struct StaticParameterTraits<FieldAccess> {
static OStream& PrintTo(OStream& os, const FieldAccess& val) {
return os << val.offset;
}
static int HashCode(const FieldAccess& val) {
return (val.offset < 16) | (val.machine_type & 0xffff);
}
static bool Equals(const FieldAccess& lhs, const FieldAccess& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.offset == rhs.offset && lhs.machine_type == rhs.machine_type &&
lhs.type->Is(rhs.type);
}
};
// Specialization for static parameters of type {ElementAccess}.
template <>
struct StaticParameterTraits<ElementAccess> {
static OStream& PrintTo(OStream& os, const ElementAccess& val) {
return os << val.header_size;
}
static int HashCode(const ElementAccess& val) {
return (val.header_size < 16) | (val.machine_type & 0xffff);
}
static bool Equals(const ElementAccess& lhs, const ElementAccess& rhs) {
return lhs.base_is_tagged == rhs.base_is_tagged &&
lhs.header_size == rhs.header_size &&
lhs.machine_type == rhs.machine_type && lhs.type->Is(rhs.type);
}
};
#define PURE_OP_LIST(V) \
V(BooleanNot, Operator::kNoProperties, 1) \
V(NumberEqual, Operator::kCommutative, 2) \
V(NumberLessThan, Operator::kNoProperties, 2) \
V(NumberLessThanOrEqual, Operator::kNoProperties, 2) \
V(NumberAdd, Operator::kCommutative, 2) \
V(NumberSubtract, Operator::kNoProperties, 2) \
V(NumberMultiply, Operator::kCommutative, 2) \
V(NumberDivide, Operator::kNoProperties, 2) \
V(NumberModulus, Operator::kNoProperties, 2) \
V(NumberToInt32, Operator::kNoProperties, 1) \
V(NumberToUint32, Operator::kNoProperties, 1) \
V(StringEqual, Operator::kCommutative, 2) \
V(StringLessThan, Operator::kNoProperties, 2) \
V(StringLessThanOrEqual, Operator::kNoProperties, 2) \
V(StringAdd, Operator::kNoProperties, 2) \
V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
V(ChangeTaggedToFloat64, Operator::kNoProperties, 1) \
V(ChangeInt32ToTagged, Operator::kNoProperties, 1) \
V(ChangeUint32ToTagged, Operator::kNoProperties, 1) \
V(ChangeFloat64ToTagged, Operator::kNoProperties, 1) \
V(ChangeBoolToBit, Operator::kNoProperties, 1) \
V(ChangeBitToBool, Operator::kNoProperties, 1)
#define ACCESS_OP_LIST(V) \
V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1) \
V(StoreField, FieldAccess, Operator::kNoRead, 2, 0) \
V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1) \
V(StoreElement, ElementAccess, Operator::kNoRead, 3, 0)
struct SimplifiedOperatorBuilderImpl FINAL {
#define PURE(Name, properties, input_count) \
struct Name##Operator FINAL : public SimpleOperator { \
Name##Operator() \
: SimpleOperator(IrOpcode::k##Name, Operator::kPure | properties, \
input_count, 1, #Name) {} \
}; \
Name##Operator k##Name;
PURE_OP_LIST(PURE)
#undef PURE
};
static base::LazyInstance<SimplifiedOperatorBuilderImpl>::type kImpl =
LAZY_INSTANCE_INITIALIZER;
SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
: impl_(kImpl.Get()), zone_(zone) {}
#define PURE(Name, properties, input_count) \
const Operator* SimplifiedOperatorBuilder::Name() const { \
return &impl_.k##Name; \
}
PURE_OP_LIST(PURE)
#undef PURE
const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) const {
// TODO(titzer): What about the type parameter?
return new (zone()) SimpleOperator(IrOpcode::kReferenceEqual,
Operator::kCommutative | Operator::kPure,
2, 1, "ReferenceEqual");
}
#define ACCESS(Name, Type, properties, input_count, output_count) \
const Operator* SimplifiedOperatorBuilder::Name(const Type& access) const { \
return new (zone()) \
Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \
input_count, output_count, #Name, access); \
}
ACCESS_OP_LIST(ACCESS)
#undef ACCESS
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -5,11 +5,8 @@
#ifndef V8_COMPILER_SIMPLIFIED_OPERATOR_H_
#define V8_COMPILER_SIMPLIFIED_OPERATOR_H_
#include "src/compiler/machine-operator.h"
#include "src/compiler/opcodes.h"
#include "src/compiler/operator.h"
#include "src/compiler/machine-type.h"
#include "src/handles.h"
#include "src/zone.h"
namespace v8 {
namespace internal {
......@@ -19,10 +16,16 @@ template <class>
class TypeImpl;
struct ZoneTypeConfig;
typedef TypeImpl<ZoneTypeConfig> Type;
class Zone;
namespace compiler {
// Forward declarations.
class Operator;
struct SimplifiedOperatorBuilderImpl;
enum BaseTaggedness { kUntaggedBase, kTaggedBase };
// An access descriptor for loads/stores of fixed structures like field
......@@ -57,44 +60,8 @@ struct ElementAccess {
static const int kNonHeapObjectHeaderSize = kHeapObjectTag;
// Specialization for static parameters of type {FieldAccess}.
template <>
struct StaticParameterTraits<FieldAccess> {
static OStream& PrintTo(OStream& os, const FieldAccess& val) { // NOLINT
return os << val.offset;
}
static int HashCode(const FieldAccess& val) {
return (val.offset < 16) | (val.machine_type & 0xffff);
}
static bool Equals(const FieldAccess& lhs, const FieldAccess& rhs);
};
// Specialization for static parameters of type {ElementAccess}.
template <>
struct StaticParameterTraits<ElementAccess> {
static OStream& PrintTo(OStream& os, const ElementAccess& val) { // NOLINT
return os << val.header_size;
}
static int HashCode(const ElementAccess& val) {
return (val.header_size < 16) | (val.machine_type & 0xffff);
}
static bool Equals(const ElementAccess& lhs, const ElementAccess& rhs);
};
inline const FieldAccess FieldAccessOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kLoadField ||
op->opcode() == IrOpcode::kStoreField);
return OpParameter<FieldAccess>(op);
}
inline const ElementAccess ElementAccessOf(const Operator* op) {
DCHECK(op->opcode() == IrOpcode::kLoadElement ||
op->opcode() == IrOpcode::kStoreElement);
return OpParameter<ElementAccess>(op);
}
const FieldAccess& FieldAccessOf(const Operator* op) WARN_UNUSED_RESULT;
const ElementAccess& ElementAccessOf(const Operator* op) WARN_UNUSED_RESULT;
// Interface for building simplified operators, which represent the
......@@ -119,78 +86,55 @@ inline const ElementAccess ElementAccessOf(const Operator* op) {
// - Bool: a tagged pointer to either the canonical JS #false or
// the canonical JS #true object
// - Bit: an untagged integer 0 or 1, but word-sized
class SimplifiedOperatorBuilder {
class SimplifiedOperatorBuilder FINAL {
public:
explicit inline SimplifiedOperatorBuilder(Zone* zone) : zone_(zone) {}
#define SIMPLE(name, properties, inputs, outputs) \
return new (zone_) \
SimpleOperator(IrOpcode::k##name, properties, inputs, outputs, #name);
#define OP1(name, ptype, pname, properties, inputs, outputs) \
return new (zone_) \
Operator1<ptype>(IrOpcode::k##name, properties | Operator::kNoThrow, \
inputs, outputs, #name, pname)
#define UNOP(name) SIMPLE(name, Operator::kPure, 1, 1)
#define BINOP(name) SIMPLE(name, Operator::kPure, 2, 1)
const Operator* BooleanNot() const { UNOP(BooleanNot); }
const Operator* NumberEqual() const { BINOP(NumberEqual); }
const Operator* NumberLessThan() const { BINOP(NumberLessThan); }
const Operator* NumberLessThanOrEqual() const {
BINOP(NumberLessThanOrEqual);
}
const Operator* NumberAdd() const { BINOP(NumberAdd); }
const Operator* NumberSubtract() const { BINOP(NumberSubtract); }
const Operator* NumberMultiply() const { BINOP(NumberMultiply); }
const Operator* NumberDivide() const { BINOP(NumberDivide); }
const Operator* NumberModulus() const { BINOP(NumberModulus); }
const Operator* NumberToInt32() const { UNOP(NumberToInt32); }
const Operator* NumberToUint32() const { UNOP(NumberToUint32); }
const Operator* ReferenceEqual(Type* type) const { BINOP(ReferenceEqual); }
const Operator* StringEqual() const { BINOP(StringEqual); }
const Operator* StringLessThan() const { BINOP(StringLessThan); }
const Operator* StringLessThanOrEqual() const {
BINOP(StringLessThanOrEqual);
}
const Operator* StringAdd() const { BINOP(StringAdd); }
const Operator* ChangeTaggedToInt32() const { UNOP(ChangeTaggedToInt32); }
const Operator* ChangeTaggedToUint32() const { UNOP(ChangeTaggedToUint32); }
const Operator* ChangeTaggedToFloat64() const { UNOP(ChangeTaggedToFloat64); }
const Operator* ChangeInt32ToTagged() const { UNOP(ChangeInt32ToTagged); }
const Operator* ChangeUint32ToTagged() const { UNOP(ChangeUint32ToTagged); }
const Operator* ChangeFloat64ToTagged() const { UNOP(ChangeFloat64ToTagged); }
const Operator* ChangeBoolToBit() const { UNOP(ChangeBoolToBit); }
const Operator* ChangeBitToBool() const { UNOP(ChangeBitToBool); }
const Operator* LoadField(const FieldAccess& access) const {
OP1(LoadField, FieldAccess, access, Operator::kNoWrite, 1, 1);
}
const Operator* StoreField(const FieldAccess& access) const {
OP1(StoreField, FieldAccess, access, Operator::kNoRead, 2, 0);
}
const Operator* LoadElement(const ElementAccess& access) const {
OP1(LoadElement, ElementAccess, access, Operator::kNoWrite, 2, 1);
}
const Operator* StoreElement(const ElementAccess& access) const {
OP1(StoreElement, ElementAccess, access, Operator::kNoRead, 3, 0);
}
#undef BINOP
#undef UNOP
#undef OP1
#undef SIMPLE
explicit SimplifiedOperatorBuilder(Zone* zone);
const Operator* BooleanNot() const WARN_UNUSED_RESULT;
const Operator* NumberEqual() const WARN_UNUSED_RESULT;
const Operator* NumberLessThan() const WARN_UNUSED_RESULT;
const Operator* NumberLessThanOrEqual() const WARN_UNUSED_RESULT;
const Operator* NumberAdd() const WARN_UNUSED_RESULT;
const Operator* NumberSubtract() const WARN_UNUSED_RESULT;
const Operator* NumberMultiply() const WARN_UNUSED_RESULT;
const Operator* NumberDivide() const WARN_UNUSED_RESULT;
const Operator* NumberModulus() const WARN_UNUSED_RESULT;
const Operator* NumberToInt32() const WARN_UNUSED_RESULT;
const Operator* NumberToUint32() const WARN_UNUSED_RESULT;
const Operator* ReferenceEqual(Type* type) const WARN_UNUSED_RESULT;
const Operator* StringEqual() const WARN_UNUSED_RESULT;
const Operator* StringLessThan() const WARN_UNUSED_RESULT;
const Operator* StringLessThanOrEqual() const WARN_UNUSED_RESULT;
const Operator* StringAdd() const WARN_UNUSED_RESULT;
const Operator* ChangeTaggedToInt32() const WARN_UNUSED_RESULT;
const Operator* ChangeTaggedToUint32() const WARN_UNUSED_RESULT;
const Operator* ChangeTaggedToFloat64() const WARN_UNUSED_RESULT;
const Operator* ChangeInt32ToTagged() const WARN_UNUSED_RESULT;
const Operator* ChangeUint32ToTagged() const WARN_UNUSED_RESULT;
const Operator* ChangeFloat64ToTagged() const WARN_UNUSED_RESULT;
const Operator* ChangeBoolToBit() const WARN_UNUSED_RESULT;
const Operator* ChangeBitToBool() const WARN_UNUSED_RESULT;
const Operator* LoadField(const FieldAccess&) const WARN_UNUSED_RESULT;
const Operator* StoreField(const FieldAccess&) const WARN_UNUSED_RESULT;
const Operator* LoadElement(const ElementAccess&) const WARN_UNUSED_RESULT;
const Operator* StoreElement(const ElementAccess&) const WARN_UNUSED_RESULT;
private:
Zone* zone_;
Zone* zone() const { return zone_; }
const SimplifiedOperatorBuilderImpl& impl_;
Zone* const zone_;
DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorBuilder);
};
}
}
} // namespace v8::internal::compiler
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_SIMPLIFIED_OPERATOR_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment