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