blob: 8f288cba40689072cd3832f9987d82fd2fd60de3 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
3// found in the LICENSE file.
4
5#ifndef V8_COMPILER_OPERATOR_H_
6#define V8_COMPILER_OPERATOR_H_
7
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#include <ostream> // NOLINT(readability/streams)
9
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/base/flags.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/base/functional.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/handles.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013#include "src/zone.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014
15namespace v8 {
16namespace internal {
17namespace compiler {
18
19// An operator represents description of the "computation" of a node in the
20// compiler IR. A computation takes values (i.e. data) as input and produces
21// zero or more values as output. The side-effects of a computation must be
22// captured by additional control and data dependencies which are part of the
23// IR graph.
24// Operators are immutable and describe the statically-known parts of a
25// computation. Thus they can be safely shared by many different nodes in the
26// IR graph, or even globally between graphs. Operators can have "static
27// parameters" which are compile-time constant parameters to the operator, such
28// as the name for a named field access, the ID of a runtime function, etc.
29// Static parameters are private to the operator and only semantically
30// meaningful to the operator itself.
31class Operator : public ZoneObject {
32 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 typedef uint16_t Opcode;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034
35 // Properties inform the operator-independent optimizer about legal
36 // transformations for nodes that have this operator.
37 enum Property {
38 kNoProperties = 0,
Ben Murdoch61f157c2016-09-16 13:49:30 +010039 kCommutative = 1 << 0, // OP(a, b) == OP(b, a) for all inputs.
40 kAssociative = 1 << 1, // OP(a, OP(b,c)) == OP(OP(a,b), c) for all inputs.
41 kIdempotent = 1 << 2, // OP(a); OP(a) == OP(a).
42 kNoRead = 1 << 3, // Has no scheduling dependency on Effects
43 kNoWrite = 1 << 4, // Does not modify any Effects and thereby
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044 // create new scheduling dependencies.
Ben Murdoch61f157c2016-09-16 13:49:30 +010045 kNoThrow = 1 << 5, // Can never generate an exception.
46 kNoDeopt = 1 << 6, // Can never generate an eager deoptimization exit.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047 kFoldable = kNoRead | kNoWrite,
Ben Murdoch61f157c2016-09-16 13:49:30 +010048 kKontrol = kNoDeopt | kFoldable | kNoThrow,
49 kEliminatable = kNoDeopt | kNoWrite | kNoThrow,
50 kPure = kNoDeopt | kNoRead | kNoWrite | kNoThrow | kIdempotent
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 };
52 typedef base::Flags<Property, uint8_t> Properties;
53
Emily Bernierd0a1eb72015-03-24 16:35:39 -040054 // Constructor.
55 Operator(Opcode opcode, Properties properties, const char* mnemonic,
56 size_t value_in, size_t effect_in, size_t control_in,
57 size_t value_out, size_t effect_out, size_t control_out);
58
59 virtual ~Operator() {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060
61 // A small integer unique to all instances of a particular kind of operator,
62 // useful for quick matching for specific kinds of operators. For fast access
63 // the opcode is stored directly in the operator object.
64 Opcode opcode() const { return opcode_; }
65
66 // Returns a constant string representing the mnemonic of the operator,
67 // without the static parameters. Useful for debugging.
68 const char* mnemonic() const { return mnemonic_; }
69
70 // Check if this operator equals another operator. Equivalent operators can
71 // be merged, and nodes with equivalent operators and equivalent inputs
72 // can be merged.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040073 virtual bool Equals(const Operator* that) const {
74 return this->opcode() == that->opcode();
75 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000076
77 // Compute a hashcode to speed up equivalence-set checking.
78 // Equal operators should always have equal hashcodes, and unequal operators
79 // should have unequal hashcodes with high probability.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040080 virtual size_t HashCode() const { return base::hash<Opcode>()(opcode()); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081
82 // Check whether this operator has the given property.
83 bool HasProperty(Property property) const {
84 return (properties() & property) == property;
85 }
86
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087 Properties properties() const { return properties_; }
88
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000089 // TODO(bmeurer): Use bit fields below?
90 static const size_t kMaxControlOutputCount = (1u << 16) - 1;
91
Emily Bernierd0a1eb72015-03-24 16:35:39 -040092 // TODO(titzer): convert return values here to size_t.
93 int ValueInputCount() const { return value_in_; }
94 int EffectInputCount() const { return effect_in_; }
95 int ControlInputCount() const { return control_in_; }
96
97 int ValueOutputCount() const { return value_out_; }
98 int EffectOutputCount() const { return effect_out_; }
99 int ControlOutputCount() const { return control_out_; }
100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000101 static size_t ZeroIfEliminatable(Properties properties) {
102 return (properties & kEliminatable) == kEliminatable ? 0 : 1;
103 }
104
105 static size_t ZeroIfNoThrow(Properties properties) {
106 return (properties & kNoThrow) == kNoThrow ? 0 : 2;
107 }
108
109 static size_t ZeroIfPure(Properties properties) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400110 return (properties & kPure) == kPure ? 0 : 1;
111 }
112
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 // TODO(titzer): API for input and output types, for typechecking graph.
114 protected:
115 // Print the full operator into the given stream, including any
116 // static parameters. Useful for debugging and visualizing the IR.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400117 virtual void PrintTo(std::ostream& os) const;
118 friend std::ostream& operator<<(std::ostream& os, const Operator& op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119
120 private:
121 Opcode opcode_;
122 Properties properties_;
123 const char* mnemonic_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124 uint32_t value_in_;
125 uint16_t effect_in_;
126 uint16_t control_in_;
127 uint16_t value_out_;
128 uint8_t effect_out_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129 uint16_t control_out_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000130
131 DISALLOW_COPY_AND_ASSIGN(Operator);
132};
133
134DEFINE_OPERATORS_FOR_FLAGS(Operator::Properties)
135
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400136std::ostream& operator<<(std::ostream& os, const Operator& op);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000137
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139// Default equality function for below Operator1<*> class.
140template <typename T>
141struct OpEqualTo : public std::equal_to<T> {};
142
143
144// Default hashing function for below Operator1<*> class.
145template <typename T>
146struct OpHash : public base::hash<T> {};
147
148
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000149// A templatized implementation of Operator that has one static parameter of
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150// type {T} with the proper default equality and hashing functions.
151template <typename T, typename Pred = OpEqualTo<T>, typename Hash = OpHash<T>>
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152class Operator1 : public Operator {
153 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 Operator1(Opcode opcode, Properties properties, const char* mnemonic,
155 size_t value_in, size_t effect_in, size_t control_in,
156 size_t value_out, size_t effect_out, size_t control_out,
157 T parameter, Pred const& pred = Pred(), Hash const& hash = Hash())
158 : Operator(opcode, properties, mnemonic, value_in, effect_in, control_in,
159 value_out, effect_out, control_out),
160 parameter_(parameter),
161 pred_(pred),
162 hash_(hash) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400164 T const& parameter() const { return parameter_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 bool Equals(const Operator* other) const final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 if (opcode() != other->opcode()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168 const Operator1<T, Pred, Hash>* that =
169 reinterpret_cast<const Operator1<T, Pred, Hash>*>(other);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400170 return this->pred_(this->parameter(), that->parameter());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 size_t HashCode() const final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400173 return base::hash_combine(this->opcode(), this->hash_(this->parameter()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175 virtual void PrintParameter(std::ostream& os) const {
176 os << "[" << this->parameter() << "]";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000177 }
178
179 protected:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180 void PrintTo(std::ostream& os) const final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400181 os << mnemonic();
182 PrintParameter(os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000183 }
184
185 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400186 T const parameter_;
187 Pred const pred_;
188 Hash const hash_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189};
190
191
192// Helper to extract parameters from Operator1<*> operator.
193template <typename T>
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400194inline T const& OpParameter(const Operator* op) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195 return reinterpret_cast<const Operator1<T, OpEqualTo<T>, OpHash<T>>*>(op)
196 ->parameter();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400197}
198
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000199
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400200// NOTE: We have to be careful to use the right equal/hash functions below, for
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201// float/double we always use the ones operating on the bit level, for Handle<>
202// we always use the ones operating on the location level.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400203template <>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204struct OpEqualTo<float> : public base::bit_equal_to<float> {};
205template <>
206struct OpHash<float> : public base::bit_hash<float> {};
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400207
208template <>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209struct OpEqualTo<double> : public base::bit_equal_to<double> {};
210template <>
211struct OpHash<double> : public base::bit_hash<double> {};
212
213template <>
214struct OpEqualTo<Handle<HeapObject>> : public Handle<HeapObject>::equal_to {};
215template <>
216struct OpHash<Handle<HeapObject>> : public Handle<HeapObject>::hash {};
217
218template <>
219struct OpEqualTo<Handle<String>> : public Handle<String>::equal_to {};
220template <>
221struct OpHash<Handle<String>> : public Handle<String>::hash {};
222
223template <>
224struct OpEqualTo<Handle<ScopeInfo>> : public Handle<ScopeInfo>::equal_to {};
225template <>
226struct OpHash<Handle<ScopeInfo>> : public Handle<ScopeInfo>::hash {};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227
228} // namespace compiler
229} // namespace internal
230} // namespace v8
231
232#endif // V8_COMPILER_OPERATOR_H_