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