blob: 03504035d715c0fa3466e94a13a2b3169beb98ad [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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"
Ben Murdoch109988c2016-05-18 11:27:45 +010010#include "src/types.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011
12namespace v8 {
13namespace internal {
14namespace compiler {
15
Ben Murdochbcf72ee2016-08-08 18:44:38 +010016size_t hash_value(BaseTaggedness base_taggedness) {
17 return static_cast<uint8_t>(base_taggedness);
18}
19
Emily Bernier958fae72015-03-24 16:35:39 -040020std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021 switch (base_taggedness) {
22 case kUntaggedBase:
23 return os << "untagged base";
24 case kTaggedBase:
25 return os << "tagged base";
26 }
27 UNREACHABLE();
28 return os;
29}
30
31
Emily Bernier958fae72015-03-24 16:35:39 -040032MachineType BufferAccess::machine_type() const {
33 switch (external_array_type_) {
34 case kExternalUint8Array:
35 case kExternalUint8ClampedArray:
Ben Murdoch014dc512016-03-22 12:00:34 +000036 return MachineType::Uint8();
Emily Bernier958fae72015-03-24 16:35:39 -040037 case kExternalInt8Array:
Ben Murdoch014dc512016-03-22 12:00:34 +000038 return MachineType::Int8();
Emily Bernier958fae72015-03-24 16:35:39 -040039 case kExternalUint16Array:
Ben Murdoch014dc512016-03-22 12:00:34 +000040 return MachineType::Uint16();
Emily Bernier958fae72015-03-24 16:35:39 -040041 case kExternalInt16Array:
Ben Murdoch014dc512016-03-22 12:00:34 +000042 return MachineType::Int16();
Emily Bernier958fae72015-03-24 16:35:39 -040043 case kExternalUint32Array:
Ben Murdoch014dc512016-03-22 12:00:34 +000044 return MachineType::Uint32();
Emily Bernier958fae72015-03-24 16:35:39 -040045 case kExternalInt32Array:
Ben Murdoch014dc512016-03-22 12:00:34 +000046 return MachineType::Int32();
Emily Bernier958fae72015-03-24 16:35:39 -040047 case kExternalFloat32Array:
Ben Murdoch014dc512016-03-22 12:00:34 +000048 return MachineType::Float32();
Emily Bernier958fae72015-03-24 16:35:39 -040049 case kExternalFloat64Array:
Ben Murdoch014dc512016-03-22 12:00:34 +000050 return MachineType::Float64();
Emily Bernier958fae72015-03-24 16:35:39 -040051 }
52 UNREACHABLE();
Ben Murdoch014dc512016-03-22 12:00:34 +000053 return MachineType::None();
Emily Bernier958fae72015-03-24 16:35:39 -040054}
55
56
57bool operator==(BufferAccess lhs, BufferAccess rhs) {
58 return lhs.external_array_type() == rhs.external_array_type();
59}
60
61
62bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
63
64
65size_t hash_value(BufferAccess access) {
66 return base::hash<ExternalArrayType>()(access.external_array_type());
67}
68
69
70std::ostream& operator<<(std::ostream& os, BufferAccess access) {
71 switch (access.external_array_type()) {
72#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
73 case kExternal##Type##Array: \
74 return os << #Type;
75 TYPED_ARRAYS(TYPED_ARRAY_CASE)
76#undef TYPED_ARRAY_CASE
77 }
78 UNREACHABLE();
79 return os;
80}
81
82
83BufferAccess const BufferAccessOf(const Operator* op) {
84 DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
85 op->opcode() == IrOpcode::kStoreBuffer);
86 return OpParameter<BufferAccess>(op);
87}
88
89
90bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +010091 // On purpose we don't include the write barrier kind here, as this method is
92 // really only relevant for eliminating loads and they don't care about the
93 // write barrier mode.
Emily Bernier958fae72015-03-24 16:35:39 -040094 return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
95 lhs.machine_type == rhs.machine_type;
96}
97
98
99bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
100 return !(lhs == rhs);
101}
102
103
104size_t hash_value(FieldAccess const& access) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100105 // On purpose we don't include the write barrier kind here, as this method is
106 // really only relevant for eliminating loads and they don't care about the
107 // write barrier mode.
Emily Bernier958fae72015-03-24 16:35:39 -0400108 return base::hash_combine(access.base_is_tagged, access.offset,
109 access.machine_type);
110}
111
112
113std::ostream& operator<<(std::ostream& os, FieldAccess const& access) {
114 os << "[" << access.base_is_tagged << ", " << access.offset << ", ";
115#ifdef OBJECT_PRINT
116 Handle<Name> name;
117 if (access.name.ToHandle(&name)) {
118 name->Print(os);
119 os << ", ";
120 }
121#endif
122 access.type->PrintTo(os);
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100123 os << ", " << access.machine_type << ", " << access.write_barrier_kind << "]";
Emily Bernier958fae72015-03-24 16:35:39 -0400124 return os;
125}
126
127
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000128bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100129 // On purpose we don't include the write barrier kind here, as this method is
130 // really only relevant for eliminating loads and they don't care about the
131 // write barrier mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000132 return lhs.base_is_tagged == rhs.base_is_tagged &&
Emily Bernier958fae72015-03-24 16:35:39 -0400133 lhs.header_size == rhs.header_size &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000134 lhs.machine_type == rhs.machine_type;
135}
136
137
138bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
139 return !(lhs == rhs);
140}
141
142
Emily Bernier958fae72015-03-24 16:35:39 -0400143size_t hash_value(ElementAccess const& access) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100144 // On purpose we don't include the write barrier kind here, as this method is
145 // really only relevant for eliminating loads and they don't care about the
146 // write barrier mode.
Emily Bernier958fae72015-03-24 16:35:39 -0400147 return base::hash_combine(access.base_is_tagged, access.header_size,
148 access.machine_type);
149}
150
151
152std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
153 os << access.base_is_tagged << ", " << access.header_size << ", ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000154 access.type->PrintTo(os);
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100155 os << ", " << access.machine_type << ", " << access.write_barrier_kind;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156 return os;
157}
158
159
160const FieldAccess& FieldAccessOf(const Operator* op) {
161 DCHECK_NOT_NULL(op);
162 DCHECK(op->opcode() == IrOpcode::kLoadField ||
163 op->opcode() == IrOpcode::kStoreField);
164 return OpParameter<FieldAccess>(op);
165}
166
167
168const ElementAccess& ElementAccessOf(const Operator* op) {
169 DCHECK_NOT_NULL(op);
170 DCHECK(op->opcode() == IrOpcode::kLoadElement ||
171 op->opcode() == IrOpcode::kStoreElement);
172 return OpParameter<ElementAccess>(op);
173}
174
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100175Type* TypeOf(const Operator* op) {
176 DCHECK_EQ(IrOpcode::kTypeGuard, op->opcode());
177 return OpParameter<Type*>(op);
178}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000179
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100180#define PURE_OP_LIST(V) \
181 V(BooleanNot, Operator::kNoProperties, 1) \
182 V(BooleanToNumber, Operator::kNoProperties, 1) \
183 V(NumberEqual, Operator::kCommutative, 2) \
184 V(NumberLessThan, Operator::kNoProperties, 2) \
185 V(NumberLessThanOrEqual, Operator::kNoProperties, 2) \
186 V(NumberAdd, Operator::kCommutative, 2) \
187 V(NumberSubtract, Operator::kNoProperties, 2) \
188 V(NumberMultiply, Operator::kCommutative, 2) \
189 V(NumberDivide, Operator::kNoProperties, 2) \
190 V(NumberModulus, Operator::kNoProperties, 2) \
191 V(NumberBitwiseOr, Operator::kCommutative, 2) \
192 V(NumberBitwiseXor, Operator::kCommutative, 2) \
193 V(NumberBitwiseAnd, Operator::kCommutative, 2) \
194 V(NumberShiftLeft, Operator::kNoProperties, 2) \
195 V(NumberShiftRight, Operator::kNoProperties, 2) \
196 V(NumberShiftRightLogical, Operator::kNoProperties, 2) \
197 V(NumberImul, Operator::kCommutative, 2) \
198 V(NumberClz32, Operator::kNoProperties, 1) \
199 V(NumberCeil, Operator::kNoProperties, 1) \
200 V(NumberFloor, Operator::kNoProperties, 1) \
201 V(NumberRound, Operator::kNoProperties, 1) \
202 V(NumberTrunc, Operator::kNoProperties, 1) \
203 V(NumberToInt32, Operator::kNoProperties, 1) \
204 V(NumberToUint32, Operator::kNoProperties, 1) \
205 V(NumberIsHoleNaN, Operator::kNoProperties, 1) \
206 V(StringToNumber, Operator::kNoProperties, 1) \
207 V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1) \
208 V(ChangeTaggedToInt32, Operator::kNoProperties, 1) \
209 V(ChangeTaggedToUint32, Operator::kNoProperties, 1) \
210 V(ChangeTaggedToFloat64, Operator::kNoProperties, 1) \
211 V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1) \
212 V(ChangeInt32ToTagged, Operator::kNoProperties, 1) \
213 V(ChangeUint32ToTagged, Operator::kNoProperties, 1) \
214 V(ChangeFloat64ToTagged, Operator::kNoProperties, 1) \
215 V(ChangeTaggedToBit, Operator::kNoProperties, 1) \
216 V(ChangeBitToTagged, Operator::kNoProperties, 1) \
217 V(TruncateTaggedToWord32, Operator::kNoProperties, 1) \
218 V(ObjectIsCallable, Operator::kNoProperties, 1) \
219 V(ObjectIsNumber, Operator::kNoProperties, 1) \
220 V(ObjectIsReceiver, Operator::kNoProperties, 1) \
221 V(ObjectIsSmi, Operator::kNoProperties, 1) \
222 V(ObjectIsString, Operator::kNoProperties, 1) \
223 V(ObjectIsUndetectable, Operator::kNoProperties, 1) \
224 V(StringEqual, Operator::kCommutative, 2) \
225 V(StringLessThan, Operator::kNoProperties, 2) \
226 V(StringLessThanOrEqual, Operator::kNoProperties, 2)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227
Ben Murdoch014dc512016-03-22 12:00:34 +0000228struct SimplifiedOperatorGlobalCache final {
Emily Bernier958fae72015-03-24 16:35:39 -0400229#define PURE(Name, properties, input_count) \
Ben Murdoch014dc512016-03-22 12:00:34 +0000230 struct Name##Operator final : public Operator { \
Emily Bernier958fae72015-03-24 16:35:39 -0400231 Name##Operator() \
232 : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
233 input_count, 0, 0, 1, 0, 0) {} \
234 }; \
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 Name##Operator k##Name;
236 PURE_OP_LIST(PURE)
237#undef PURE
Emily Bernier958fae72015-03-24 16:35:39 -0400238
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100239 template <PretenureFlag kPretenure>
240 struct AllocateOperator final : public Operator1<PretenureFlag> {
241 AllocateOperator()
242 : Operator1<PretenureFlag>(IrOpcode::kAllocate, Operator::kNoThrow,
243 "Allocate", 1, 1, 1, 1, 1, 0, kPretenure) {}
244 };
245 AllocateOperator<NOT_TENURED> kAllocateNotTenuredOperator;
246 AllocateOperator<TENURED> kAllocateTenuredOperator;
Ben Murdoch014dc512016-03-22 12:00:34 +0000247
Emily Bernier958fae72015-03-24 16:35:39 -0400248#define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
Ben Murdoch014dc512016-03-22 12:00:34 +0000249 struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
Emily Bernier958fae72015-03-24 16:35:39 -0400250 LoadBuffer##Type##Operator() \
251 : Operator1<BufferAccess>(IrOpcode::kLoadBuffer, \
252 Operator::kNoThrow | Operator::kNoWrite, \
253 "LoadBuffer", 3, 1, 1, 1, 1, 0, \
254 BufferAccess(kExternal##Type##Array)) {} \
255 }; \
Ben Murdoch014dc512016-03-22 12:00:34 +0000256 struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
Emily Bernier958fae72015-03-24 16:35:39 -0400257 StoreBuffer##Type##Operator() \
258 : Operator1<BufferAccess>(IrOpcode::kStoreBuffer, \
259 Operator::kNoRead | Operator::kNoThrow, \
260 "StoreBuffer", 4, 1, 1, 0, 1, 0, \
261 BufferAccess(kExternal##Type##Array)) {} \
262 }; \
263 LoadBuffer##Type##Operator kLoadBuffer##Type; \
264 StoreBuffer##Type##Operator kStoreBuffer##Type;
265 TYPED_ARRAYS(BUFFER_ACCESS)
266#undef BUFFER_ACCESS
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000267};
268
269
Emily Bernier958fae72015-03-24 16:35:39 -0400270static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 LAZY_INSTANCE_INITIALIZER;
272
273
274SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
Emily Bernier958fae72015-03-24 16:35:39 -0400275 : cache_(kCache.Get()), zone_(zone) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276
277
Ben Murdoch014dc512016-03-22 12:00:34 +0000278#define GET_FROM_CACHE(Name, properties, input_count) \
Emily Bernier958fae72015-03-24 16:35:39 -0400279 const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
Ben Murdoch014dc512016-03-22 12:00:34 +0000280PURE_OP_LIST(GET_FROM_CACHE)
Ben Murdoch014dc512016-03-22 12:00:34 +0000281#undef GET_FROM_CACHE
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000282
283
284const Operator* SimplifiedOperatorBuilder::ReferenceEqual(Type* type) {
Emily Bernier958fae72015-03-24 16:35:39 -0400285 return new (zone()) Operator(IrOpcode::kReferenceEqual,
286 Operator::kCommutative | Operator::kPure,
287 "ReferenceEqual", 2, 0, 0, 1, 0, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288}
289
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100290const Operator* SimplifiedOperatorBuilder::TypeGuard(Type* type) {
291 class TypeGuardOperator final : public Operator1<Type*> {
292 public:
293 explicit TypeGuardOperator(Type* type)
294 : Operator1<Type*>( // --
295 IrOpcode::kTypeGuard, Operator::kPure, // opcode
296 "TypeGuard", // name
297 1, 0, 1, 1, 0, 0, // counts
298 type) {} // parameter
299
300 void PrintParameter(std::ostream& os) const final {
301 parameter()->PrintTo(os);
302 }
303 };
304 return new (zone()) TypeGuardOperator(type);
305}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000306
Ben Murdoch014dc512016-03-22 12:00:34 +0000307const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
Ben Murdochbcf72ee2016-08-08 18:44:38 +0100308 switch (pretenure) {
309 case NOT_TENURED:
310 return &cache_.kAllocateNotTenuredOperator;
311 case TENURED:
312 return &cache_.kAllocateTenuredOperator;
313 }
314 UNREACHABLE();
315 return nullptr;
Ben Murdoch014dc512016-03-22 12:00:34 +0000316}
317
318
Emily Bernier958fae72015-03-24 16:35:39 -0400319const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
320 switch (access.external_array_type()) {
321#define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
322 case kExternal##Type##Array: \
323 return &cache_.kLoadBuffer##Type;
324 TYPED_ARRAYS(LOAD_BUFFER)
325#undef LOAD_BUFFER
326 }
327 UNREACHABLE();
328 return nullptr;
329}
330
331
332const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
333 switch (access.external_array_type()) {
334#define STORE_BUFFER(Type, type, TYPE, ctype, size) \
335 case kExternal##Type##Array: \
336 return &cache_.kStoreBuffer##Type;
337 TYPED_ARRAYS(STORE_BUFFER)
338#undef STORE_BUFFER
339 }
340 UNREACHABLE();
341 return nullptr;
342}
343
344
345#define ACCESS_OP_LIST(V) \
346 V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
347 V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \
348 V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
349 V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0)
350
351
352#define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
353 output_count) \
354 const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \
355 return new (zone()) \
356 Operator1<Type>(IrOpcode::k##Name, Operator::kNoThrow | properties, \
357 #Name, value_input_count, 1, control_input_count, \
358 output_count, 1, 0, access); \
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000359 }
360ACCESS_OP_LIST(ACCESS)
361#undef ACCESS
362
363} // namespace compiler
364} // namespace internal
365} // namespace v8