From 78f3df63c65cadaf44790bd69ab09c161e6cb8f5 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Fri, 12 Sep 2014 07:06:50 +0000 Subject: [PATCH] [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 --- src/compiler/compiler.gyp | 1 + .../simplified-operator-reducer-unittest.cc | 3 +- src/compiler/simplified-operator-unittest.cc | 117 +++++++++++++++ src/compiler/simplified-operator.cc | 139 +++++++++++++++-- src/compiler/simplified-operator.h | 166 +++++++-------------- 5 files changed, 303 insertions(+), 123 deletions(-) create mode 100644 src/compiler/simplified-operator-unittest.cc diff --git a/src/compiler/compiler.gyp b/src/compiler/compiler.gyp index 605add3..fc19168 100644 --- a/src/compiler/compiler.gyp +++ b/src/compiler/compiler.gyp @@ -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': [ diff --git a/src/compiler/simplified-operator-reducer-unittest.cc b/src/compiler/simplified-operator-reducer-unittest.cc index 9ab8109..21b7b71 100644 --- a/src/compiler/simplified-operator-reducer-unittest.cc +++ b/src/compiler/simplified-operator-reducer-unittest.cc @@ -166,7 +166,8 @@ TEST_P(SimplifiedUnaryOperatorTest, Parameter) { } -INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedUnaryOperatorTest, +INSTANTIATE_TEST_CASE_P(SimplifiedOperatorReducerTest, + SimplifiedUnaryOperatorTest, ::testing::ValuesIn(kUnaryOperators)); diff --git a/src/compiler/simplified-operator-unittest.cc b/src/compiler/simplified-operator-unittest.cc new file mode 100644 index 0000000..e6e7acc --- /dev/null +++ b/src/compiler/simplified-operator-unittest.cc @@ -0,0 +1,117 @@ +// 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 {}; + + +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 diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc index 12d56a9..16ae8ff 100644 --- a/src/compiler/simplified-operator.cc +++ b/src/compiler/simplified-operator.cc @@ -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::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(op); +} + + +const ElementAccess& ElementAccessOf(const Operator* op) { + DCHECK_NOT_NULL(op); + DCHECK(op->opcode() == IrOpcode::kLoadElement || + op->opcode() == IrOpcode::kStoreElement); + return OpParameter(op); } -// static -bool StaticParameterTraits::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 { + 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 { + 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::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(IrOpcode::k##Name, Operator::kNoThrow | properties, \ + input_count, output_count, #Name, access); \ + } +ACCESS_OP_LIST(ACCESS) +#undef ACCESS + } // namespace compiler } // namespace internal } // namespace v8 diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index b56b632..01fd6e7 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -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 TypeImpl; struct ZoneTypeConfig; typedef TypeImpl 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 { - 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 { - 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(op); -} - - -inline const ElementAccess ElementAccessOf(const Operator* op) { - DCHECK(op->opcode() == IrOpcode::kLoadElement || - op->opcode() == IrOpcode::kStoreElement); - return OpParameter(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(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_ -- 2.7.4