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/compiler/types.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
hash_value(BaseTaggedness base_taggedness)16 size_t hash_value(BaseTaggedness base_taggedness) {
17 return static_cast<uint8_t>(base_taggedness);
18 }
19
operator <<(std::ostream & os,BaseTaggedness base_taggedness)20 std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
21 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
machine_type() const32 MachineType BufferAccess::machine_type() const {
33 switch (external_array_type_) {
34 case kExternalUint8Array:
35 case kExternalUint8ClampedArray:
36 return MachineType::Uint8();
37 case kExternalInt8Array:
38 return MachineType::Int8();
39 case kExternalUint16Array:
40 return MachineType::Uint16();
41 case kExternalInt16Array:
42 return MachineType::Int16();
43 case kExternalUint32Array:
44 return MachineType::Uint32();
45 case kExternalInt32Array:
46 return MachineType::Int32();
47 case kExternalFloat32Array:
48 return MachineType::Float32();
49 case kExternalFloat64Array:
50 return MachineType::Float64();
51 }
52 UNREACHABLE();
53 return MachineType::None();
54 }
55
56
operator ==(BufferAccess lhs,BufferAccess rhs)57 bool operator==(BufferAccess lhs, BufferAccess rhs) {
58 return lhs.external_array_type() == rhs.external_array_type();
59 }
60
61
operator !=(BufferAccess lhs,BufferAccess rhs)62 bool operator!=(BufferAccess lhs, BufferAccess rhs) { return !(lhs == rhs); }
63
64
hash_value(BufferAccess access)65 size_t hash_value(BufferAccess access) {
66 return base::hash<ExternalArrayType>()(access.external_array_type());
67 }
68
69
operator <<(std::ostream & os,BufferAccess access)70 std::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
BufferAccessOf(const Operator * op)83 BufferAccess const BufferAccessOf(const Operator* op) {
84 DCHECK(op->opcode() == IrOpcode::kLoadBuffer ||
85 op->opcode() == IrOpcode::kStoreBuffer);
86 return OpParameter<BufferAccess>(op);
87 }
88
89
operator ==(FieldAccess const & lhs,FieldAccess const & rhs)90 bool operator==(FieldAccess const& lhs, FieldAccess const& rhs) {
91 // 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.
94 return lhs.base_is_tagged == rhs.base_is_tagged && lhs.offset == rhs.offset &&
95 lhs.machine_type == rhs.machine_type;
96 }
97
98
operator !=(FieldAccess const & lhs,FieldAccess const & rhs)99 bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
100 return !(lhs == rhs);
101 }
102
103
hash_value(FieldAccess const & access)104 size_t hash_value(FieldAccess const& access) {
105 // 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.
108 return base::hash_combine(access.base_is_tagged, access.offset,
109 access.machine_type);
110 }
111
112
operator <<(std::ostream & os,FieldAccess const & access)113 std::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);
123 os << ", " << access.machine_type << ", " << access.write_barrier_kind << "]";
124 return os;
125 }
126
127 template <>
PrintParameter(std::ostream & os,PrintVerbosity verbose) const128 void Operator1<FieldAccess>::PrintParameter(std::ostream& os,
129 PrintVerbosity verbose) const {
130 if (verbose == PrintVerbosity::kVerbose) {
131 os << parameter();
132 } else {
133 os << "[+" << parameter().offset << "]";
134 }
135 }
136
operator ==(ElementAccess const & lhs,ElementAccess const & rhs)137 bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
138 // On purpose we don't include the write barrier kind here, as this method is
139 // really only relevant for eliminating loads and they don't care about the
140 // write barrier mode.
141 return lhs.base_is_tagged == rhs.base_is_tagged &&
142 lhs.header_size == rhs.header_size &&
143 lhs.machine_type == rhs.machine_type;
144 }
145
146
operator !=(ElementAccess const & lhs,ElementAccess const & rhs)147 bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
148 return !(lhs == rhs);
149 }
150
151
hash_value(ElementAccess const & access)152 size_t hash_value(ElementAccess const& access) {
153 // On purpose we don't include the write barrier kind here, as this method is
154 // really only relevant for eliminating loads and they don't care about the
155 // write barrier mode.
156 return base::hash_combine(access.base_is_tagged, access.header_size,
157 access.machine_type);
158 }
159
160
operator <<(std::ostream & os,ElementAccess const & access)161 std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
162 os << access.base_is_tagged << ", " << access.header_size << ", ";
163 access.type->PrintTo(os);
164 os << ", " << access.machine_type << ", " << access.write_barrier_kind;
165 return os;
166 }
167
168
FieldAccessOf(const Operator * op)169 const FieldAccess& FieldAccessOf(const Operator* op) {
170 DCHECK_NOT_NULL(op);
171 DCHECK(op->opcode() == IrOpcode::kLoadField ||
172 op->opcode() == IrOpcode::kStoreField);
173 return OpParameter<FieldAccess>(op);
174 }
175
176
ElementAccessOf(const Operator * op)177 const ElementAccess& ElementAccessOf(const Operator* op) {
178 DCHECK_NOT_NULL(op);
179 DCHECK(op->opcode() == IrOpcode::kLoadElement ||
180 op->opcode() == IrOpcode::kStoreElement);
181 return OpParameter<ElementAccess>(op);
182 }
183
ExternalArrayTypeOf(const Operator * op)184 ExternalArrayType ExternalArrayTypeOf(const Operator* op) {
185 DCHECK(op->opcode() == IrOpcode::kLoadTypedElement ||
186 op->opcode() == IrOpcode::kStoreTypedElement);
187 return OpParameter<ExternalArrayType>(op);
188 }
189
hash_value(CheckFloat64HoleMode mode)190 size_t hash_value(CheckFloat64HoleMode mode) {
191 return static_cast<size_t>(mode);
192 }
193
operator <<(std::ostream & os,CheckFloat64HoleMode mode)194 std::ostream& operator<<(std::ostream& os, CheckFloat64HoleMode mode) {
195 switch (mode) {
196 case CheckFloat64HoleMode::kAllowReturnHole:
197 return os << "allow-return-hole";
198 case CheckFloat64HoleMode::kNeverReturnHole:
199 return os << "never-return-hole";
200 }
201 UNREACHABLE();
202 return os;
203 }
204
CheckFloat64HoleModeOf(const Operator * op)205 CheckFloat64HoleMode CheckFloat64HoleModeOf(const Operator* op) {
206 DCHECK_EQ(IrOpcode::kCheckFloat64Hole, op->opcode());
207 return OpParameter<CheckFloat64HoleMode>(op);
208 }
209
CheckMinusZeroModeOf(const Operator * op)210 CheckForMinusZeroMode CheckMinusZeroModeOf(const Operator* op) {
211 DCHECK(op->opcode() == IrOpcode::kCheckedInt32Mul ||
212 op->opcode() == IrOpcode::kCheckedFloat64ToInt32 ||
213 op->opcode() == IrOpcode::kCheckedTaggedToInt32);
214 return OpParameter<CheckForMinusZeroMode>(op);
215 }
216
hash_value(CheckForMinusZeroMode mode)217 size_t hash_value(CheckForMinusZeroMode mode) {
218 return static_cast<size_t>(mode);
219 }
220
operator <<(std::ostream & os,CheckForMinusZeroMode mode)221 std::ostream& operator<<(std::ostream& os, CheckForMinusZeroMode mode) {
222 switch (mode) {
223 case CheckForMinusZeroMode::kCheckForMinusZero:
224 return os << "check-for-minus-zero";
225 case CheckForMinusZeroMode::kDontCheckForMinusZero:
226 return os << "dont-check-for-minus-zero";
227 }
228 UNREACHABLE();
229 return os;
230 }
231
hash_value(CheckTaggedInputMode mode)232 size_t hash_value(CheckTaggedInputMode mode) {
233 return static_cast<size_t>(mode);
234 }
235
operator <<(std::ostream & os,CheckTaggedInputMode mode)236 std::ostream& operator<<(std::ostream& os, CheckTaggedInputMode mode) {
237 switch (mode) {
238 case CheckTaggedInputMode::kNumber:
239 return os << "Number";
240 case CheckTaggedInputMode::kNumberOrOddball:
241 return os << "NumberOrOddball";
242 }
243 UNREACHABLE();
244 return os;
245 }
246
CheckTaggedInputModeOf(const Operator * op)247 CheckTaggedInputMode CheckTaggedInputModeOf(const Operator* op) {
248 DCHECK_EQ(IrOpcode::kCheckedTaggedToFloat64, op->opcode());
249 return OpParameter<CheckTaggedInputMode>(op);
250 }
251
operator <<(std::ostream & os,GrowFastElementsFlags flags)252 std::ostream& operator<<(std::ostream& os, GrowFastElementsFlags flags) {
253 bool empty = true;
254 if (flags & GrowFastElementsFlag::kArrayObject) {
255 os << "ArrayObject";
256 empty = false;
257 }
258 if (flags & GrowFastElementsFlag::kDoubleElements) {
259 if (!empty) os << "|";
260 os << "DoubleElements";
261 empty = false;
262 }
263 if (flags & GrowFastElementsFlag::kHoleyElements) {
264 if (!empty) os << "|";
265 os << "HoleyElements";
266 empty = false;
267 }
268 if (empty) os << "None";
269 return os;
270 }
271
GrowFastElementsFlagsOf(const Operator * op)272 GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator* op) {
273 DCHECK_EQ(IrOpcode::kMaybeGrowFastElements, op->opcode());
274 return OpParameter<GrowFastElementsFlags>(op);
275 }
276
hash_value(ElementsTransition transition)277 size_t hash_value(ElementsTransition transition) {
278 return static_cast<uint8_t>(transition);
279 }
280
operator <<(std::ostream & os,ElementsTransition transition)281 std::ostream& operator<<(std::ostream& os, ElementsTransition transition) {
282 switch (transition) {
283 case ElementsTransition::kFastTransition:
284 return os << "fast-transition";
285 case ElementsTransition::kSlowTransition:
286 return os << "slow-transition";
287 }
288 UNREACHABLE();
289 return os;
290 }
291
ElementsTransitionOf(const Operator * op)292 ElementsTransition ElementsTransitionOf(const Operator* op) {
293 DCHECK_EQ(IrOpcode::kTransitionElementsKind, op->opcode());
294 return OpParameter<ElementsTransition>(op);
295 }
296
operator <<(std::ostream & os,NumberOperationHint hint)297 std::ostream& operator<<(std::ostream& os, NumberOperationHint hint) {
298 switch (hint) {
299 case NumberOperationHint::kSignedSmall:
300 return os << "SignedSmall";
301 case NumberOperationHint::kSigned32:
302 return os << "Signed32";
303 case NumberOperationHint::kNumber:
304 return os << "Number";
305 case NumberOperationHint::kNumberOrOddball:
306 return os << "NumberOrOddball";
307 }
308 UNREACHABLE();
309 return os;
310 }
311
hash_value(NumberOperationHint hint)312 size_t hash_value(NumberOperationHint hint) {
313 return static_cast<uint8_t>(hint);
314 }
315
NumberOperationHintOf(const Operator * op)316 NumberOperationHint NumberOperationHintOf(const Operator* op) {
317 DCHECK(op->opcode() == IrOpcode::kSpeculativeNumberAdd ||
318 op->opcode() == IrOpcode::kSpeculativeNumberSubtract ||
319 op->opcode() == IrOpcode::kSpeculativeNumberMultiply ||
320 op->opcode() == IrOpcode::kSpeculativeNumberDivide ||
321 op->opcode() == IrOpcode::kSpeculativeNumberModulus ||
322 op->opcode() == IrOpcode::kSpeculativeNumberShiftLeft ||
323 op->opcode() == IrOpcode::kSpeculativeNumberShiftRight ||
324 op->opcode() == IrOpcode::kSpeculativeNumberShiftRightLogical ||
325 op->opcode() == IrOpcode::kSpeculativeNumberBitwiseAnd ||
326 op->opcode() == IrOpcode::kSpeculativeNumberBitwiseOr ||
327 op->opcode() == IrOpcode::kSpeculativeNumberBitwiseXor ||
328 op->opcode() == IrOpcode::kSpeculativeNumberEqual ||
329 op->opcode() == IrOpcode::kSpeculativeNumberLessThan ||
330 op->opcode() == IrOpcode::kSpeculativeNumberLessThanOrEqual);
331 return OpParameter<NumberOperationHint>(op);
332 }
333
PretenureFlagOf(const Operator * op)334 PretenureFlag PretenureFlagOf(const Operator* op) {
335 DCHECK_EQ(IrOpcode::kAllocate, op->opcode());
336 return OpParameter<PretenureFlag>(op);
337 }
338
UnicodeEncodingOf(const Operator * op)339 UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
340 DCHECK(op->opcode() == IrOpcode::kStringFromCodePoint);
341 return OpParameter<UnicodeEncoding>(op);
342 }
343
344 #define PURE_OP_LIST(V) \
345 V(BooleanNot, Operator::kNoProperties, 1, 0) \
346 V(NumberEqual, Operator::kCommutative, 2, 0) \
347 V(NumberLessThan, Operator::kNoProperties, 2, 0) \
348 V(NumberLessThanOrEqual, Operator::kNoProperties, 2, 0) \
349 V(NumberAdd, Operator::kCommutative, 2, 0) \
350 V(NumberSubtract, Operator::kNoProperties, 2, 0) \
351 V(NumberMultiply, Operator::kCommutative, 2, 0) \
352 V(NumberDivide, Operator::kNoProperties, 2, 0) \
353 V(NumberModulus, Operator::kNoProperties, 2, 0) \
354 V(NumberBitwiseOr, Operator::kCommutative, 2, 0) \
355 V(NumberBitwiseXor, Operator::kCommutative, 2, 0) \
356 V(NumberBitwiseAnd, Operator::kCommutative, 2, 0) \
357 V(NumberShiftLeft, Operator::kNoProperties, 2, 0) \
358 V(NumberShiftRight, Operator::kNoProperties, 2, 0) \
359 V(NumberShiftRightLogical, Operator::kNoProperties, 2, 0) \
360 V(NumberImul, Operator::kCommutative, 2, 0) \
361 V(NumberAbs, Operator::kNoProperties, 1, 0) \
362 V(NumberClz32, Operator::kNoProperties, 1, 0) \
363 V(NumberCeil, Operator::kNoProperties, 1, 0) \
364 V(NumberFloor, Operator::kNoProperties, 1, 0) \
365 V(NumberFround, Operator::kNoProperties, 1, 0) \
366 V(NumberAcos, Operator::kNoProperties, 1, 0) \
367 V(NumberAcosh, Operator::kNoProperties, 1, 0) \
368 V(NumberAsin, Operator::kNoProperties, 1, 0) \
369 V(NumberAsinh, Operator::kNoProperties, 1, 0) \
370 V(NumberAtan, Operator::kNoProperties, 1, 0) \
371 V(NumberAtan2, Operator::kNoProperties, 2, 0) \
372 V(NumberAtanh, Operator::kNoProperties, 1, 0) \
373 V(NumberCbrt, Operator::kNoProperties, 1, 0) \
374 V(NumberCos, Operator::kNoProperties, 1, 0) \
375 V(NumberCosh, Operator::kNoProperties, 1, 0) \
376 V(NumberExp, Operator::kNoProperties, 1, 0) \
377 V(NumberExpm1, Operator::kNoProperties, 1, 0) \
378 V(NumberLog, Operator::kNoProperties, 1, 0) \
379 V(NumberLog1p, Operator::kNoProperties, 1, 0) \
380 V(NumberLog10, Operator::kNoProperties, 1, 0) \
381 V(NumberLog2, Operator::kNoProperties, 1, 0) \
382 V(NumberMax, Operator::kNoProperties, 2, 0) \
383 V(NumberMin, Operator::kNoProperties, 2, 0) \
384 V(NumberPow, Operator::kNoProperties, 2, 0) \
385 V(NumberRound, Operator::kNoProperties, 1, 0) \
386 V(NumberSign, Operator::kNoProperties, 1, 0) \
387 V(NumberSin, Operator::kNoProperties, 1, 0) \
388 V(NumberSinh, Operator::kNoProperties, 1, 0) \
389 V(NumberSqrt, Operator::kNoProperties, 1, 0) \
390 V(NumberTan, Operator::kNoProperties, 1, 0) \
391 V(NumberTanh, Operator::kNoProperties, 1, 0) \
392 V(NumberTrunc, Operator::kNoProperties, 1, 0) \
393 V(NumberToBoolean, Operator::kNoProperties, 1, 0) \
394 V(NumberToInt32, Operator::kNoProperties, 1, 0) \
395 V(NumberToUint32, Operator::kNoProperties, 1, 0) \
396 V(NumberToUint8Clamped, Operator::kNoProperties, 1, 0) \
397 V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \
398 V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \
399 V(StringFromCharCode, Operator::kNoProperties, 1, 0) \
400 V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
401 V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
402 V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \
403 V(ChangeTaggedSignedToInt32, Operator::kNoProperties, 1, 0) \
404 V(ChangeTaggedToInt32, Operator::kNoProperties, 1, 0) \
405 V(ChangeTaggedToUint32, Operator::kNoProperties, 1, 0) \
406 V(ChangeTaggedToFloat64, Operator::kNoProperties, 1, 0) \
407 V(ChangeFloat64ToTagged, Operator::kNoProperties, 1, 0) \
408 V(ChangeFloat64ToTaggedPointer, Operator::kNoProperties, 1, 0) \
409 V(ChangeInt31ToTaggedSigned, Operator::kNoProperties, 1, 0) \
410 V(ChangeInt32ToTagged, Operator::kNoProperties, 1, 0) \
411 V(ChangeUint32ToTagged, Operator::kNoProperties, 1, 0) \
412 V(ChangeTaggedToBit, Operator::kNoProperties, 1, 0) \
413 V(ChangeBitToTagged, Operator::kNoProperties, 1, 0) \
414 V(TruncateTaggedToBit, Operator::kNoProperties, 1, 0) \
415 V(TruncateTaggedToWord32, Operator::kNoProperties, 1, 0) \
416 V(TruncateTaggedToFloat64, Operator::kNoProperties, 1, 0) \
417 V(ObjectIsCallable, Operator::kNoProperties, 1, 0) \
418 V(ObjectIsNumber, Operator::kNoProperties, 1, 0) \
419 V(ObjectIsReceiver, Operator::kNoProperties, 1, 0) \
420 V(ObjectIsSmi, Operator::kNoProperties, 1, 0) \
421 V(ObjectIsString, Operator::kNoProperties, 1, 0) \
422 V(ObjectIsUndetectable, Operator::kNoProperties, 1, 0) \
423 V(ConvertTaggedHoleToUndefined, Operator::kNoProperties, 1, 0) \
424 V(ReferenceEqual, Operator::kCommutative, 2, 0) \
425 V(StringEqual, Operator::kCommutative, 2, 0) \
426 V(StringLessThan, Operator::kNoProperties, 2, 0) \
427 V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0)
428
429 #define SPECULATIVE_NUMBER_BINOP_LIST(V) \
430 SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
431 V(SpeculativeNumberEqual) \
432 V(SpeculativeNumberLessThan) \
433 V(SpeculativeNumberLessThanOrEqual)
434
435 #define CHECKED_OP_LIST(V) \
436 V(CheckBounds, 2, 1) \
437 V(CheckHeapObject, 1, 1) \
438 V(CheckIf, 1, 0) \
439 V(CheckNumber, 1, 1) \
440 V(CheckSmi, 1, 1) \
441 V(CheckString, 1, 1) \
442 V(CheckTaggedHole, 1, 1) \
443 V(CheckedInt32Add, 2, 1) \
444 V(CheckedInt32Sub, 2, 1) \
445 V(CheckedInt32Div, 2, 1) \
446 V(CheckedInt32Mod, 2, 1) \
447 V(CheckedUint32Div, 2, 1) \
448 V(CheckedUint32Mod, 2, 1) \
449 V(CheckedUint32ToInt32, 1, 1) \
450 V(CheckedUint32ToTaggedSigned, 1, 1) \
451 V(CheckedInt32ToTaggedSigned, 1, 1) \
452 V(CheckedTaggedSignedToInt32, 1, 1) \
453 V(CheckedTaggedToTaggedSigned, 1, 1) \
454 V(CheckedTaggedToTaggedPointer, 1, 1) \
455 V(CheckedTruncateTaggedToWord32, 1, 1)
456
457 struct SimplifiedOperatorGlobalCache final {
458 #define PURE(Name, properties, value_input_count, control_input_count) \
459 struct Name##Operator final : public Operator { \
460 Name##Operator() \
461 : Operator(IrOpcode::k##Name, Operator::kPure | properties, #Name, \
462 value_input_count, 0, control_input_count, 1, 0, 0) {} \
463 }; \
464 Name##Operator k##Name;
465 PURE_OP_LIST(PURE)
466 #undef PURE
467
468 #define CHECKED(Name, value_input_count, value_output_count) \
469 struct Name##Operator final : public Operator { \
470 Name##Operator() \
471 : Operator(IrOpcode::k##Name, \
472 Operator::kFoldable | Operator::kNoThrow, #Name, \
473 value_input_count, 1, 1, value_output_count, 1, 0) {} \
474 }; \
475 Name##Operator k##Name;
476 CHECKED_OP_LIST(CHECKED)
477 #undef CHECKED
478
479 template <UnicodeEncoding kEncoding>
480 struct StringFromCodePointOperator final : public Operator1<UnicodeEncoding> {
StringFromCodePointOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::StringFromCodePointOperator481 StringFromCodePointOperator()
482 : Operator1<UnicodeEncoding>(IrOpcode::kStringFromCodePoint,
483 Operator::kPure, "StringFromCodePoint", 1,
484 0, 0, 1, 0, 0, kEncoding) {}
485 };
486 StringFromCodePointOperator<UnicodeEncoding::UTF16>
487 kStringFromCodePointOperatorUTF16;
488 StringFromCodePointOperator<UnicodeEncoding::UTF32>
489 kStringFromCodePointOperatorUTF32;
490
491 struct ArrayBufferWasNeuteredOperator final : public Operator {
ArrayBufferWasNeuteredOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::ArrayBufferWasNeuteredOperator492 ArrayBufferWasNeuteredOperator()
493 : Operator(IrOpcode::kArrayBufferWasNeutered, Operator::kEliminatable,
494 "ArrayBufferWasNeutered", 1, 1, 1, 1, 1, 0) {}
495 };
496 ArrayBufferWasNeuteredOperator kArrayBufferWasNeutered;
497
498 template <CheckForMinusZeroMode kMode>
499 struct CheckedInt32MulOperator final
500 : public Operator1<CheckForMinusZeroMode> {
CheckedInt32MulOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedInt32MulOperator501 CheckedInt32MulOperator()
502 : Operator1<CheckForMinusZeroMode>(
503 IrOpcode::kCheckedInt32Mul,
504 Operator::kFoldable | Operator::kNoThrow, "CheckedInt32Mul", 2, 1,
505 1, 1, 1, 0, kMode) {}
506 };
507 CheckedInt32MulOperator<CheckForMinusZeroMode::kCheckForMinusZero>
508 kCheckedInt32MulCheckForMinusZeroOperator;
509 CheckedInt32MulOperator<CheckForMinusZeroMode::kDontCheckForMinusZero>
510 kCheckedInt32MulDontCheckForMinusZeroOperator;
511
512 template <CheckForMinusZeroMode kMode>
513 struct CheckedFloat64ToInt32Operator final
514 : public Operator1<CheckForMinusZeroMode> {
CheckedFloat64ToInt32Operatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedFloat64ToInt32Operator515 CheckedFloat64ToInt32Operator()
516 : Operator1<CheckForMinusZeroMode>(
517 IrOpcode::kCheckedFloat64ToInt32,
518 Operator::kFoldable | Operator::kNoThrow, "CheckedFloat64ToInt32",
519 1, 1, 1, 1, 1, 0, kMode) {}
520 };
521 CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero>
522 kCheckedFloat64ToInt32CheckForMinusZeroOperator;
523 CheckedFloat64ToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero>
524 kCheckedFloat64ToInt32DontCheckForMinusZeroOperator;
525
526 template <CheckForMinusZeroMode kMode>
527 struct CheckedTaggedToInt32Operator final
528 : public Operator1<CheckForMinusZeroMode> {
CheckedTaggedToInt32Operatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedTaggedToInt32Operator529 CheckedTaggedToInt32Operator()
530 : Operator1<CheckForMinusZeroMode>(
531 IrOpcode::kCheckedTaggedToInt32,
532 Operator::kFoldable | Operator::kNoThrow, "CheckedTaggedToInt32",
533 1, 1, 1, 1, 1, 0, kMode) {}
534 };
535 CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kCheckForMinusZero>
536 kCheckedTaggedToInt32CheckForMinusZeroOperator;
537 CheckedTaggedToInt32Operator<CheckForMinusZeroMode::kDontCheckForMinusZero>
538 kCheckedTaggedToInt32DontCheckForMinusZeroOperator;
539
540 template <CheckTaggedInputMode kMode>
541 struct CheckedTaggedToFloat64Operator final
542 : public Operator1<CheckTaggedInputMode> {
CheckedTaggedToFloat64Operatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedTaggedToFloat64Operator543 CheckedTaggedToFloat64Operator()
544 : Operator1<CheckTaggedInputMode>(
545 IrOpcode::kCheckedTaggedToFloat64,
546 Operator::kFoldable | Operator::kNoThrow,
547 "CheckedTaggedToFloat64", 1, 1, 1, 1, 1, 0, kMode) {}
548 };
549 CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumber>
550 kCheckedTaggedToFloat64NumberOperator;
551 CheckedTaggedToFloat64Operator<CheckTaggedInputMode::kNumberOrOddball>
552 kCheckedTaggedToFloat64NumberOrOddballOperator;
553
554 template <CheckFloat64HoleMode kMode>
555 struct CheckFloat64HoleNaNOperator final
556 : public Operator1<CheckFloat64HoleMode> {
CheckFloat64HoleNaNOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckFloat64HoleNaNOperator557 CheckFloat64HoleNaNOperator()
558 : Operator1<CheckFloat64HoleMode>(
559 IrOpcode::kCheckFloat64Hole,
560 Operator::kFoldable | Operator::kNoThrow, "CheckFloat64Hole", 1,
561 1, 1, 1, 1, 0, kMode) {}
562 };
563 CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kAllowReturnHole>
564 kCheckFloat64HoleAllowReturnHoleOperator;
565 CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kNeverReturnHole>
566 kCheckFloat64HoleNeverReturnHoleOperator;
567
568 template <PretenureFlag kPretenure>
569 struct AllocateOperator final : public Operator1<PretenureFlag> {
AllocateOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::AllocateOperator570 AllocateOperator()
571 : Operator1<PretenureFlag>(
572 IrOpcode::kAllocate,
573 Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite,
574 "Allocate", 1, 1, 1, 1, 1, 0, kPretenure) {}
575 };
576 AllocateOperator<NOT_TENURED> kAllocateNotTenuredOperator;
577 AllocateOperator<TENURED> kAllocateTenuredOperator;
578
579 struct EnsureWritableFastElementsOperator final : public Operator {
EnsureWritableFastElementsOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::EnsureWritableFastElementsOperator580 EnsureWritableFastElementsOperator()
581 : Operator( // --
582 IrOpcode::kEnsureWritableFastElements, // opcode
583 Operator::kNoDeopt | Operator::kNoThrow, // flags
584 "EnsureWritableFastElements", // name
585 2, 1, 1, 1, 1, 0) {} // counts
586 };
587 EnsureWritableFastElementsOperator kEnsureWritableFastElements;
588
589 #define SPECULATIVE_NUMBER_BINOP(Name) \
590 template <NumberOperationHint kHint> \
591 struct Name##Operator final : public Operator1<NumberOperationHint> { \
592 Name##Operator() \
593 : Operator1<NumberOperationHint>( \
594 IrOpcode::k##Name, Operator::kFoldable | Operator::kNoThrow, \
595 #Name, 2, 1, 1, 1, 1, 0, kHint) {} \
596 }; \
597 Name##Operator<NumberOperationHint::kSignedSmall> \
598 k##Name##SignedSmallOperator; \
599 Name##Operator<NumberOperationHint::kSigned32> k##Name##Signed32Operator; \
600 Name##Operator<NumberOperationHint::kNumber> k##Name##NumberOperator; \
601 Name##Operator<NumberOperationHint::kNumberOrOddball> \
602 k##Name##NumberOrOddballOperator;
603 SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
604 #undef SPECULATIVE_NUMBER_BINOP
605
606 #define BUFFER_ACCESS(Type, type, TYPE, ctype, size) \
607 struct LoadBuffer##Type##Operator final : public Operator1<BufferAccess> { \
608 LoadBuffer##Type##Operator() \
609 : Operator1<BufferAccess>( \
610 IrOpcode::kLoadBuffer, \
611 Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, \
612 "LoadBuffer", 3, 1, 1, 1, 1, 0, \
613 BufferAccess(kExternal##Type##Array)) {} \
614 }; \
615 struct StoreBuffer##Type##Operator final : public Operator1<BufferAccess> { \
616 StoreBuffer##Type##Operator() \
617 : Operator1<BufferAccess>( \
618 IrOpcode::kStoreBuffer, \
619 Operator::kNoDeopt | Operator::kNoRead | Operator::kNoThrow, \
620 "StoreBuffer", 4, 1, 1, 0, 1, 0, \
621 BufferAccess(kExternal##Type##Array)) {} \
622 }; \
623 LoadBuffer##Type##Operator kLoadBuffer##Type; \
624 StoreBuffer##Type##Operator kStoreBuffer##Type;
625 TYPED_ARRAYS(BUFFER_ACCESS)
626 #undef BUFFER_ACCESS
627 };
628
629
630 static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
631 LAZY_INSTANCE_INITIALIZER;
632
633
SimplifiedOperatorBuilder(Zone * zone)634 SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
635 : cache_(kCache.Get()), zone_(zone) {}
636
637 #define GET_FROM_CACHE(Name, ...) \
638 const Operator* SimplifiedOperatorBuilder::Name() { return &cache_.k##Name; }
639 PURE_OP_LIST(GET_FROM_CACHE)
CHECKED_OP_LIST(GET_FROM_CACHE)640 CHECKED_OP_LIST(GET_FROM_CACHE)
641 GET_FROM_CACHE(ArrayBufferWasNeutered)
642 #undef GET_FROM_CACHE
643
644 const Operator* SimplifiedOperatorBuilder::CheckedInt32Mul(
645 CheckForMinusZeroMode mode) {
646 switch (mode) {
647 case CheckForMinusZeroMode::kCheckForMinusZero:
648 return &cache_.kCheckedInt32MulCheckForMinusZeroOperator;
649 case CheckForMinusZeroMode::kDontCheckForMinusZero:
650 return &cache_.kCheckedInt32MulDontCheckForMinusZeroOperator;
651 }
652 UNREACHABLE();
653 return nullptr;
654 }
655
CheckedFloat64ToInt32(CheckForMinusZeroMode mode)656 const Operator* SimplifiedOperatorBuilder::CheckedFloat64ToInt32(
657 CheckForMinusZeroMode mode) {
658 switch (mode) {
659 case CheckForMinusZeroMode::kCheckForMinusZero:
660 return &cache_.kCheckedFloat64ToInt32CheckForMinusZeroOperator;
661 case CheckForMinusZeroMode::kDontCheckForMinusZero:
662 return &cache_.kCheckedFloat64ToInt32DontCheckForMinusZeroOperator;
663 }
664 UNREACHABLE();
665 return nullptr;
666 }
667
CheckedTaggedToInt32(CheckForMinusZeroMode mode)668 const Operator* SimplifiedOperatorBuilder::CheckedTaggedToInt32(
669 CheckForMinusZeroMode mode) {
670 switch (mode) {
671 case CheckForMinusZeroMode::kCheckForMinusZero:
672 return &cache_.kCheckedTaggedToInt32CheckForMinusZeroOperator;
673 case CheckForMinusZeroMode::kDontCheckForMinusZero:
674 return &cache_.kCheckedTaggedToInt32DontCheckForMinusZeroOperator;
675 }
676 UNREACHABLE();
677 return nullptr;
678 }
679
CheckedTaggedToFloat64(CheckTaggedInputMode mode)680 const Operator* SimplifiedOperatorBuilder::CheckedTaggedToFloat64(
681 CheckTaggedInputMode mode) {
682 switch (mode) {
683 case CheckTaggedInputMode::kNumber:
684 return &cache_.kCheckedTaggedToFloat64NumberOperator;
685 case CheckTaggedInputMode::kNumberOrOddball:
686 return &cache_.kCheckedTaggedToFloat64NumberOrOddballOperator;
687 }
688 UNREACHABLE();
689 return nullptr;
690 }
691
CheckMaps(int map_input_count)692 const Operator* SimplifiedOperatorBuilder::CheckMaps(int map_input_count) {
693 // TODO(bmeurer): Cache the most important versions of this operator.
694 DCHECK_LT(0, map_input_count);
695 int const value_input_count = 1 + map_input_count;
696 return new (zone()) Operator1<int>( // --
697 IrOpcode::kCheckMaps, // opcode
698 Operator::kNoThrow | Operator::kNoWrite, // flags
699 "CheckMaps", // name
700 value_input_count, 1, 1, 0, 1, 0, // counts
701 map_input_count); // parameter
702 }
703
CheckFloat64Hole(CheckFloat64HoleMode mode)704 const Operator* SimplifiedOperatorBuilder::CheckFloat64Hole(
705 CheckFloat64HoleMode mode) {
706 switch (mode) {
707 case CheckFloat64HoleMode::kAllowReturnHole:
708 return &cache_.kCheckFloat64HoleAllowReturnHoleOperator;
709 case CheckFloat64HoleMode::kNeverReturnHole:
710 return &cache_.kCheckFloat64HoleNeverReturnHoleOperator;
711 }
712 UNREACHABLE();
713 return nullptr;
714 }
715
EnsureWritableFastElements()716 const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() {
717 return &cache_.kEnsureWritableFastElements;
718 }
719
MaybeGrowFastElements(GrowFastElementsFlags flags)720 const Operator* SimplifiedOperatorBuilder::MaybeGrowFastElements(
721 GrowFastElementsFlags flags) {
722 return new (zone()) Operator1<GrowFastElementsFlags>( // --
723 IrOpcode::kMaybeGrowFastElements, // opcode
724 Operator::kNoThrow, // flags
725 "MaybeGrowFastElements", // name
726 4, 1, 1, 1, 1, 0, // counts
727 flags); // parameter
728 }
729
TransitionElementsKind(ElementsTransition transition)730 const Operator* SimplifiedOperatorBuilder::TransitionElementsKind(
731 ElementsTransition transition) {
732 return new (zone()) Operator1<ElementsTransition>( // --
733 IrOpcode::kTransitionElementsKind, // opcode
734 Operator::kNoDeopt | Operator::kNoThrow, // flags
735 "TransitionElementsKind", // name
736 3, 1, 1, 0, 1, 0, // counts
737 transition); // parameter
738 }
739
Allocate(PretenureFlag pretenure)740 const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
741 switch (pretenure) {
742 case NOT_TENURED:
743 return &cache_.kAllocateNotTenuredOperator;
744 case TENURED:
745 return &cache_.kAllocateTenuredOperator;
746 }
747 UNREACHABLE();
748 return nullptr;
749 }
750
751
LoadBuffer(BufferAccess access)752 const Operator* SimplifiedOperatorBuilder::LoadBuffer(BufferAccess access) {
753 switch (access.external_array_type()) {
754 #define LOAD_BUFFER(Type, type, TYPE, ctype, size) \
755 case kExternal##Type##Array: \
756 return &cache_.kLoadBuffer##Type;
757 TYPED_ARRAYS(LOAD_BUFFER)
758 #undef LOAD_BUFFER
759 }
760 UNREACHABLE();
761 return nullptr;
762 }
763
764
StoreBuffer(BufferAccess access)765 const Operator* SimplifiedOperatorBuilder::StoreBuffer(BufferAccess access) {
766 switch (access.external_array_type()) {
767 #define STORE_BUFFER(Type, type, TYPE, ctype, size) \
768 case kExternal##Type##Array: \
769 return &cache_.kStoreBuffer##Type;
770 TYPED_ARRAYS(STORE_BUFFER)
771 #undef STORE_BUFFER
772 }
773 UNREACHABLE();
774 return nullptr;
775 }
776
StringFromCodePoint(UnicodeEncoding encoding)777 const Operator* SimplifiedOperatorBuilder::StringFromCodePoint(
778 UnicodeEncoding encoding) {
779 switch (encoding) {
780 case UnicodeEncoding::UTF16:
781 return &cache_.kStringFromCodePointOperatorUTF16;
782 case UnicodeEncoding::UTF32:
783 return &cache_.kStringFromCodePointOperatorUTF32;
784 }
785 UNREACHABLE();
786 return nullptr;
787 }
788
789 #define SPECULATIVE_NUMBER_BINOP(Name) \
790 const Operator* SimplifiedOperatorBuilder::Name(NumberOperationHint hint) { \
791 switch (hint) { \
792 case NumberOperationHint::kSignedSmall: \
793 return &cache_.k##Name##SignedSmallOperator; \
794 case NumberOperationHint::kSigned32: \
795 return &cache_.k##Name##Signed32Operator; \
796 case NumberOperationHint::kNumber: \
797 return &cache_.k##Name##NumberOperator; \
798 case NumberOperationHint::kNumberOrOddball: \
799 return &cache_.k##Name##NumberOrOddballOperator; \
800 } \
801 UNREACHABLE(); \
802 return nullptr; \
803 }
804 SPECULATIVE_NUMBER_BINOP_LIST(SPECULATIVE_NUMBER_BINOP)
805 #undef SPECULATIVE_NUMBER_BINOP
806
807 #define ACCESS_OP_LIST(V) \
808 V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1, 1) \
809 V(StoreField, FieldAccess, Operator::kNoRead, 2, 1, 0) \
810 V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1, 1) \
811 V(StoreElement, ElementAccess, Operator::kNoRead, 3, 1, 0) \
812 V(LoadTypedElement, ExternalArrayType, Operator::kNoWrite, 4, 1, 1) \
813 V(StoreTypedElement, ExternalArrayType, Operator::kNoRead, 5, 1, 0)
814
815 #define ACCESS(Name, Type, properties, value_input_count, control_input_count, \
816 output_count) \
817 const Operator* SimplifiedOperatorBuilder::Name(const Type& access) { \
818 return new (zone()) \
819 Operator1<Type>(IrOpcode::k##Name, \
820 Operator::kNoDeopt | Operator::kNoThrow | properties, \
821 #Name, value_input_count, 1, control_input_count, \
822 output_count, 1, 0, access); \
823 }
824 ACCESS_OP_LIST(ACCESS)
825 #undef ACCESS
826
827 } // namespace compiler
828 } // namespace internal
829 } // namespace v8
830