1 // Copyright 2012 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 #include "src/compiler/simplified-operator.h"
6
7 #include "src/base/lazy-instance.h"
8 #include "src/compiler/opcodes.h"
9 #include "src/compiler/operator.h"
10 #include "src/types-inl.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
operator <<(std::ostream & os,BaseTaggedness base_taggedness)16 std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
17 switch (base_taggedness) {
18 case kUntaggedBase:
19 return os << "untagged base";
20 case kTaggedBase:
21 return os << "tagged base";
22 }
23 UNREACHABLE();
24 return os;
25 }
26
27
machine_type() const28 MachineType BufferAccess::machine_type() const {
29 switch (external_array_type_) {
30 case kExternalUint8Array:
31 case kExternalUint8ClampedArray:
32 return MachineType::Uint8();
33 case kExternalInt8Array:
34 return MachineType::Int8();
35 case kExternalUint16Array:
36 return MachineType::Uint16();
37 case kExternalInt16Array:
38 return MachineType::Int16();
39 case kExternalUint32Array:
40 return MachineType::Uint32();
41 case kExternalInt32Array:
42 return MachineType::Int32();
43 case kExternalFloat32Array:
44 return MachineType::Float32();
45 case kExternalFloat64Array:
46 return MachineType::Float64();
47 }
48 UNREACHABLE();
49 return MachineType::None();
50 }
51
52
operator ==(BufferAccess lhs,BufferAccess rhs)53 bool operator==(BufferAccess lhs, BufferAccess rhs) {
54 return lhs.external_array_type() == rhs.external_array_type();
55 }
56
57
operator !=(BufferAccess lhs,BufferAccess rhs)58 bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
59
60
hash_value(BufferAccess access)61 size_t hash_value(BufferAccess access) {
62 return base::hash<ExternalArrayType>()(access.external_array_type());
63 }
64
65
operator <<(std::ostream & os,BufferAccess access)66 std::ostream& operator<<(std::ostream& os, BufferAccess access) {
67 switch (access.external_array_type()) {
68 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
69 case kExternal##Type##Array: \
70 return os << #Type;
71 TYPED_ARRAYS(TYPED_ARRAY_CASE)
72 #undef TYPED_ARRAY_CASE
73 }
74 UNREACHABLE();
75 return os;
76 }
77
78
BufferAccessOf(const Operator * op)79 BufferAccess const BufferAccessOf(const Operator* op) {
80 DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
81 op->opcode() == IrOpcode::kStoreBuffer);
82 return OpParameter<BufferAccess>(op);
83 }
84
85
operator ==(FieldAccess const & lhs,FieldAccess const & rhs)86 bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
87 return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
88 lhs.machine_type == rhs.machine_type;
89 }
90
91
operator !=(FieldAccess const & lhs,FieldAccess const & rhs)92 bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
93 return !(lhs == rhs);
94 }
95
96
hash_value(FieldAccess const & access)97 size_t hash_value(FieldAccess const& access) {
98 return base::hash_combine(access.base_is_tagged, access.offset,
99 access.machine_type);
100 }
101
102
operator <<(std::ostream & os,FieldAccess const & access)103 std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
104 os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
105 #ifdef OBJECT_PRINT
106 Handle<Name> name;
107 if (access.name.ToHandle(&name)) {
108 name->Print(os);
109 os << ", ";
110 }
111 #endif
112 access.type->PrintTo(os);
113 os << ", " << access.machine_type << "]";
114 return os;
115 }
116
117
operator ==(ElementAccess const & lhs,ElementAccess const & rhs)118 bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
119 return lhs.base_is_tagged == rhs.base_is_tagged &&
120 lhs.header_size == rhs.header_size &&
121 lhs.machine_type == rhs.machine_type;
122 }
123
124
operator !=(ElementAccess const & lhs,ElementAccess const & rhs)125 bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
126 return !(lhs == rhs);
127 }
128
129
hash_value(ElementAccess const & access)130 size_t hash_value(ElementAccess const& access) {
131 return base::hash_combine(access.base_is_tagged, access.header_size,
132 access.machine_type);
133 }
134
135
operator <<(std::ostream & os,ElementAccess const & access)136 std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
137 os << access.base_is_tagged << ", " << access.header_size << ", ";
138 access.type->PrintTo(os);
139 os << ", " << access.machine_type;
140 return os;
141 }
142
143
FieldAccessOf(const Operator * op)144 const FieldAccess& FieldAccessOf(const Operator* op) {
145 DCHECK_NOT_NULL(op);
146 DCHECK(op->opcode() == IrOpcode::kLoadField ||
147 op->opcode() == IrOpcode::kStoreField);
148 return OpParameter<FieldAccess>(op);
149 }
150
151
ElementAccessOf(const Operator * op)152 const ElementAccess& ElementAccessOf(const Operator* op) {
153 DCHECK_NOT_NULL(op);
154 DCHECK(op->opcode() == IrOpcode::kLoadElement ||
155 op->opcode() == IrOpcode::kStoreElement);
156 return OpParameter<ElementAccess>(op);
157 }
158
159
160 #define PURE_OP_LIST(V) \
161 V(BooleanNot, Operator::kNoProperties, 1) \
162 V(BooleanToNumber, Operator::kNoProperties, 1) \
163 V(NumberEqual, Operator::kCommutative, 2) \
164 V(NumberLessThan, Operator::kNoProperties, 2) \
165 V(NumberLessThanOrEqual, Operator::kNoProperties, 2) \
166 V(NumberAdd, Operator::kCommutative, 2) \
167 V(NumberSubtract, Operator::kNoProperties, 2) \
168 V(NumberMultiply, Operator::kCommutative, 2) \
169 V(NumberDivide, Operator::kNoProperties, 2) \
170 V(NumberModulus, Operator::kNoProperties, 2) \
171 V(NumberBitwiseOr, Operator::kCommutative, 2) \
172 V(NumberBitwiseXor, Operator::kCommutative, 2) \
173 V(NumberBitwiseAnd, Operator::kCommutative, 2) \
174 V(NumberShiftLeft, Operator::kNoProperties, 2) \
175 V(NumberShiftRight, Operator::kNoProperties, 2) \
176 V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
177 V(NumberToInt32, Operator::kNoProperties, 1) \
178 V(NumberToUint32, Operator::kNoProperties, 1) \
179 V(NumberIsHoleNaN, Operator::kNoProperties, 1) \
180 V(PlainPrimitiveToNumber, Operator::kNoProperties, 1) \
181 V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
182 V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
183 V(ChangeTaggedToFloat64, Operator::kNoProperties, 1) \
184 V(ChangeInt32ToTagged, Operator::kNoProperties, 1) \
185 V(ChangeUint32ToTagged, Operator::kNoProperties, 1) \
186 V(ChangeFloat64ToTagged, Operator::kNoProperties, 1) \
187 V(ChangeBoolToBit, Operator::kNoProperties, 1) \
188 V(ChangeBitToBool, Operator::kNoProperties, 1) \
189 V(ObjectIsNumber, Operator::kNoProperties, 1) \
190 V(ObjectIsSmi, Operator::kNoProperties, 1)
191
192 #define NO_THROW_OP_LIST(V) \
193 V(StringEqual, Operator::kCommutative, 2) \
194 V(StringLessThan, Operator::kNoThrow, 2) \
195 V(StringLessThanOrEqual, Operator::kNoThrow, 2)
196
197 struct SimplifiedOperatorGlobalCache final {
198 #define PURE(Name, properties, input_count) \
199 struct Name##Operator final : public Operator { \
200 Name##Operator() \
201 : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
202 input_count, 0, 0, 1, 0, 0) {} \
203 }; \
204 Name##Operator k##Name;
205 PURE_OP_LIST(PURE)
206 #undef PURE
207
208 #define NO_THROW(Name, properties, input_count) \
209 struct Name##Operator final : public Operator { \
210 Name##Operator() \
211 : Operator(IrOpcode::k##Name, Operator::kNoThrow | properties, #Name, \
212 input_count, 1, 1, 1, 1, 0) {} \
213 }; \
214 Name##Operator k##Name;
215 NO_THROW_OP_LIST(NO_THROW)
216 #undef NO_THROW
217
218 #define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
219 struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
220 LoadBuffer##Type##Operator() \
221 : Operator1<BufferAccess>(IrOpcode::kLoadBuffer, \
222 Operator::kNoThrow | Operator::kNoWrite, \
223 "LoadBuffer", 3, 1, 1, 1, 1, 0, \
224 BufferAccess(kExternal##Type##Array)) {} \
225 }; \
226 struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
227 StoreBuffer##Type##Operator() \
228 : Operator1<BufferAccess>(IrOpcode::kStoreBuffer, \
229 Operator::kNoRead | Operator::kNoThrow, \
230 "StoreBuffer", 4, 1, 1, 0, 1, 0, \
231 BufferAccess(kExternal##Type##Array)) {} \
232 }; \
233 LoadBuffer##Type##Operator kLoadBuffer##Type; \
234 StoreBuffer##Type##Operator kStoreBuffer##Type;
235 TYPED_ARRAYS(BUFFER_ACCESS)
236 #undef BUFFER_ACCESS
237 };
238
239
240 static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
241 LAZY_INSTANCE_INITIALIZER;
242
243
SimplifiedOperatorBuilder(Zone * zone)244 SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
245 : cache_(kCache.Get()), zone_(zone) {}
246
247
248 #define GET_FROM_CACHE(Name, properties, input_count) \
249 const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
250 PURE_OP_LIST(GET_FROM_CACHE)
NO_THROW_OP_LIST(GET_FROM_CACHE) const251 NO_THROW_OP_LIST(GET_FROM_CACHE)
252 #undef GET_FROM_CACHE
253
254
255 const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
256 // TODO(titzer): What about the type parameter?
257 return new (zone()) Operator(IrOpcode::kReferenceEqual,
258 Operator::kCommutative | Operator::kPure,
259 "ReferenceEqual", 2, 0, 0, 1, 0, 0);
260 }
261
262
Allocate(PretenureFlag pretenure)263 const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
264 return new (zone())
265 Operator1<PretenureFlag>(IrOpcode::kAllocate, Operator::kNoThrow,
266 "Allocate", 1, 1, 1, 1, 1, 0, pretenure);
267 }
268
269
LoadBuffer(BufferAccess access)270 const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
271 switch (access.external_array_type()) {
272 #define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
273 case kExternal##Type##Array: \
274 return &cache_.kLoadBuffer##Type;
275 TYPED_ARRAYS(LOAD_BUFFER)
276 #undef LOAD_BUFFER
277 }
278 UNREACHABLE();
279 return nullptr;
280 }
281
282
StoreBuffer(BufferAccess access)283 const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
284 switch (access.external_array_type()) {
285 #define STORE_BUFFER(Type, type, TYPE, ctype, size) \
286 case kExternal##Type##Array: \
287 return &cache_.kStoreBuffer##Type;
288 TYPED_ARRAYS(STORE_BUFFER)
289 #undef STORE_BUFFER
290 }
291 UNREACHABLE();
292 return nullptr;
293 }
294
295
296 #define ACCESS_OP_LIST(V) \
297 V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
298 V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \
299 V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
300 V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)
301
302
303 #define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
304 output_count) \
305 const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \
306 return new (zone()) \
307 Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \
308 #Name, value_input_count, 1, control_input_count, \
309 output_count, 1, 0, access); \
310 }
311 ACCESS_OP_LIST(ACCESS)
312 #undef ACCESS
313
314 } // namespace compiler
315 } // namespace internal
316 } // namespace v8
317