OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_COMPILER_OPERATOR_H_ | 5 #ifndef V8_COMPILER_OPERATOR_H_ |
6 #define V8_COMPILER_OPERATOR_H_ | 6 #define V8_COMPILER_OPERATOR_H_ |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/base/flags.h" |
9 | |
10 #include "src/assembler.h" | |
11 #include "src/ostreams.h" | 9 #include "src/ostreams.h" |
12 #include "src/unique.h" | 10 #include "src/unique.h" |
13 | 11 |
14 namespace v8 { | 12 namespace v8 { |
15 namespace internal { | 13 namespace internal { |
| 14 |
| 15 // Forward declarations. |
| 16 class ExternalReference; |
| 17 |
| 18 |
16 namespace compiler { | 19 namespace compiler { |
17 | 20 |
18 // An operator represents description of the "computation" of a node in the | 21 // An operator represents description of the "computation" of a node in the |
19 // compiler IR. A computation takes values (i.e. data) as input and produces | 22 // compiler IR. A computation takes values (i.e. data) as input and produces |
20 // zero or more values as output. The side-effects of a computation must be | 23 // zero or more values as output. The side-effects of a computation must be |
21 // captured by additional control and data dependencies which are part of the | 24 // captured by additional control and data dependencies which are part of the |
22 // IR graph. | 25 // IR graph. |
23 // Operators are immutable and describe the statically-known parts of a | 26 // Operators are immutable and describe the statically-known parts of a |
24 // computation. Thus they can be safely shared by many different nodes in the | 27 // computation. Thus they can be safely shared by many different nodes in the |
25 // IR graph, or even globally between graphs. Operators can have "static | 28 // IR graph, or even globally between graphs. Operators can have "static |
26 // parameters" which are compile-time constant parameters to the operator, such | 29 // parameters" which are compile-time constant parameters to the operator, such |
27 // as the name for a named field access, the ID of a runtime function, etc. | 30 // as the name for a named field access, the ID of a runtime function, etc. |
28 // Static parameters are private to the operator and only semantically | 31 // Static parameters are private to the operator and only semantically |
29 // meaningful to the operator itself. | 32 // meaningful to the operator itself. |
30 class Operator : public ZoneObject { | 33 class Operator : public ZoneObject { |
31 public: | 34 public: |
32 Operator(uint8_t opcode, uint16_t properties) | 35 typedef uint8_t Opcode; |
33 : opcode_(opcode), properties_(properties) {} | |
34 virtual ~Operator() {} | |
35 | 36 |
36 // Properties inform the operator-independent optimizer about legal | 37 // Properties inform the operator-independent optimizer about legal |
37 // transformations for nodes that have this operator. | 38 // transformations for nodes that have this operator. |
38 enum Property { | 39 enum Property { |
39 kNoProperties = 0, | 40 kNoProperties = 0, |
40 kReducible = 1 << 0, // Participates in strength reduction. | 41 kReducible = 1 << 0, // Participates in strength reduction. |
41 kCommutative = 1 << 1, // OP(a, b) == OP(b, a) for all inputs. | 42 kCommutative = 1 << 1, // OP(a, b) == OP(b, a) for all inputs. |
42 kAssociative = 1 << 2, // OP(a, OP(b,c)) == OP(OP(a,b), c) for all inputs. | 43 kAssociative = 1 << 2, // OP(a, OP(b,c)) == OP(OP(a,b), c) for all inputs. |
43 kIdempotent = 1 << 3, // OP(a); OP(a) == OP(a). | 44 kIdempotent = 1 << 3, // OP(a); OP(a) == OP(a). |
44 kNoRead = 1 << 4, // Has no scheduling dependency on Effects | 45 kNoRead = 1 << 4, // Has no scheduling dependency on Effects |
45 kNoWrite = 1 << 5, // Does not modify any Effects and thereby | 46 kNoWrite = 1 << 5, // Does not modify any Effects and thereby |
46 // create new scheduling dependencies. | 47 // create new scheduling dependencies. |
47 kNoThrow = 1 << 6, // Can never generate an exception. | 48 kNoThrow = 1 << 6, // Can never generate an exception. |
48 kFoldable = kNoRead | kNoWrite, | 49 kFoldable = kNoRead | kNoWrite, |
49 kEliminatable = kNoWrite | kNoThrow, | 50 kEliminatable = kNoWrite | kNoThrow, |
50 kPure = kNoRead | kNoWrite | kNoThrow | kIdempotent | 51 kPure = kNoRead | kNoWrite | kNoThrow | kIdempotent |
51 }; | 52 }; |
| 53 typedef base::Flags<Property, uint8_t> Properties; |
| 54 |
| 55 Operator(Opcode opcode, Properties properties, const char* mnemonic) |
| 56 : opcode_(opcode), properties_(properties), mnemonic_(mnemonic) {} |
| 57 virtual ~Operator(); |
52 | 58 |
53 // A small integer unique to all instances of a particular kind of operator, | 59 // A small integer unique to all instances of a particular kind of operator, |
54 // useful for quick matching for specific kinds of operators. For fast access | 60 // useful for quick matching for specific kinds of operators. For fast access |
55 // the opcode is stored directly in the operator object. | 61 // the opcode is stored directly in the operator object. |
56 inline uint8_t opcode() const { return opcode_; } | 62 Opcode opcode() const { return opcode_; } |
57 | 63 |
58 // Returns a constant string representing the mnemonic of the operator, | 64 // Returns a constant string representing the mnemonic of the operator, |
59 // without the static parameters. Useful for debugging. | 65 // without the static parameters. Useful for debugging. |
60 virtual const char* mnemonic() = 0; | 66 const char* mnemonic() const { return mnemonic_; } |
61 | 67 |
62 // Check if this operator equals another operator. Equivalent operators can | 68 // Check if this operator equals another operator. Equivalent operators can |
63 // be merged, and nodes with equivalent operators and equivalent inputs | 69 // be merged, and nodes with equivalent operators and equivalent inputs |
64 // can be merged. | 70 // can be merged. |
65 virtual bool Equals(Operator* other) = 0; | 71 virtual bool Equals(const Operator* other) const = 0; |
66 | 72 |
67 // Compute a hashcode to speed up equivalence-set checking. | 73 // Compute a hashcode to speed up equivalence-set checking. |
68 // Equal operators should always have equal hashcodes, and unequal operators | 74 // Equal operators should always have equal hashcodes, and unequal operators |
69 // should have unequal hashcodes with high probability. | 75 // should have unequal hashcodes with high probability. |
70 virtual int HashCode() = 0; | 76 virtual int HashCode() const = 0; |
71 | 77 |
72 // Check whether this operator has the given property. | 78 // Check whether this operator has the given property. |
73 inline bool HasProperty(Property property) const { | 79 bool HasProperty(Property property) const { |
74 return (properties_ & static_cast<int>(property)) == property; | 80 return (properties() & property) == property; |
75 } | 81 } |
76 | 82 |
77 // Number of data inputs to the operator, for verifying graph structure. | 83 // Number of data inputs to the operator, for verifying graph structure. |
78 virtual int InputCount() = 0; | 84 virtual int InputCount() const = 0; |
79 | 85 |
80 // Number of data outputs from the operator, for verifying graph structure. | 86 // Number of data outputs from the operator, for verifying graph structure. |
81 virtual int OutputCount() = 0; | 87 virtual int OutputCount() const = 0; |
82 | 88 |
83 inline Property properties() { return static_cast<Property>(properties_); } | 89 Properties properties() const { return properties_; } |
84 | 90 |
85 // TODO(titzer): API for input and output types, for typechecking graph. | 91 // TODO(titzer): API for input and output types, for typechecking graph. |
86 private: | 92 protected: |
87 // Print the full operator into the given stream, including any | 93 // Print the full operator into the given stream, including any |
88 // static parameters. Useful for debugging and visualizing the IR. | 94 // static parameters. Useful for debugging and visualizing the IR. |
89 virtual OStream& PrintTo(OStream& os) const = 0; // NOLINT | 95 virtual OStream& PrintTo(OStream& os) const = 0; // NOLINT |
90 friend OStream& operator<<(OStream& os, const Operator& op); | 96 friend OStream& operator<<(OStream& os, const Operator& op); |
91 | 97 |
92 uint8_t opcode_; | 98 private: |
93 uint16_t properties_; | 99 Opcode opcode_; |
| 100 Properties properties_; |
| 101 const char* mnemonic_; |
| 102 |
| 103 DISALLOW_COPY_AND_ASSIGN(Operator); |
94 }; | 104 }; |
95 | 105 |
| 106 DEFINE_OPERATORS_FOR_FLAGS(Operator::Properties) |
| 107 |
96 OStream& operator<<(OStream& os, const Operator& op); | 108 OStream& operator<<(OStream& os, const Operator& op); |
97 | 109 |
98 // An implementation of Operator that has no static parameters. Such operators | 110 // An implementation of Operator that has no static parameters. Such operators |
99 // have just a name, an opcode, and a fixed number of inputs and outputs. | 111 // have just a name, an opcode, and a fixed number of inputs and outputs. |
100 // They can represented by singletons and shared globally. | 112 // They can represented by singletons and shared globally. |
101 class SimpleOperator : public Operator { | 113 class SimpleOperator FINAL : public Operator { |
102 public: | 114 public: |
103 SimpleOperator(uint8_t opcode, uint16_t properties, int input_count, | 115 SimpleOperator(Opcode opcode, Properties properties, int input_count, |
104 int output_count, const char* mnemonic) | 116 int output_count, const char* mnemonic); |
105 : Operator(opcode, properties), | 117 ~SimpleOperator(); |
106 input_count_(input_count), | |
107 output_count_(output_count), | |
108 mnemonic_(mnemonic) {} | |
109 | 118 |
110 virtual const char* mnemonic() { return mnemonic_; } | 119 virtual bool Equals(const Operator* that) const OVERRIDE { |
111 virtual bool Equals(Operator* that) { return opcode() == that->opcode(); } | 120 return opcode() == that->opcode(); |
112 virtual int HashCode() { return opcode(); } | 121 } |
113 virtual int InputCount() { return input_count_; } | 122 virtual int HashCode() const OVERRIDE { return opcode(); } |
114 virtual int OutputCount() { return output_count_; } | 123 virtual int InputCount() const OVERRIDE { return input_count_; } |
| 124 virtual int OutputCount() const OVERRIDE { return output_count_; } |
115 | 125 |
116 private: | 126 private: |
117 virtual OStream& PrintTo(OStream& os) const { // NOLINT | 127 virtual OStream& PrintTo(OStream& os) const OVERRIDE { // NOLINT |
118 return os << mnemonic_; | 128 return os << mnemonic(); |
119 } | 129 } |
120 | 130 |
121 int input_count_; | 131 int input_count_; |
122 int output_count_; | 132 int output_count_; |
123 const char* mnemonic_; | 133 |
| 134 DISALLOW_COPY_AND_ASSIGN(SimpleOperator); |
124 }; | 135 }; |
125 | 136 |
126 // Template specialization implements a kind of type class for dealing with the | 137 // Template specialization implements a kind of type class for dealing with the |
127 // static parameters of Operator1 automatically. | 138 // static parameters of Operator1 automatically. |
128 template <typename T> | 139 template <typename T> |
129 struct StaticParameterTraits { | 140 struct StaticParameterTraits { |
130 static OStream& PrintTo(OStream& os, T val) { // NOLINT | 141 static OStream& PrintTo(OStream& os, T val) { // NOLINT |
131 return os << "??"; | 142 return os << "??"; |
132 } | 143 } |
133 static int HashCode(T a) { return 0; } | 144 static int HashCode(T a) { return 0; } |
134 static bool Equals(T a, T b) { | 145 static bool Equals(T a, T b) { |
135 return false; // Not every T has a ==. By default, be conservative. | 146 return false; // Not every T has a ==. By default, be conservative. |
136 } | 147 } |
137 }; | 148 }; |
138 | 149 |
139 template <> | 150 template <> |
140 struct StaticParameterTraits<ExternalReference> { | 151 struct StaticParameterTraits<ExternalReference> { |
141 static OStream& PrintTo(OStream& os, ExternalReference val) { // NOLINT | 152 static OStream& PrintTo(OStream& os, ExternalReference reference); // NOLINT |
142 os << val.address(); | 153 static int HashCode(ExternalReference reference); |
143 const Runtime::Function* function = | 154 static bool Equals(ExternalReference lhs, ExternalReference rhs); |
144 Runtime::FunctionForEntry(val.address()); | |
145 if (function != NULL) { | |
146 os << " <" << function->name << ".entry>"; | |
147 } | |
148 return os; | |
149 } | |
150 static int HashCode(ExternalReference a) { | |
151 return reinterpret_cast<intptr_t>(a.address()) & 0xFFFFFFFF; | |
152 } | |
153 static bool Equals(ExternalReference a, ExternalReference b) { | |
154 return a == b; | |
155 } | |
156 }; | 155 }; |
157 | 156 |
158 // Specialization for static parameters of type {int}. | 157 // Specialization for static parameters of type {int}. |
159 template <> | 158 template <> |
160 struct StaticParameterTraits<int> { | 159 struct StaticParameterTraits<int> { |
161 static OStream& PrintTo(OStream& os, int val) { // NOLINT | 160 static OStream& PrintTo(OStream& os, int val) { // NOLINT |
162 return os << val; | 161 return os << val; |
163 } | 162 } |
164 static int HashCode(int a) { return a; } | 163 static int HashCode(int a) { return a; } |
165 static bool Equals(int a, int b) { return a == b; } | 164 static bool Equals(int a, int b) { return a == b; } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 } | 225 } |
227 }; | 226 }; |
228 #endif | 227 #endif |
229 | 228 |
230 // A templatized implementation of Operator that has one static parameter of | 229 // A templatized implementation of Operator that has one static parameter of |
231 // type {T}. If a specialization of StaticParameterTraits<{T}> exists, then | 230 // type {T}. If a specialization of StaticParameterTraits<{T}> exists, then |
232 // operators of this kind can automatically be hashed, compared, and printed. | 231 // operators of this kind can automatically be hashed, compared, and printed. |
233 template <typename T> | 232 template <typename T> |
234 class Operator1 : public Operator { | 233 class Operator1 : public Operator { |
235 public: | 234 public: |
236 Operator1(uint8_t opcode, uint16_t properties, int input_count, | 235 Operator1(Opcode opcode, Properties properties, int input_count, |
237 int output_count, const char* mnemonic, T parameter) | 236 int output_count, const char* mnemonic, T parameter) |
238 : Operator(opcode, properties), | 237 : Operator(opcode, properties, mnemonic), |
239 input_count_(input_count), | 238 input_count_(input_count), |
240 output_count_(output_count), | 239 output_count_(output_count), |
241 mnemonic_(mnemonic), | |
242 parameter_(parameter) {} | 240 parameter_(parameter) {} |
243 | 241 |
244 const T& parameter() const { return parameter_; } | 242 const T& parameter() const { return parameter_; } |
245 | 243 |
246 virtual const char* mnemonic() { return mnemonic_; } | 244 virtual bool Equals(const Operator* other) const OVERRIDE { |
247 virtual bool Equals(Operator* other) { | |
248 if (opcode() != other->opcode()) return false; | 245 if (opcode() != other->opcode()) return false; |
249 Operator1<T>* that = static_cast<Operator1<T>*>(other); | 246 const Operator1<T>* that = static_cast<const Operator1<T>*>(other); |
250 T temp1 = this->parameter_; | 247 return StaticParameterTraits<T>::Equals(this->parameter_, that->parameter_); |
251 T temp2 = that->parameter_; | |
252 return StaticParameterTraits<T>::Equals(temp1, temp2); | |
253 } | 248 } |
254 virtual int HashCode() { | 249 virtual int HashCode() const OVERRIDE { |
255 return opcode() + 33 * StaticParameterTraits<T>::HashCode(this->parameter_); | 250 return opcode() + 33 * StaticParameterTraits<T>::HashCode(this->parameter_); |
256 } | 251 } |
257 virtual int InputCount() { return input_count_; } | 252 virtual int InputCount() const OVERRIDE { return input_count_; } |
258 virtual int OutputCount() { return output_count_; } | 253 virtual int OutputCount() const OVERRIDE { return output_count_; } |
259 virtual OStream& PrintParameter(OStream& os) const { // NOLINT | 254 virtual OStream& PrintParameter(OStream& os) const { // NOLINT |
260 return StaticParameterTraits<T>::PrintTo(os << "[", parameter_) << "]"; | 255 return StaticParameterTraits<T>::PrintTo(os << "[", parameter_) << "]"; |
261 } | 256 } |
262 | 257 |
263 private: | 258 protected: |
264 virtual OStream& PrintTo(OStream& os) const { // NOLINT | 259 virtual OStream& PrintTo(OStream& os) const FINAL { // NOLINT |
265 return PrintParameter(os << mnemonic_); | 260 return PrintParameter(os << mnemonic()); |
266 } | 261 } |
267 | 262 |
| 263 private: |
268 int input_count_; | 264 int input_count_; |
269 int output_count_; | 265 int output_count_; |
270 const char* mnemonic_; | |
271 T parameter_; | 266 T parameter_; |
272 }; | 267 }; |
273 | 268 |
274 // Type definitions for operators with specific types of parameters. | 269 // Type definitions for operators with specific types of parameters. |
275 typedef Operator1<PrintableUnique<Name> > NameOperator; | 270 typedef Operator1<PrintableUnique<Name> > NameOperator; |
276 } | 271 |
277 } | 272 } // namespace compiler |
278 } // namespace v8::internal::compiler | 273 } // namespace internal |
| 274 } // namespace v8 |
279 | 275 |
280 #endif // V8_COMPILER_OPERATOR_H_ | 276 #endif // V8_COMPILER_OPERATOR_H_ |
OLD | NEW |