[turbofan] Most simplified operators are globally shared singletons.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Fri, 12 Sep 2014 07:06:50 +0000 (07:06 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Fri, 12 Sep 2014 07:06:50 +0000 (07:06 +0000)
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
src/compiler/simplified-operator-reducer-unittest.cc
src/compiler/simplified-operator-unittest.cc [new file with mode: 0644]
src/compiler/simplified-operator.cc
src/compiler/simplified-operator.h

index 605add3..fc19168 100644 (file)
@@ -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': [
index 9ab8109..21b7b71 100644 (file)
@@ -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 (file)
index 0000000..e6e7acc
--- /dev/null
@@ -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<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
index 12d56a9..16ae8ff 100644 (file)
 // 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
index b56b632..01fd6e7 100644 (file)
@@ -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_