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.map.address() == rhs.map.address() &&
96 lhs.machine_type == rhs.machine_type;
97 }
98
99
operator !=(FieldAccess const & lhs,FieldAccess const & rhs)100 bool operator!=(FieldAccess const& lhs, FieldAccess const& rhs) {
101 return !(lhs == rhs);
102 }
103
104
hash_value(FieldAccess const & access)105 size_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
operator <<(std::ostream & os,FieldAccess const & access)114 std::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
132 template <>
PrintParameter(std::ostream & os,PrintVerbosity verbose) const133 void 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
operator ==(ElementAccess const & lhs,ElementAccess const & rhs)142 bool 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
operator !=(ElementAccess const & lhs,ElementAccess const & rhs)152 bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
153 return !(lhs == rhs);
154 }
155
156
hash_value(ElementAccess const & access)157 size_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
operator <<(std::ostream & os,ElementAccess const & access)166 std::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
FieldAccessOf(const Operator * op)174 const 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
ElementAccessOf(const Operator * op)182 const 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
ExternalArrayTypeOf(const Operator * op)189 ExternalArrayType ExternalArrayTypeOf(const Operator* op) {
190 DCHECK(op->opcode() == IrOpcode::kLoadTypedElement ||
191 op->opcode() == IrOpcode::kStoreTypedElement);
192 return OpParameter<ExternalArrayType>(op);
193 }
194
hash_value(CheckFloat64HoleMode mode)195 size_t hash_value(CheckFloat64HoleMode mode) {
196 return static_cast<size_t>(mode);
197 }
198
operator <<(std::ostream & os,CheckFloat64HoleMode mode)199 std::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
CheckFloat64HoleModeOf(const Operator * op)210 CheckFloat64HoleMode CheckFloat64HoleModeOf(const Operator* op) {
211 DCHECK_EQ(IrOpcode::kCheckFloat64Hole, op->opcode());
212 return OpParameter<CheckFloat64HoleMode>(op);
213 }
214
CheckMinusZeroModeOf(const Operator * op)215 CheckForMinusZeroMode 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
hash_value(CheckForMinusZeroMode mode)222 size_t hash_value(CheckForMinusZeroMode mode) {
223 return static_cast<size_t>(mode);
224 }
225
operator <<(std::ostream & os,CheckForMinusZeroMode mode)226 std::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
operator <<(std::ostream & os,CheckMapsFlags flags)237 std::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
operator ==(CheckMapsParameters const & lhs,CheckMapsParameters const & rhs)247 bool operator==(CheckMapsParameters const& lhs,
248 CheckMapsParameters const& rhs) {
249 return lhs.flags() == rhs.flags() && lhs.maps() == rhs.maps();
250 }
251
operator !=(CheckMapsParameters const & lhs,CheckMapsParameters const & rhs)252 bool operator!=(CheckMapsParameters const& lhs,
253 CheckMapsParameters const& rhs) {
254 return !(lhs == rhs);
255 }
256
hash_value(CheckMapsParameters const & p)257 size_t hash_value(CheckMapsParameters const& p) {
258 return base::hash_combine(p.flags(), p.maps());
259 }
260
operator <<(std::ostream & os,CheckMapsParameters const & p)261 std::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
CheckMapsParametersOf(Operator const * op)270 CheckMapsParameters const& CheckMapsParametersOf(Operator const* op) {
271 DCHECK_EQ(IrOpcode::kCheckMaps, op->opcode());
272 return OpParameter<CheckMapsParameters>(op);
273 }
274
hash_value(CheckTaggedInputMode mode)275 size_t hash_value(CheckTaggedInputMode mode) {
276 return static_cast<size_t>(mode);
277 }
278
operator <<(std::ostream & os,CheckTaggedInputMode mode)279 std::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
CheckTaggedInputModeOf(const Operator * op)290 CheckTaggedInputMode CheckTaggedInputModeOf(const Operator* op) {
291 DCHECK_EQ(IrOpcode::kCheckedTaggedToFloat64, op->opcode());
292 return OpParameter<CheckTaggedInputMode>(op);
293 }
294
operator <<(std::ostream & os,GrowFastElementsFlags flags)295 std::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
GrowFastElementsFlagsOf(const Operator * op)315 GrowFastElementsFlags GrowFastElementsFlagsOf(const Operator* op) {
316 DCHECK_EQ(IrOpcode::kMaybeGrowFastElements, op->opcode());
317 return OpParameter<GrowFastElementsFlags>(op);
318 }
319
operator ==(ElementsTransition const & lhs,ElementsTransition const & rhs)320 bool 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
operator !=(ElementsTransition const & lhs,ElementsTransition const & rhs)326 bool operator!=(ElementsTransition const& lhs, ElementsTransition const& rhs) {
327 return !(lhs == rhs);
328 }
329
hash_value(ElementsTransition transition)330 size_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
operator <<(std::ostream & os,ElementsTransition transition)336 std::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
ElementsTransitionOf(const Operator * op)349 ElementsTransition const& ElementsTransitionOf(const Operator* op) {
350 DCHECK_EQ(IrOpcode::kTransitionElementsKind, op->opcode());
351 return OpParameter<ElementsTransition>(op);
352 }
353
operator <<(std::ostream & os,NumberOperationHint hint)354 std::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
hash_value(NumberOperationHint hint)369 size_t hash_value(NumberOperationHint hint) {
370 return static_cast<uint8_t>(hint);
371 }
372
NumberOperationHintOf(const Operator * op)373 NumberOperationHint 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
ParameterCountOf(const Operator * op)391 int ParameterCountOf(const Operator* op) {
392 DCHECK(op->opcode() == IrOpcode::kNewUnmappedArgumentsElements ||
393 op->opcode() == IrOpcode::kNewRestParameterElements);
394 return OpParameter<int>(op);
395 }
396
PretenureFlagOf(const Operator * op)397 PretenureFlag PretenureFlagOf(const Operator* op) {
398 DCHECK_EQ(IrOpcode::kAllocate, op->opcode());
399 return OpParameter<PretenureFlag>(op);
400 }
401
UnicodeEncodingOf(const Operator * op)402 UnicodeEncoding 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
526 struct 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> {
StringFromCodePointOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::StringFromCodePointOperator550 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 {
ArrayBufferWasNeuteredOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::ArrayBufferWasNeuteredOperator561 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> {
CheckedInt32MulOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedInt32MulOperator570 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> {
CheckedFloat64ToInt32Operatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedFloat64ToInt32Operator584 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> {
CheckedTaggedToInt32Operatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedTaggedToInt32Operator598 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> {
CheckedTaggedToFloat64Operatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckedTaggedToFloat64Operator612 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> {
CheckFloat64HoleNaNOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::CheckFloat64HoleNaNOperator626 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> {
AllocateOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::AllocateOperator639 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 {
EnsureWritableFastElementsOperatorv8::internal::compiler::SimplifiedOperatorGlobalCache::EnsureWritableFastElementsOperator649 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
699 static base::LazyInstance<SimplifiedOperatorGlobalCache>::type kCache =
700 LAZY_INSTANCE_INITIALIZER;
701
702
SimplifiedOperatorBuilder(Zone * zone)703 SimplifiedOperatorBuilder::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; }
708 PURE_OP_LIST(GET_FROM_CACHE)
CHECKED_OP_LIST(GET_FROM_CACHE)709 CHECKED_OP_LIST(GET_FROM_CACHE)
710 GET_FROM_CACHE(ArrayBufferWasNeutered)
711 #undef GET_FROM_CACHE
712
713 const 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
CheckedFloat64ToInt32(CheckForMinusZeroMode mode)725 const 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
CheckedTaggedToInt32(CheckForMinusZeroMode mode)737 const 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
CheckedTaggedToFloat64(CheckTaggedInputMode mode)749 const 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
CheckMaps(CheckMapsFlags flags,ZoneHandleSet<Map> maps)761 const 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
CheckFloat64Hole(CheckFloat64HoleMode mode)772 const 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
EnsureWritableFastElements()784 const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() {
785 return &cache_.kEnsureWritableFastElements;
786 }
787
MaybeGrowFastElements(GrowFastElementsFlags flags)788 const 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
TransitionElementsKind(ElementsTransition transition)798 const 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
NewUnmappedArgumentsElements(int parameter_count)808 const 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
NewRestParameterElements(int parameter_count)818 const 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
Allocate(PretenureFlag pretenure)828 const 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
LoadBuffer(BufferAccess access)840 const 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
StoreBuffer(BufferAccess access)853 const 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
StringFromCodePoint(UnicodeEncoding encoding)865 const 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 }
892 SPECULATIVE_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 }
912 ACCESS_OP_LIST(ACCESS)
913 #undef ACCESS
914
915 } // namespace compiler
916 } // namespace internal
917 } // namespace v8
918