Line data Source code
1 : // Copyright 2014 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 : #ifndef V8_COMPILER_BACKEND_INSTRUCTION_H_
6 : #define V8_COMPILER_BACKEND_INSTRUCTION_H_
7 :
8 : #include <deque>
9 : #include <iosfwd>
10 : #include <map>
11 : #include <set>
12 :
13 : #include "src/base/compiler-specific.h"
14 : #include "src/compiler/backend/instruction-codes.h"
15 : #include "src/compiler/common-operator.h"
16 : #include "src/compiler/frame.h"
17 : #include "src/compiler/opcodes.h"
18 : #include "src/double.h"
19 : #include "src/external-reference.h"
20 : #include "src/globals.h"
21 : #include "src/register-arch.h"
22 : #include "src/source-position.h"
23 : #include "src/zone/zone-allocator.h"
24 :
25 : namespace v8 {
26 : namespace internal {
27 :
28 : class RegisterConfiguration;
29 :
30 : namespace compiler {
31 :
32 : class Schedule;
33 : class SourcePositionTable;
34 :
35 : class V8_EXPORT_PRIVATE InstructionOperand {
36 : public:
37 : static const int kInvalidVirtualRegister = -1;
38 :
39 : enum Kind {
40 : INVALID,
41 : UNALLOCATED,
42 : CONSTANT,
43 : IMMEDIATE,
44 : // Location operand kinds.
45 : EXPLICIT,
46 : ALLOCATED,
47 : FIRST_LOCATION_OPERAND_KIND = EXPLICIT
48 : // Location operand kinds must be last.
49 : };
50 :
51 : InstructionOperand() : InstructionOperand(INVALID) {}
52 :
53 3528417530 : Kind kind() const { return KindField::decode(value_); }
54 :
55 : #define INSTRUCTION_OPERAND_PREDICATE(name, type) \
56 : bool Is##name() const { return kind() == type; }
57 : INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID)
58 : // UnallocatedOperands are place-holder operands created before register
59 : // allocation. They later are assigned registers and become AllocatedOperands.
60 1 : INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
61 : // Constant operands participate in register allocation. They are allocated to
62 : // registers but have a special "spilling" behavior. When a ConstantOperand
63 : // value must be rematerialized, it is loaded from an immediate constant
64 : // rather from an unspilled slot.
65 2594825 : INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT)
66 : // ImmediateOperands do not participate in register allocation and are only
67 : // embedded directly in instructions, e.g. small integers and on some
68 : // platforms Objects.
69 84754 : INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE)
70 : // ExplicitOperands do not participate in register allocation. They are
71 : // created by the instruction selector for direct access to registers and
72 : // stack slots, completely bypassing the register allocator. They are never
73 : // associated with a virtual register
74 : INSTRUCTION_OPERAND_PREDICATE(Explicit, EXPLICIT)
75 : // AllocatedOperands are registers or stack slots that are assigned by the
76 : // register allocator and are always associated with a virtual register.
77 : INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED)
78 : #undef INSTRUCTION_OPERAND_PREDICATE
79 :
80 : inline bool IsAnyLocationOperand() const;
81 : inline bool IsLocationOperand() const;
82 : inline bool IsFPLocationOperand() const;
83 : inline bool IsAnyRegister() const;
84 : inline bool IsRegister() const;
85 : inline bool IsFPRegister() const;
86 : inline bool IsFloatRegister() const;
87 : inline bool IsDoubleRegister() const;
88 : inline bool IsSimd128Register() const;
89 : inline bool IsAnyStackSlot() const;
90 : inline bool IsStackSlot() const;
91 : inline bool IsFPStackSlot() const;
92 : inline bool IsFloatStackSlot() const;
93 : inline bool IsDoubleStackSlot() const;
94 : inline bool IsSimd128StackSlot() const;
95 :
96 : template <typename SubKindOperand>
97 : static SubKindOperand* New(Zone* zone, const SubKindOperand& op) {
98 0 : void* buffer = zone->New(sizeof(op));
99 0 : return new (buffer) SubKindOperand(op);
100 : }
101 :
102 : static void ReplaceWith(InstructionOperand* dest,
103 : const InstructionOperand* src) {
104 47681941 : *dest = *src;
105 : }
106 :
107 : bool Equals(const InstructionOperand& that) const {
108 29947701 : return this->value_ == that.value_;
109 : }
110 :
111 : bool Compare(const InstructionOperand& that) const {
112 0 : return this->value_ < that.value_;
113 : }
114 :
115 : bool EqualsCanonicalized(const InstructionOperand& that) const {
116 665044717 : return this->GetCanonicalizedValue() == that.GetCanonicalizedValue();
117 : }
118 :
119 : bool CompareCanonicalized(const InstructionOperand& that) const {
120 58690751 : return this->GetCanonicalizedValue() < that.GetCanonicalizedValue();
121 : }
122 :
123 : bool InterferesWith(const InstructionOperand& other) const;
124 :
125 : // APIs to aid debugging. For general-stream APIs, use operator<<.
126 : void Print() const;
127 :
128 : protected:
129 210397168 : explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {}
130 :
131 : inline uint64_t GetCanonicalizedValue() const;
132 :
133 : class KindField : public BitField64<Kind, 0, 3> {};
134 :
135 : uint64_t value_;
136 : };
137 :
138 : typedef ZoneVector<InstructionOperand> InstructionOperandVector;
139 :
140 : std::ostream& operator<<(std::ostream&, const InstructionOperand&);
141 :
142 : #define INSTRUCTION_OPERAND_CASTS(OperandType, OperandKind) \
143 : \
144 : static OperandType* cast(InstructionOperand* op) { \
145 : DCHECK_EQ(OperandKind, op->kind()); \
146 : return static_cast<OperandType*>(op); \
147 : } \
148 : \
149 : static const OperandType* cast(const InstructionOperand* op) { \
150 : DCHECK_EQ(OperandKind, op->kind()); \
151 : return static_cast<const OperandType*>(op); \
152 : } \
153 : \
154 : static OperandType cast(const InstructionOperand& op) { \
155 : DCHECK_EQ(OperandKind, op.kind()); \
156 : return *static_cast<const OperandType*>(&op); \
157 : }
158 :
159 : class UnallocatedOperand final : public InstructionOperand {
160 : public:
161 : enum BasicPolicy { FIXED_SLOT, EXTENDED_POLICY };
162 :
163 : enum ExtendedPolicy {
164 : NONE,
165 : REGISTER_OR_SLOT,
166 : REGISTER_OR_SLOT_OR_CONSTANT,
167 : FIXED_REGISTER,
168 : FIXED_FP_REGISTER,
169 : MUST_HAVE_REGISTER,
170 : MUST_HAVE_SLOT,
171 : SAME_AS_FIRST_INPUT
172 : };
173 :
174 : // Lifetime of operand inside the instruction.
175 : enum Lifetime {
176 : // USED_AT_START operand is guaranteed to be live only at instruction start.
177 : // The register allocator is free to assign the same register to some other
178 : // operand used inside instruction (i.e. temporary or output).
179 : USED_AT_START,
180 :
181 : // USED_AT_END operand is treated as live until the end of instruction.
182 : // This means that register allocator will not reuse its register for any
183 : // other operand inside instruction.
184 : USED_AT_END
185 : };
186 :
187 : UnallocatedOperand(ExtendedPolicy policy, int virtual_register)
188 : : UnallocatedOperand(virtual_register) {
189 37769296 : value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
190 35670394 : value_ |= ExtendedPolicyField::encode(policy);
191 66743682 : value_ |= LifetimeField::encode(USED_AT_END);
192 : }
193 :
194 : UnallocatedOperand(BasicPolicy policy, int index, int virtual_register)
195 : : UnallocatedOperand(virtual_register) {
196 : DCHECK(policy == FIXED_SLOT);
197 0 : value_ |= BasicPolicyField::encode(policy);
198 : value_ |= static_cast<uint64_t>(static_cast<int64_t>(index))
199 4305908 : << FixedSlotIndexField::kShift;
200 : DCHECK(this->fixed_slot_index() == index);
201 : }
202 :
203 : UnallocatedOperand(ExtendedPolicy policy, int index, int virtual_register)
204 : : UnallocatedOperand(virtual_register) {
205 : DCHECK(policy == FIXED_REGISTER || policy == FIXED_FP_REGISTER);
206 122 : value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
207 122 : value_ |= ExtendedPolicyField::encode(policy);
208 26724527 : value_ |= LifetimeField::encode(USED_AT_END);
209 26724527 : value_ |= FixedRegisterField::encode(index);
210 : }
211 :
212 : UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime,
213 : int virtual_register)
214 : : UnallocatedOperand(virtual_register) {
215 5312263 : value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
216 29184287 : value_ |= ExtendedPolicyField::encode(policy);
217 2379411 : value_ |= LifetimeField::encode(lifetime);
218 : }
219 :
220 : UnallocatedOperand(int reg_id, int slot_id, int virtual_register)
221 : : UnallocatedOperand(FIXED_REGISTER, reg_id, virtual_register) {
222 73100 : value_ |= HasSecondaryStorageField::encode(true);
223 73100 : value_ |= SecondaryStorageField::encode(slot_id);
224 : }
225 :
226 : UnallocatedOperand(const UnallocatedOperand& other, int virtual_register) {
227 : DCHECK_NE(kInvalidVirtualRegister, virtual_register);
228 : value_ = VirtualRegisterField::update(
229 5268174 : other.value_, static_cast<uint32_t>(virtual_register));
230 : }
231 :
232 : // Predicates for the operand policy.
233 : bool HasRegisterOrSlotPolicy() const {
234 99051918 : return basic_policy() == EXTENDED_POLICY &&
235 : extended_policy() == REGISTER_OR_SLOT;
236 : }
237 : bool HasRegisterOrSlotOrConstantPolicy() const {
238 99052108 : return basic_policy() == EXTENDED_POLICY &&
239 : extended_policy() == REGISTER_OR_SLOT_OR_CONSTANT;
240 : }
241 : bool HasFixedPolicy() const {
242 91934379 : return basic_policy() == FIXED_SLOT ||
243 158537024 : extended_policy() == FIXED_REGISTER ||
244 : extended_policy() == FIXED_FP_REGISTER;
245 : }
246 : bool HasRegisterPolicy() const {
247 209311880 : return basic_policy() == EXTENDED_POLICY &&
248 : extended_policy() == MUST_HAVE_REGISTER;
249 : }
250 : bool HasSlotPolicy() const {
251 230969098 : return basic_policy() == EXTENDED_POLICY &&
252 : extended_policy() == MUST_HAVE_SLOT;
253 : }
254 : bool HasSameAsInputPolicy() const {
255 43749962 : return basic_policy() == EXTENDED_POLICY &&
256 : extended_policy() == SAME_AS_FIRST_INPUT;
257 : }
258 : bool HasFixedSlotPolicy() const { return basic_policy() == FIXED_SLOT; }
259 : bool HasFixedRegisterPolicy() const {
260 53382245 : return basic_policy() == EXTENDED_POLICY &&
261 : extended_policy() == FIXED_REGISTER;
262 : }
263 : bool HasFixedFPRegisterPolicy() const {
264 290443 : return basic_policy() == EXTENDED_POLICY &&
265 : extended_policy() == FIXED_FP_REGISTER;
266 : }
267 : bool HasSecondaryStorage() const {
268 7978201 : return basic_policy() == EXTENDED_POLICY &&
269 17013595 : extended_policy() == FIXED_REGISTER &&
270 : HasSecondaryStorageField::decode(value_);
271 : }
272 : int GetSecondaryStorage() const {
273 : DCHECK(HasSecondaryStorage());
274 73043 : return SecondaryStorageField::decode(value_);
275 : }
276 :
277 : // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
278 216062979 : BasicPolicy basic_policy() const { return BasicPolicyField::decode(value_); }
279 :
280 : // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
281 : ExtendedPolicy extended_policy() const {
282 : DCHECK(basic_policy() == EXTENDED_POLICY);
283 : return ExtendedPolicyField::decode(value_);
284 : }
285 :
286 : // [fixed_slot_index]: Only for FIXED_SLOT.
287 : int fixed_slot_index() const {
288 : DCHECK(HasFixedSlotPolicy());
289 4300277 : return static_cast<int>(static_cast<int64_t>(value_) >>
290 4300277 : FixedSlotIndexField::kShift);
291 : }
292 :
293 : // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_FP_REGISTER.
294 : int fixed_register_index() const {
295 : DCHECK(HasFixedRegisterPolicy() || HasFixedFPRegisterPolicy());
296 122 : return FixedRegisterField::decode(value_);
297 : }
298 :
299 : // [virtual_register]: The virtual register ID for this operand.
300 : int32_t virtual_register() const {
301 410915718 : return static_cast<int32_t>(VirtualRegisterField::decode(value_));
302 : }
303 :
304 : // [lifetime]: Only for non-FIXED_SLOT.
305 : bool IsUsedAtStart() const {
306 : DCHECK(basic_policy() == EXTENDED_POLICY);
307 2 : return LifetimeField::decode(value_) == USED_AT_START;
308 : }
309 :
310 30632148 : INSTRUCTION_OPERAND_CASTS(UnallocatedOperand, UNALLOCATED)
311 :
312 : // The encoding used for UnallocatedOperand operands depends on the policy
313 : // that is
314 : // stored within the operand. The FIXED_SLOT policy uses a compact encoding
315 : // because it accommodates a larger pay-load.
316 : //
317 : // For FIXED_SLOT policy:
318 : // +------------------------------------------------+
319 : // | slot_index | 0 | virtual_register | 001 |
320 : // +------------------------------------------------+
321 : //
322 : // For all other (extended) policies:
323 : // +-----------------------------------------------------+
324 : // | reg_index | L | PPP | 1 | virtual_register | 001 |
325 : // +-----------------------------------------------------+
326 : // L ... Lifetime
327 : // P ... Policy
328 : //
329 : // The slot index is a signed value which requires us to decode it manually
330 : // instead of using the BitField utility class.
331 :
332 : STATIC_ASSERT(KindField::kSize == 3);
333 :
334 : class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {};
335 :
336 : // BitFields for all unallocated operands.
337 : class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {};
338 :
339 : // BitFields specific to BasicPolicy::FIXED_SLOT.
340 : class FixedSlotIndexField : public BitField64<int, 36, 28> {};
341 :
342 : // BitFields specific to BasicPolicy::EXTENDED_POLICY.
343 : class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {};
344 : class LifetimeField : public BitField64<Lifetime, 39, 1> {};
345 : class HasSecondaryStorageField : public BitField64<bool, 40, 1> {};
346 : class FixedRegisterField : public BitField64<int, 41, 6> {};
347 : class SecondaryStorageField : public BitField64<int, 47, 3> {};
348 :
349 : private:
350 : explicit UnallocatedOperand(int virtual_register)
351 : : InstructionOperand(UNALLOCATED) {
352 : value_ |=
353 174626380 : VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register));
354 : }
355 : };
356 :
357 : class ConstantOperand : public InstructionOperand {
358 : public:
359 : explicit ConstantOperand(int virtual_register)
360 : : InstructionOperand(CONSTANT) {
361 : value_ |=
362 25373633 : VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register));
363 : }
364 :
365 : int32_t virtual_register() const {
366 56470797 : return static_cast<int32_t>(VirtualRegisterField::decode(value_));
367 : }
368 :
369 : static ConstantOperand* New(Zone* zone, int virtual_register) {
370 : return InstructionOperand::New(zone, ConstantOperand(virtual_register));
371 : }
372 :
373 16 : INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT)
374 :
375 : STATIC_ASSERT(KindField::kSize == 3);
376 : class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {};
377 : };
378 :
379 : class ImmediateOperand : public InstructionOperand {
380 : public:
381 : enum ImmediateType { INLINE, INDEXED };
382 :
383 : explicit ImmediateOperand(ImmediateType type, int32_t value)
384 : : InstructionOperand(IMMEDIATE) {
385 : value_ |= TypeField::encode(type);
386 : value_ |= static_cast<uint64_t>(static_cast<int64_t>(value))
387 62970662 : << ValueField::kShift;
388 : }
389 :
390 63591860 : ImmediateType type() const { return TypeField::decode(value_); }
391 :
392 : int32_t inline_value() const {
393 : DCHECK_EQ(INLINE, type());
394 17200079 : return static_cast<int64_t>(value_) >> ValueField::kShift;
395 : }
396 :
397 : int32_t indexed_value() const {
398 : DCHECK_EQ(INDEXED, type());
399 46392508 : return static_cast<int64_t>(value_) >> ValueField::kShift;
400 : }
401 :
402 : static ImmediateOperand* New(Zone* zone, ImmediateType type, int32_t value) {
403 : return InstructionOperand::New(zone, ImmediateOperand(type, value));
404 : }
405 :
406 : INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE)
407 :
408 : STATIC_ASSERT(KindField::kSize == 3);
409 : class TypeField : public BitField64<ImmediateType, 3, 1> {};
410 : class ValueField : public BitField64<int32_t, 32, 32> {};
411 : };
412 :
413 : class LocationOperand : public InstructionOperand {
414 : public:
415 : enum LocationKind { REGISTER, STACK_SLOT };
416 :
417 : LocationOperand(InstructionOperand::Kind operand_kind,
418 : LocationOperand::LocationKind location_kind,
419 : MachineRepresentation rep, int index)
420 : : InstructionOperand(operand_kind) {
421 : DCHECK_IMPLIES(location_kind == REGISTER, index >= 0);
422 : DCHECK(IsSupportedRepresentation(rep));
423 719998 : value_ |= LocationKindField::encode(location_kind);
424 134858879 : value_ |= RepresentationField::encode(rep);
425 : value_ |= static_cast<uint64_t>(static_cast<int64_t>(index))
426 134877879 : << IndexField::kShift;
427 : }
428 :
429 : int index() const {
430 : DCHECK(IsStackSlot() || IsFPStackSlot());
431 73624451 : return static_cast<int64_t>(value_) >> IndexField::kShift;
432 : }
433 :
434 : int register_code() const {
435 : DCHECK(IsRegister() || IsFPRegister());
436 185896725 : return static_cast<int64_t>(value_) >> IndexField::kShift;
437 : }
438 :
439 : Register GetRegister() const {
440 : DCHECK(IsRegister());
441 : return Register::from_code(register_code());
442 : }
443 :
444 : FloatRegister GetFloatRegister() const {
445 : DCHECK(IsFloatRegister());
446 : return FloatRegister::from_code(register_code());
447 : }
448 :
449 : DoubleRegister GetDoubleRegister() const {
450 : // On platforms where FloatRegister, DoubleRegister, and Simd128Register
451 : // are all the same type, it's convenient to treat everything as a
452 : // DoubleRegister, so be lax about type checking here.
453 : DCHECK(IsFPRegister());
454 : return DoubleRegister::from_code(register_code());
455 : }
456 :
457 : Simd128Register GetSimd128Register() const {
458 : DCHECK(IsSimd128Register());
459 : return Simd128Register::from_code(register_code());
460 : }
461 :
462 : LocationKind location_kind() const {
463 : return LocationKindField::decode(value_);
464 : }
465 :
466 : MachineRepresentation representation() const {
467 32754 : return RepresentationField::decode(value_);
468 : }
469 :
470 : static bool IsSupportedRepresentation(MachineRepresentation rep) {
471 : switch (rep) {
472 : case MachineRepresentation::kWord32:
473 : case MachineRepresentation::kWord64:
474 : case MachineRepresentation::kFloat32:
475 : case MachineRepresentation::kFloat64:
476 : case MachineRepresentation::kSimd128:
477 : case MachineRepresentation::kTaggedSigned:
478 : case MachineRepresentation::kTaggedPointer:
479 : case MachineRepresentation::kTagged:
480 : return true;
481 : case MachineRepresentation::kBit:
482 : case MachineRepresentation::kWord8:
483 : case MachineRepresentation::kWord16:
484 : case MachineRepresentation::kNone:
485 : return false;
486 : }
487 : UNREACHABLE();
488 : }
489 :
490 : // Return true if the locations can be moved to one another.
491 : bool IsCompatible(LocationOperand* op);
492 :
493 : static LocationOperand* cast(InstructionOperand* op) {
494 : DCHECK(op->IsAnyLocationOperand());
495 : return static_cast<LocationOperand*>(op);
496 : }
497 :
498 : static const LocationOperand* cast(const InstructionOperand* op) {
499 : DCHECK(op->IsAnyLocationOperand());
500 : return static_cast<const LocationOperand*>(op);
501 : }
502 :
503 : static LocationOperand cast(const InstructionOperand& op) {
504 : DCHECK(op.IsAnyLocationOperand());
505 46824 : return *static_cast<const LocationOperand*>(&op);
506 : }
507 :
508 : STATIC_ASSERT(KindField::kSize == 3);
509 : class LocationKindField : public BitField64<LocationKind, 3, 2> {};
510 : class RepresentationField : public BitField64<MachineRepresentation, 5, 8> {};
511 : class IndexField : public BitField64<int32_t, 35, 29> {};
512 : };
513 :
514 : class V8_EXPORT_PRIVATE ExplicitOperand
515 : : public NON_EXPORTED_BASE(LocationOperand) {
516 : public:
517 : ExplicitOperand(LocationKind kind, MachineRepresentation rep, int index);
518 :
519 : static ExplicitOperand* New(Zone* zone, LocationKind kind,
520 : MachineRepresentation rep, int index) {
521 : return InstructionOperand::New(zone, ExplicitOperand(kind, rep, index));
522 : }
523 :
524 : INSTRUCTION_OPERAND_CASTS(ExplicitOperand, EXPLICIT)
525 : };
526 :
527 : class AllocatedOperand : public LocationOperand {
528 : public:
529 : AllocatedOperand(LocationKind kind, MachineRepresentation rep, int index)
530 : : LocationOperand(ALLOCATED, kind, rep, index) {}
531 :
532 0 : static AllocatedOperand* New(Zone* zone, LocationKind kind,
533 : MachineRepresentation rep, int index) {
534 0 : return InstructionOperand::New(zone, AllocatedOperand(kind, rep, index));
535 : }
536 :
537 24243 : INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED)
538 : };
539 :
540 : #undef INSTRUCTION_OPERAND_CASTS
541 :
542 : bool InstructionOperand::IsAnyLocationOperand() const {
543 1734779187 : return this->kind() >= FIRST_LOCATION_OPERAND_KIND;
544 : }
545 :
546 : bool InstructionOperand::IsLocationOperand() const {
547 : return IsAnyLocationOperand() &&
548 : !IsFloatingPoint(LocationOperand::cast(this)->representation());
549 : }
550 :
551 : bool InstructionOperand::IsFPLocationOperand() const {
552 : return IsAnyLocationOperand() &&
553 : IsFloatingPoint(LocationOperand::cast(this)->representation());
554 : }
555 :
556 : bool InstructionOperand::IsAnyRegister() const {
557 2742097699 : return IsAnyLocationOperand() &&
558 : LocationOperand::cast(this)->location_kind() ==
559 : LocationOperand::REGISTER;
560 : }
561 :
562 : bool InstructionOperand::IsRegister() const {
563 311967152 : return IsAnyRegister() &&
564 : !IsFloatingPoint(LocationOperand::cast(this)->representation());
565 : }
566 :
567 : bool InstructionOperand::IsFPRegister() const {
568 1814121486 : return IsAnyRegister() &&
569 : IsFloatingPoint(LocationOperand::cast(this)->representation());
570 : }
571 :
572 : bool InstructionOperand::IsFloatRegister() const {
573 743781 : return IsAnyRegister() && LocationOperand::cast(this)->representation() ==
574 : MachineRepresentation::kFloat32;
575 : }
576 :
577 : bool InstructionOperand::IsDoubleRegister() const {
578 728099 : return IsAnyRegister() && LocationOperand::cast(this)->representation() ==
579 : MachineRepresentation::kFloat64;
580 : }
581 :
582 : bool InstructionOperand::IsSimd128Register() const {
583 723609 : return IsAnyRegister() && LocationOperand::cast(this)->representation() ==
584 : MachineRepresentation::kSimd128;
585 : }
586 :
587 : bool InstructionOperand::IsAnyStackSlot() const {
588 335244291 : return IsAnyLocationOperand() &&
589 : LocationOperand::cast(this)->location_kind() ==
590 : LocationOperand::STACK_SLOT;
591 : }
592 :
593 : bool InstructionOperand::IsStackSlot() const {
594 252365167 : return IsAnyStackSlot() &&
595 : !IsFloatingPoint(LocationOperand::cast(this)->representation());
596 : }
597 :
598 : bool InstructionOperand::IsFPStackSlot() const {
599 20353103 : return IsAnyStackSlot() &&
600 : IsFloatingPoint(LocationOperand::cast(this)->representation());
601 : }
602 :
603 : bool InstructionOperand::IsFloatStackSlot() const {
604 14673 : return IsAnyLocationOperand() &&
605 : LocationOperand::cast(this)->location_kind() ==
606 29346 : LocationOperand::STACK_SLOT &&
607 : LocationOperand::cast(this)->representation() ==
608 : MachineRepresentation::kFloat32;
609 : }
610 :
611 : bool InstructionOperand::IsDoubleStackSlot() const {
612 10785 : return IsAnyLocationOperand() &&
613 : LocationOperand::cast(this)->location_kind() ==
614 21570 : LocationOperand::STACK_SLOT &&
615 : LocationOperand::cast(this)->representation() ==
616 : MachineRepresentation::kFloat64;
617 : }
618 :
619 : bool InstructionOperand::IsSimd128StackSlot() const {
620 : return IsAnyLocationOperand() &&
621 : LocationOperand::cast(this)->location_kind() ==
622 : LocationOperand::STACK_SLOT &&
623 : LocationOperand::cast(this)->representation() ==
624 : MachineRepresentation::kSimd128;
625 : }
626 :
627 1384570547 : uint64_t InstructionOperand::GetCanonicalizedValue() const {
628 1384570547 : if (IsAnyLocationOperand()) {
629 : MachineRepresentation canonical = MachineRepresentation::kNone;
630 1121208136 : if (IsFPRegister()) {
631 : if (kSimpleFPAliasing) {
632 : // We treat all FP register operands the same for simple aliasing.
633 : canonical = MachineRepresentation::kFloat64;
634 : } else {
635 : // We need to distinguish FP register operands of different reps when
636 : // aliasing is not simple (e.g. ARM).
637 : canonical = LocationOperand::cast(this)->representation();
638 : }
639 : }
640 : return InstructionOperand::KindField::update(
641 : LocationOperand::RepresentationField::update(this->value_, canonical),
642 1121208136 : LocationOperand::EXPLICIT);
643 : }
644 : return this->value_;
645 : }
646 :
647 : // Required for maps that don't care about machine type.
648 : struct CompareOperandModuloType {
649 : bool operator()(const InstructionOperand& a,
650 : const InstructionOperand& b) const {
651 : return a.CompareCanonicalized(b);
652 : }
653 : };
654 :
655 : class V8_EXPORT_PRIVATE MoveOperands final
656 : : public NON_EXPORTED_BASE(ZoneObject) {
657 : public:
658 : MoveOperands(const InstructionOperand& source,
659 : const InstructionOperand& destination)
660 76361282 : : source_(source), destination_(destination) {
661 : DCHECK(!source.IsInvalid() && !destination.IsInvalid());
662 : }
663 :
664 : const InstructionOperand& source() const { return source_; }
665 : InstructionOperand& source() { return source_; }
666 1439779 : void set_source(const InstructionOperand& operand) { source_ = operand; }
667 :
668 : const InstructionOperand& destination() const { return destination_; }
669 : InstructionOperand& destination() { return destination_; }
670 : void set_destination(const InstructionOperand& operand) {
671 12331987 : destination_ = operand;
672 : }
673 :
674 : // The gap resolver marks moves as "in-progress" by clearing the
675 : // destination (but not the source).
676 : bool IsPending() const {
677 34406856 : return destination_.IsInvalid() && !source_.IsInvalid();
678 : }
679 12401643 : void SetPending() { destination_ = InstructionOperand(); }
680 :
681 : // A move is redundant if it's been eliminated or if its source and
682 : // destination are the same.
683 275942743 : bool IsRedundant() const {
684 : DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant());
685 498423905 : return IsEliminated() || source_.EqualsCanonicalized(destination_);
686 : }
687 :
688 : // We clear both operands to indicate move that's been eliminated.
689 43512115 : void Eliminate() { source_ = destination_ = InstructionOperand(); }
690 : bool IsEliminated() const {
691 : DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid());
692 : return source_.IsInvalid();
693 : }
694 :
695 : // APIs to aid debugging. For general-stream APIs, use operator<<.
696 : void Print() const;
697 :
698 : private:
699 : InstructionOperand source_;
700 : InstructionOperand destination_;
701 :
702 : DISALLOW_COPY_AND_ASSIGN(MoveOperands);
703 : };
704 :
705 : std::ostream& operator<<(std::ostream&, const MoveOperands&);
706 :
707 : class V8_EXPORT_PRIVATE ParallelMove final
708 : : public NON_EXPORTED_BASE(ZoneVector<MoveOperands*>),
709 : public NON_EXPORTED_BASE(ZoneObject) {
710 : public:
711 : explicit ParallelMove(Zone* zone) : ZoneVector<MoveOperands*>(zone) {}
712 :
713 : MoveOperands* AddMove(const InstructionOperand& from,
714 : const InstructionOperand& to) {
715 : Zone* zone = get_allocator().zone();
716 63049163 : return AddMove(from, to, zone);
717 : }
718 :
719 75662120 : MoveOperands* AddMove(const InstructionOperand& from,
720 : const InstructionOperand& to,
721 : Zone* operand_allocation_zone) {
722 75662332 : if (from.EqualsCanonicalized(to)) return nullptr;
723 75553185 : MoveOperands* move = new (operand_allocation_zone) MoveOperands(from, to);
724 75553185 : if (empty()) reserve(4);
725 75553043 : push_back(move);
726 75553213 : return move;
727 : }
728 :
729 : bool IsRedundant() const;
730 :
731 : // Prepare this ParallelMove to insert move as if it happened in a subsequent
732 : // ParallelMove. move->source() may be changed. Any MoveOperands added to
733 : // to_eliminate must be Eliminated.
734 : void PrepareInsertAfter(MoveOperands* move,
735 : ZoneVector<MoveOperands*>* to_eliminate) const;
736 :
737 : private:
738 : DISALLOW_COPY_AND_ASSIGN(ParallelMove);
739 : };
740 :
741 : std::ostream& operator<<(std::ostream&, const ParallelMove&);
742 :
743 : class ReferenceMap final : public ZoneObject {
744 : public:
745 : explicit ReferenceMap(Zone* zone)
746 5842500 : : reference_operands_(8, zone), instruction_position_(-1) {}
747 :
748 : const ZoneVector<InstructionOperand>& reference_operands() const {
749 : return reference_operands_;
750 : }
751 : int instruction_position() const { return instruction_position_; }
752 :
753 : void set_instruction_position(int pos) {
754 : DCHECK_EQ(-1, instruction_position_);
755 5723976 : instruction_position_ = pos;
756 : }
757 :
758 : void RecordReference(const AllocatedOperand& op);
759 :
760 : private:
761 : friend std::ostream& operator<<(std::ostream&, const ReferenceMap&);
762 :
763 : ZoneVector<InstructionOperand> reference_operands_;
764 : int instruction_position_;
765 : };
766 :
767 : std::ostream& operator<<(std::ostream&, const ReferenceMap&);
768 :
769 : class InstructionBlock;
770 :
771 : class V8_EXPORT_PRIVATE Instruction final {
772 : public:
773 : size_t OutputCount() const { return OutputCountField::decode(bit_field_); }
774 : const InstructionOperand* OutputAt(size_t i) const {
775 : DCHECK(i < OutputCount());
776 : return &operands_[i];
777 : }
778 : InstructionOperand* OutputAt(size_t i) {
779 : DCHECK(i < OutputCount());
780 : return &operands_[i];
781 : }
782 :
783 10600404 : bool HasOutput() const { return OutputCount() > 0; }
784 : const InstructionOperand* Output() const { return OutputAt(0); }
785 : InstructionOperand* Output() { return OutputAt(0); }
786 :
787 : size_t InputCount() const { return InputCountField::decode(bit_field_); }
788 22796 : const InstructionOperand* InputAt(size_t i) const {
789 : DCHECK(i < InputCount());
790 9209601 : return &operands_[OutputCount() + i];
791 : }
792 120948630 : InstructionOperand* InputAt(size_t i) {
793 : DCHECK(i < InputCount());
794 567055948 : return &operands_[OutputCount() + i];
795 : }
796 :
797 : size_t TempCount() const { return TempCountField::decode(bit_field_); }
798 0 : const InstructionOperand* TempAt(size_t i) const {
799 : DCHECK(i < TempCount());
800 0 : return &operands_[OutputCount() + InputCount() + i];
801 : }
802 50900 : InstructionOperand* TempAt(size_t i) {
803 : DCHECK(i < TempCount());
804 3386581 : return &operands_[OutputCount() + InputCount() + i];
805 : }
806 :
807 : InstructionCode opcode() const { return opcode_; }
808 249476009 : ArchOpcode arch_opcode() const { return ArchOpcodeField::decode(opcode()); }
809 1377949 : AddressingMode addressing_mode() const {
810 1377949 : return AddressingModeField::decode(opcode());
811 : }
812 4 : FlagsMode flags_mode() const { return FlagsModeField::decode(opcode()); }
813 : FlagsCondition flags_condition() const {
814 : return FlagsConditionField::decode(opcode());
815 : }
816 :
817 2142472 : static Instruction* New(Zone* zone, InstructionCode opcode) {
818 2142472 : return New(zone, opcode, 0, nullptr, 0, nullptr, 0, nullptr);
819 : }
820 :
821 63182657 : static Instruction* New(Zone* zone, InstructionCode opcode,
822 : size_t output_count, InstructionOperand* outputs,
823 : size_t input_count, InstructionOperand* inputs,
824 : size_t temp_count, InstructionOperand* temps) {
825 : DCHECK_LE(0, opcode);
826 : DCHECK(output_count == 0 || outputs != nullptr);
827 : DCHECK(input_count == 0 || inputs != nullptr);
828 : DCHECK(temp_count == 0 || temps != nullptr);
829 : // TODO(jarin/mstarzinger): Handle this gracefully. See crbug.com/582702.
830 63182657 : CHECK(InputCountField::is_valid(input_count));
831 :
832 63182657 : size_t total_extra_ops = output_count + input_count + temp_count;
833 63182657 : if (total_extra_ops != 0) total_extra_ops--;
834 : int size = static_cast<int>(
835 : RoundUp(sizeof(Instruction), sizeof(InstructionOperand)) +
836 63182657 : total_extra_ops * sizeof(InstructionOperand));
837 63182657 : return new (zone->New(size)) Instruction(
838 63182657 : opcode, output_count, outputs, input_count, inputs, temp_count, temps);
839 : }
840 :
841 : Instruction* MarkAsCall() {
842 11447940 : bit_field_ = IsCallField::update(bit_field_, true);
843 : return this;
844 : }
845 : bool IsCall() const { return IsCallField::decode(bit_field_); }
846 63182779 : bool NeedsReferenceMap() const { return IsCall(); }
847 : bool HasReferenceMap() const { return reference_map_ != nullptr; }
848 :
849 : bool ClobbersRegisters() const { return IsCall(); }
850 : bool ClobbersTemps() const { return IsCall(); }
851 63172767 : bool ClobbersDoubleRegisters() const { return IsCall(); }
852 : ReferenceMap* reference_map() const { return reference_map_; }
853 :
854 : void set_reference_map(ReferenceMap* map) {
855 : DCHECK(NeedsReferenceMap());
856 : DCHECK(!reference_map_);
857 5723976 : reference_map_ = map;
858 : }
859 :
860 : void OverwriteWithNop() {
861 4151829 : opcode_ = ArchOpcodeField::encode(kArchNop);
862 4151829 : bit_field_ = 0;
863 4151829 : reference_map_ = nullptr;
864 : }
865 :
866 : bool IsNop() const { return arch_opcode() == kArchNop; }
867 :
868 : bool IsDeoptimizeCall() const {
869 32296892 : return arch_opcode() == ArchOpcode::kArchDeoptimize ||
870 64515547 : FlagsModeField::decode(opcode()) == kFlags_deoptimize ||
871 : FlagsModeField::decode(opcode()) == kFlags_deoptimize_and_poison;
872 : }
873 :
874 : bool IsTrap() const {
875 : return FlagsModeField::decode(opcode()) == kFlags_trap;
876 : }
877 :
878 : bool IsJump() const { return arch_opcode() == ArchOpcode::kArchJmp; }
879 : bool IsRet() const { return arch_opcode() == ArchOpcode::kArchRet; }
880 : bool IsTailCall() const {
881 89753789 : return arch_opcode() == ArchOpcode::kArchTailCallCodeObject ||
882 89749649 : arch_opcode() == ArchOpcode::kArchTailCallCodeObjectFromJSFunction ||
883 179385079 : arch_opcode() == ArchOpcode::kArchTailCallAddress ||
884 : arch_opcode() == ArchOpcode::kArchTailCallWasm;
885 : }
886 : bool IsThrow() const {
887 : return arch_opcode() == ArchOpcode::kArchThrowTerminator;
888 : }
889 :
890 : enum GapPosition {
891 : START,
892 : END,
893 : FIRST_GAP_POSITION = START,
894 : LAST_GAP_POSITION = END
895 : };
896 :
897 71614078 : ParallelMove* GetOrCreateParallelMove(GapPosition pos, Zone* zone) {
898 71614078 : if (parallel_moves_[pos] == nullptr) {
899 45158782 : parallel_moves_[pos] = new (zone) ParallelMove(zone);
900 : }
901 71614040 : return parallel_moves_[pos];
902 : }
903 :
904 : ParallelMove* GetParallelMove(GapPosition pos) {
905 252912903 : return parallel_moves_[pos];
906 : }
907 :
908 : const ParallelMove* GetParallelMove(GapPosition pos) const {
909 7647816 : return parallel_moves_[pos];
910 : }
911 :
912 : bool AreMovesRedundant() const;
913 :
914 : ParallelMove* const* parallel_moves() const { return ¶llel_moves_[0]; }
915 : ParallelMove** parallel_moves() { return ¶llel_moves_[0]; }
916 :
917 : // The block_id may be invalidated in JumpThreading. It is only important for
918 : // register allocation, to avoid searching for blocks from instruction
919 : // indexes.
920 : InstructionBlock* block() const { return block_; }
921 : void set_block(InstructionBlock* block) {
922 : DCHECK_NOT_NULL(block);
923 63182769 : block_ = block;
924 : }
925 :
926 : // APIs to aid debugging. For general-stream APIs, use operator<<.
927 : void Print() const;
928 :
929 : typedef BitField<size_t, 0, 8> OutputCountField;
930 : typedef BitField<size_t, 8, 16> InputCountField;
931 : typedef BitField<size_t, 24, 6> TempCountField;
932 :
933 : static const size_t kMaxOutputCount = OutputCountField::kMax;
934 : static const size_t kMaxInputCount = InputCountField::kMax;
935 : static const size_t kMaxTempCount = TempCountField::kMax;
936 :
937 : private:
938 : explicit Instruction(InstructionCode opcode);
939 :
940 : Instruction(InstructionCode opcode, size_t output_count,
941 : InstructionOperand* outputs, size_t input_count,
942 : InstructionOperand* inputs, size_t temp_count,
943 : InstructionOperand* temps);
944 :
945 : typedef BitField<bool, 30, 1> IsCallField;
946 :
947 : InstructionCode opcode_;
948 : uint32_t bit_field_;
949 : ParallelMove* parallel_moves_[2];
950 : ReferenceMap* reference_map_;
951 : InstructionBlock* block_;
952 : InstructionOperand operands_[1];
953 :
954 : DISALLOW_COPY_AND_ASSIGN(Instruction);
955 : };
956 :
957 : std::ostream& operator<<(std::ostream&, const Instruction&);
958 :
959 : class RpoNumber final {
960 : public:
961 : static const int kInvalidRpoNumber = -1;
962 : int ToInt() const {
963 : DCHECK(IsValid());
964 75706300 : return index_;
965 : }
966 : size_t ToSize() const {
967 : DCHECK(IsValid());
968 670731634 : return static_cast<size_t>(index_);
969 : }
970 45541248 : bool IsValid() const { return index_ >= 0; }
971 : static RpoNumber FromInt(int index) { return RpoNumber(index); }
972 : static RpoNumber Invalid() { return RpoNumber(kInvalidRpoNumber); }
973 :
974 : bool IsNext(const RpoNumber other) const {
975 : DCHECK(IsValid());
976 30346382 : return other.index_ == this->index_ + 1;
977 : }
978 :
979 : // Comparison operators.
980 978232591 : bool operator==(RpoNumber other) const { return index_ == other.index_; }
981 : bool operator!=(RpoNumber other) const { return index_ != other.index_; }
982 : bool operator>(RpoNumber other) const { return index_ > other.index_; }
983 2672278 : bool operator<(RpoNumber other) const { return index_ < other.index_; }
984 23279866 : bool operator<=(RpoNumber other) const { return index_ <= other.index_; }
985 2 : bool operator>=(RpoNumber other) const { return index_ >= other.index_; }
986 :
987 : private:
988 : explicit RpoNumber(int32_t index) : index_(index) {}
989 : int32_t index_;
990 : };
991 :
992 : std::ostream& operator<<(std::ostream&, const RpoNumber&);
993 :
994 : class V8_EXPORT_PRIVATE Constant final {
995 : public:
996 : enum Type {
997 : kInt32,
998 : kInt64,
999 : kFloat32,
1000 : kFloat64,
1001 : kExternalReference,
1002 : kHeapObject,
1003 : kRpoNumber,
1004 : kDelayedStringConstant
1005 : };
1006 :
1007 : explicit Constant(int32_t v);
1008 : explicit Constant(int64_t v) : type_(kInt64), value_(v) {}
1009 10408 : explicit Constant(float v) : type_(kFloat32), value_(bit_cast<int32_t>(v)) {}
1010 : explicit Constant(double v) : type_(kFloat64), value_(bit_cast<int64_t>(v)) {}
1011 : explicit Constant(ExternalReference ref)
1012 : : type_(kExternalReference), value_(bit_cast<intptr_t>(ref.address())) {}
1013 : explicit Constant(Handle<HeapObject> obj)
1014 : : type_(kHeapObject), value_(bit_cast<intptr_t>(obj)) {}
1015 25457976 : explicit Constant(RpoNumber rpo) : type_(kRpoNumber), value_(rpo.ToInt()) {}
1016 : explicit Constant(const StringConstantBase* str)
1017 : : type_(kDelayedStringConstant), value_(bit_cast<intptr_t>(str)) {}
1018 : explicit Constant(RelocatablePtrConstantInfo info);
1019 :
1020 : Type type() const { return type_; }
1021 :
1022 : RelocInfo::Mode rmode() const { return rmode_; }
1023 :
1024 : int32_t ToInt32() const {
1025 : DCHECK(type() == kInt32 || type() == kInt64);
1026 51339769 : const int32_t value = static_cast<int32_t>(value_);
1027 : DCHECK_EQ(value_, static_cast<int64_t>(value));
1028 : return value;
1029 : }
1030 :
1031 80812 : int64_t ToInt64() const {
1032 2827098 : if (type() == kInt32) return ToInt32();
1033 : DCHECK_EQ(kInt64, type());
1034 2732976 : return value_;
1035 : }
1036 :
1037 : float ToFloat32() const {
1038 : // TODO(ahaas): We should remove this function. If value_ has the bit
1039 : // representation of a signalling NaN, then returning it as float can cause
1040 : // the signalling bit to flip, and value_ is returned as a quiet NaN.
1041 : DCHECK_EQ(kFloat32, type());
1042 16678 : return bit_cast<float>(static_cast<int32_t>(value_));
1043 : }
1044 :
1045 : uint32_t ToFloat32AsInt() const {
1046 : DCHECK_EQ(kFloat32, type());
1047 : return bit_cast<uint32_t>(static_cast<int32_t>(value_));
1048 : }
1049 :
1050 : Double ToFloat64() const {
1051 : DCHECK_EQ(kFloat64, type());
1052 6 : return Double(bit_cast<uint64_t>(value_));
1053 : }
1054 :
1055 : ExternalReference ToExternalReference() const {
1056 : DCHECK_EQ(kExternalReference, type());
1057 2376715 : return ExternalReference::FromRawAddress(static_cast<Address>(value_));
1058 : }
1059 :
1060 : RpoNumber ToRpoNumber() const {
1061 : DCHECK_EQ(kRpoNumber, type());
1062 43649054 : return RpoNumber::FromInt(static_cast<int>(value_));
1063 : }
1064 :
1065 : Handle<HeapObject> ToHeapObject() const;
1066 : Handle<Code> ToCode() const;
1067 : const StringConstantBase* ToDelayedStringConstant() const;
1068 :
1069 : private:
1070 : Type type_;
1071 : RelocInfo::Mode rmode_ = RelocInfo::NONE;
1072 : int64_t value_;
1073 : };
1074 :
1075 : std::ostream& operator<<(std::ostream&, const Constant&);
1076 :
1077 : // Forward declarations.
1078 : class FrameStateDescriptor;
1079 :
1080 : enum class StateValueKind : uint8_t {
1081 : kArgumentsElements,
1082 : kArgumentsLength,
1083 : kPlain,
1084 : kOptimizedOut,
1085 : kNested,
1086 : kDuplicate
1087 : };
1088 :
1089 : class StateValueDescriptor {
1090 : public:
1091 : StateValueDescriptor()
1092 : : kind_(StateValueKind::kPlain), type_(MachineType::AnyTagged()) {}
1093 :
1094 : static StateValueDescriptor ArgumentsElements(ArgumentsStateType type) {
1095 : StateValueDescriptor descr(StateValueKind::kArgumentsElements,
1096 : MachineType::AnyTagged());
1097 : descr.args_type_ = type;
1098 : return descr;
1099 : }
1100 : static StateValueDescriptor ArgumentsLength(ArgumentsStateType type) {
1101 : StateValueDescriptor descr(StateValueKind::kArgumentsLength,
1102 : MachineType::AnyTagged());
1103 : descr.args_type_ = type;
1104 : return descr;
1105 : }
1106 : static StateValueDescriptor Plain(MachineType type) {
1107 : return StateValueDescriptor(StateValueKind::kPlain, type);
1108 : }
1109 : static StateValueDescriptor OptimizedOut() {
1110 : return StateValueDescriptor(StateValueKind::kOptimizedOut,
1111 : MachineType::AnyTagged());
1112 : }
1113 : static StateValueDescriptor Recursive(size_t id) {
1114 : StateValueDescriptor descr(StateValueKind::kNested,
1115 : MachineType::AnyTagged());
1116 : descr.id_ = id;
1117 : return descr;
1118 : }
1119 : static StateValueDescriptor Duplicate(size_t id) {
1120 : StateValueDescriptor descr(StateValueKind::kDuplicate,
1121 : MachineType::AnyTagged());
1122 : descr.id_ = id;
1123 : return descr;
1124 : }
1125 :
1126 : bool IsArgumentsElements() const {
1127 : return kind_ == StateValueKind::kArgumentsElements;
1128 : }
1129 : bool IsArgumentsLength() const {
1130 : return kind_ == StateValueKind::kArgumentsLength;
1131 : }
1132 : bool IsPlain() const { return kind_ == StateValueKind::kPlain; }
1133 : bool IsOptimizedOut() const { return kind_ == StateValueKind::kOptimizedOut; }
1134 : bool IsNested() const { return kind_ == StateValueKind::kNested; }
1135 : bool IsDuplicate() const { return kind_ == StateValueKind::kDuplicate; }
1136 : MachineType type() const { return type_; }
1137 : size_t id() const {
1138 : DCHECK(kind_ == StateValueKind::kDuplicate ||
1139 : kind_ == StateValueKind::kNested);
1140 : return id_;
1141 : }
1142 : ArgumentsStateType arguments_type() const {
1143 : DCHECK(kind_ == StateValueKind::kArgumentsElements ||
1144 : kind_ == StateValueKind::kArgumentsLength);
1145 : return args_type_;
1146 : }
1147 :
1148 : private:
1149 : StateValueDescriptor(StateValueKind kind, MachineType type)
1150 : : kind_(kind), type_(type) {}
1151 :
1152 : StateValueKind kind_;
1153 : MachineType type_;
1154 : union {
1155 : size_t id_;
1156 : ArgumentsStateType args_type_;
1157 : };
1158 : };
1159 :
1160 : class StateValueList {
1161 : public:
1162 : explicit StateValueList(Zone* zone) : fields_(zone), nested_(zone) {}
1163 :
1164 98457 : size_t size() { return fields_.size(); }
1165 :
1166 : struct Value {
1167 : StateValueDescriptor* desc;
1168 : StateValueList* nested;
1169 :
1170 : Value(StateValueDescriptor* desc, StateValueList* nested)
1171 : : desc(desc), nested(nested) {}
1172 : };
1173 :
1174 : class iterator {
1175 : public:
1176 : // Bare minimum of operators needed for range iteration.
1177 : bool operator!=(const iterator& other) const {
1178 : return field_iterator != other.field_iterator;
1179 : }
1180 : bool operator==(const iterator& other) const {
1181 : return field_iterator == other.field_iterator;
1182 : }
1183 : iterator& operator++() {
1184 51188760 : if (field_iterator->IsNested()) {
1185 : nested_iterator++;
1186 : }
1187 : ++field_iterator;
1188 : return *this;
1189 : }
1190 : Value operator*() {
1191 51188747 : StateValueDescriptor* desc = &(*field_iterator);
1192 51188747 : StateValueList* nested = desc->IsNested() ? *nested_iterator : nullptr;
1193 : return Value(desc, nested);
1194 : }
1195 :
1196 : private:
1197 : friend class StateValueList;
1198 :
1199 : iterator(ZoneVector<StateValueDescriptor>::iterator it,
1200 : ZoneVector<StateValueList*>::iterator nested)
1201 : : field_iterator(it), nested_iterator(nested) {}
1202 :
1203 : ZoneVector<StateValueDescriptor>::iterator field_iterator;
1204 : ZoneVector<StateValueList*>::iterator nested_iterator;
1205 : };
1206 :
1207 3946957 : void ReserveSize(size_t size) { fields_.reserve(size); }
1208 :
1209 98457 : StateValueList* PushRecursiveField(Zone* zone, size_t id) {
1210 196914 : fields_.push_back(StateValueDescriptor::Recursive(id));
1211 : StateValueList* nested =
1212 196914 : new (zone->New(sizeof(StateValueList))) StateValueList(zone);
1213 98457 : nested_.push_back(nested);
1214 98457 : return nested;
1215 : }
1216 6180 : void PushArgumentsElements(ArgumentsStateType type) {
1217 12360 : fields_.push_back(StateValueDescriptor::ArgumentsElements(type));
1218 6180 : }
1219 6500 : void PushArgumentsLength(ArgumentsStateType type) {
1220 13000 : fields_.push_back(StateValueDescriptor::ArgumentsLength(type));
1221 6500 : }
1222 22779 : void PushDuplicate(size_t id) {
1223 45558 : fields_.push_back(StateValueDescriptor::Duplicate(id));
1224 22779 : }
1225 23807388 : void PushPlain(MachineType type) {
1226 47615228 : fields_.push_back(StateValueDescriptor::Plain(type));
1227 23807840 : }
1228 27837124 : void PushOptimizedOut() {
1229 55674414 : fields_.push_back(StateValueDescriptor::OptimizedOut());
1230 27837290 : }
1231 :
1232 : iterator begin() { return iterator(fields_.begin(), nested_.begin()); }
1233 : iterator end() { return iterator(fields_.end(), nested_.end()); }
1234 :
1235 : private:
1236 : ZoneVector<StateValueDescriptor> fields_;
1237 : ZoneVector<StateValueList*> nested_;
1238 : };
1239 :
1240 : class FrameStateDescriptor : public ZoneObject {
1241 : public:
1242 : FrameStateDescriptor(Zone* zone, FrameStateType type, BailoutId bailout_id,
1243 : OutputFrameStateCombine state_combine,
1244 : size_t parameters_count, size_t locals_count,
1245 : size_t stack_count,
1246 : MaybeHandle<SharedFunctionInfo> shared_info,
1247 : FrameStateDescriptor* outer_state = nullptr);
1248 :
1249 : FrameStateType type() const { return type_; }
1250 : BailoutId bailout_id() const { return bailout_id_; }
1251 : OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
1252 : size_t parameters_count() const { return parameters_count_; }
1253 : size_t locals_count() const { return locals_count_; }
1254 : size_t stack_count() const { return stack_count_; }
1255 : MaybeHandle<SharedFunctionInfo> shared_info() const { return shared_info_; }
1256 : FrameStateDescriptor* outer_state() const { return outer_state_; }
1257 : bool HasContext() const {
1258 263298 : return FrameStateFunctionInfo::IsJSFunctionType(type_) ||
1259 11487900 : type_ == FrameStateType::kBuiltinContinuation ||
1260 : type_ == FrameStateType::kConstructStub;
1261 : }
1262 :
1263 : size_t GetSize() const;
1264 : size_t GetTotalSize() const;
1265 : size_t GetFrameCount() const;
1266 : size_t GetJSFrameCount() const;
1267 :
1268 : StateValueList* GetStateValueDescriptors() { return &values_; }
1269 :
1270 : static const int kImpossibleValue = 0xdead;
1271 :
1272 : private:
1273 : FrameStateType type_;
1274 : BailoutId bailout_id_;
1275 : OutputFrameStateCombine frame_state_combine_;
1276 : size_t parameters_count_;
1277 : size_t locals_count_;
1278 : size_t stack_count_;
1279 : StateValueList values_;
1280 : MaybeHandle<SharedFunctionInfo> const shared_info_;
1281 : FrameStateDescriptor* outer_state_;
1282 : };
1283 :
1284 : // A deoptimization entry is a pair of the reason why we deoptimize and the
1285 : // frame state descriptor that we have to go back to.
1286 : class DeoptimizationEntry final {
1287 : public:
1288 : DeoptimizationEntry() = default;
1289 : DeoptimizationEntry(FrameStateDescriptor* descriptor, DeoptimizeKind kind,
1290 : DeoptimizeReason reason, VectorSlotPair const& feedback)
1291 : : descriptor_(descriptor),
1292 : kind_(kind),
1293 : reason_(reason),
1294 3569045 : feedback_(feedback) {}
1295 :
1296 : FrameStateDescriptor* descriptor() const { return descriptor_; }
1297 : DeoptimizeKind kind() const { return kind_; }
1298 : DeoptimizeReason reason() const { return reason_; }
1299 : VectorSlotPair const& feedback() const { return feedback_; }
1300 :
1301 : private:
1302 : FrameStateDescriptor* descriptor_ = nullptr;
1303 : DeoptimizeKind kind_ = DeoptimizeKind::kEager;
1304 : DeoptimizeReason reason_ = DeoptimizeReason::kUnknown;
1305 : VectorSlotPair feedback_ = VectorSlotPair();
1306 : };
1307 :
1308 : typedef ZoneVector<DeoptimizationEntry> DeoptimizationVector;
1309 :
1310 : class V8_EXPORT_PRIVATE PhiInstruction final
1311 : : public NON_EXPORTED_BASE(ZoneObject) {
1312 : public:
1313 : typedef ZoneVector<InstructionOperand> Inputs;
1314 :
1315 : PhiInstruction(Zone* zone, int virtual_register, size_t input_count);
1316 :
1317 : void SetInput(size_t offset, int virtual_register);
1318 : void RenameInput(size_t offset, int virtual_register);
1319 :
1320 : int virtual_register() const { return virtual_register_; }
1321 : const IntVector& operands() const { return operands_; }
1322 :
1323 : // TODO(dcarney): this has no real business being here, since it's internal to
1324 : // the register allocator, but putting it here was convenient.
1325 : const InstructionOperand& output() const { return output_; }
1326 : InstructionOperand& output() { return output_; }
1327 :
1328 : private:
1329 : const int virtual_register_;
1330 : InstructionOperand output_;
1331 : IntVector operands_;
1332 : };
1333 :
1334 : // Analogue of BasicBlock for Instructions instead of Nodes.
1335 : class V8_EXPORT_PRIVATE InstructionBlock final
1336 : : public NON_EXPORTED_BASE(ZoneObject) {
1337 : public:
1338 : InstructionBlock(Zone* zone, RpoNumber rpo_number, RpoNumber loop_header,
1339 : RpoNumber loop_end, bool deferred, bool handler);
1340 :
1341 : // Instruction indexes (used by the register allocator).
1342 : int first_instruction_index() const {
1343 : DCHECK_LE(0, code_start_);
1344 : DCHECK_LT(0, code_end_);
1345 : DCHECK_GE(code_end_, code_start_);
1346 : return code_start_;
1347 : }
1348 : int last_instruction_index() const {
1349 : DCHECK_LE(0, code_start_);
1350 : DCHECK_LT(0, code_end_);
1351 : DCHECK_GE(code_end_, code_start_);
1352 281574563 : return code_end_ - 1;
1353 : }
1354 :
1355 : int32_t code_start() const { return code_start_; }
1356 38891235 : void set_code_start(int32_t start) { code_start_ = start; }
1357 :
1358 : int32_t code_end() const { return code_end_; }
1359 38891382 : void set_code_end(int32_t end) { code_end_ = end; }
1360 :
1361 : bool IsDeferred() const { return deferred_; }
1362 : bool IsHandler() const { return handler_; }
1363 :
1364 : RpoNumber ao_number() const { return ao_number_; }
1365 : RpoNumber rpo_number() const { return rpo_number_; }
1366 : RpoNumber loop_header() const { return loop_header_; }
1367 : RpoNumber loop_end() const {
1368 : DCHECK(IsLoopHeader());
1369 : return loop_end_;
1370 : }
1371 : inline bool IsLoopHeader() const { return loop_end_.IsValid(); }
1372 : inline bool IsSwitchTarget() const { return switch_target_; }
1373 : inline bool ShouldAlign() const { return alignment_; }
1374 :
1375 : typedef ZoneVector<RpoNumber> Predecessors;
1376 : Predecessors& predecessors() { return predecessors_; }
1377 : const Predecessors& predecessors() const { return predecessors_; }
1378 85997096 : size_t PredecessorCount() const { return predecessors_.size(); }
1379 : size_t PredecessorIndexOf(RpoNumber rpo_number) const;
1380 :
1381 : typedef ZoneVector<RpoNumber> Successors;
1382 : Successors& successors() { return successors_; }
1383 : const Successors& successors() const { return successors_; }
1384 11214438 : size_t SuccessorCount() const { return successors_.size(); }
1385 :
1386 : typedef ZoneVector<PhiInstruction*> PhiInstructions;
1387 : const PhiInstructions& phis() const { return phis_; }
1388 2098796 : PhiInstruction* PhiAt(size_t i) const { return phis_[i]; }
1389 2098904 : void AddPhi(PhiInstruction* phi) { phis_.push_back(phi); }
1390 :
1391 35680381 : void set_ao_number(RpoNumber ao_number) { ao_number_ = ao_number; }
1392 :
1393 505470 : void set_alignment(bool val) { alignment_ = val; }
1394 :
1395 438325 : void set_switch_target(bool val) { switch_target_ = val; }
1396 :
1397 : bool needs_frame() const { return needs_frame_; }
1398 20222009 : void mark_needs_frame() { needs_frame_ = true; }
1399 :
1400 : bool must_construct_frame() const { return must_construct_frame_; }
1401 2151238 : void mark_must_construct_frame() { must_construct_frame_ = true; }
1402 :
1403 : bool must_deconstruct_frame() const { return must_deconstruct_frame_; }
1404 2431779 : void mark_must_deconstruct_frame() { must_deconstruct_frame_ = true; }
1405 :
1406 : private:
1407 : Successors successors_;
1408 : Predecessors predecessors_;
1409 : PhiInstructions phis_;
1410 : RpoNumber ao_number_; // Assembly order number.
1411 : const RpoNumber rpo_number_;
1412 : const RpoNumber loop_header_;
1413 : const RpoNumber loop_end_;
1414 : int32_t code_start_; // start index of arch-specific code.
1415 : int32_t code_end_ = -1; // end index of arch-specific code.
1416 : const bool deferred_ = -1; // Block contains deferred code.
1417 : const bool handler_; // Block is a handler entry point.
1418 : bool switch_target_ = false;
1419 : bool alignment_ = false; // insert alignment before this block
1420 : bool needs_frame_ = false;
1421 : bool must_construct_frame_ = false;
1422 : bool must_deconstruct_frame_ = false;
1423 : };
1424 :
1425 : class InstructionSequence;
1426 :
1427 : struct PrintableInstructionBlock {
1428 : const InstructionBlock* block_;
1429 : const InstructionSequence* code_;
1430 : };
1431 :
1432 : std::ostream& operator<<(std::ostream&, const PrintableInstructionBlock&);
1433 :
1434 : typedef ZoneDeque<Constant> ConstantDeque;
1435 : typedef std::map<int, Constant, std::less<int>,
1436 : ZoneAllocator<std::pair<const int, Constant> > >
1437 : ConstantMap;
1438 :
1439 : typedef ZoneDeque<Instruction*> InstructionDeque;
1440 : typedef ZoneDeque<ReferenceMap*> ReferenceMapDeque;
1441 : typedef ZoneVector<InstructionBlock*> InstructionBlocks;
1442 :
1443 : // Represents architecture-specific generated code before, during, and after
1444 : // register allocation.
1445 2912 : class V8_EXPORT_PRIVATE InstructionSequence final
1446 : : public NON_EXPORTED_BASE(ZoneObject) {
1447 : public:
1448 : static InstructionBlocks* InstructionBlocksFor(Zone* zone,
1449 : const Schedule* schedule);
1450 : InstructionSequence(Isolate* isolate, Zone* zone,
1451 : InstructionBlocks* instruction_blocks);
1452 :
1453 : int NextVirtualRegister();
1454 : int VirtualRegisterCount() const { return next_virtual_register_; }
1455 :
1456 : const InstructionBlocks& instruction_blocks() const {
1457 : return *instruction_blocks_;
1458 : }
1459 :
1460 : const InstructionBlocks& ao_blocks() const { return *ao_blocks_; }
1461 :
1462 : int InstructionBlockCount() const {
1463 88379334 : return static_cast<int>(instruction_blocks_->size());
1464 : }
1465 :
1466 402710862 : InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) {
1467 805421724 : return instruction_blocks_->at(rpo_number.ToSize());
1468 : }
1469 :
1470 243537 : int LastLoopInstructionIndex(const InstructionBlock* block) {
1471 243537 : return instruction_blocks_->at(block->loop_end().ToSize() - 1)
1472 487074 : ->last_instruction_index();
1473 : }
1474 :
1475 191308678 : const InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) const {
1476 382617356 : return instruction_blocks_->at(rpo_number.ToSize());
1477 : }
1478 :
1479 : InstructionBlock* GetInstructionBlock(int instruction_index) const;
1480 :
1481 : static MachineRepresentation DefaultRepresentation() {
1482 : return MachineType::PointerRepresentation();
1483 : }
1484 : MachineRepresentation GetRepresentation(int virtual_register) const;
1485 : void MarkAsRepresentation(MachineRepresentation rep, int virtual_register);
1486 :
1487 : bool IsReference(int virtual_register) const {
1488 73338366 : return CanBeTaggedPointer(GetRepresentation(virtual_register));
1489 : }
1490 : bool IsFP(int virtual_register) const {
1491 2931035 : return IsFloatingPoint(GetRepresentation(virtual_register));
1492 : }
1493 : int representation_mask() const { return representation_mask_; }
1494 2141575 : bool HasFPVirtualRegisters() const {
1495 : constexpr int kFPRepMask =
1496 : RepresentationBit(MachineRepresentation::kFloat32) |
1497 : RepresentationBit(MachineRepresentation::kFloat64) |
1498 : RepresentationBit(MachineRepresentation::kSimd128);
1499 2141575 : return (representation_mask() & kFPRepMask) != 0;
1500 : }
1501 :
1502 : Instruction* GetBlockStart(RpoNumber rpo) const;
1503 :
1504 : typedef InstructionDeque::const_iterator const_iterator;
1505 : const_iterator begin() const { return instructions_.begin(); }
1506 : const_iterator end() const { return instructions_.end(); }
1507 : const InstructionDeque& instructions() const { return instructions_; }
1508 : int LastInstructionIndex() const {
1509 2 : return static_cast<int>(instructions().size()) - 1;
1510 : }
1511 :
1512 : Instruction* InstructionAt(int index) const {
1513 : DCHECK_LE(0, index);
1514 : DCHECK_GT(instructions_.size(), index);
1515 483363253 : return instructions_[index];
1516 : }
1517 :
1518 : Isolate* isolate() const { return isolate_; }
1519 : const ReferenceMapDeque* reference_maps() const { return &reference_maps_; }
1520 : Zone* zone() const { return zone_; }
1521 :
1522 : // Used by the instruction selector while adding instructions.
1523 : int AddInstruction(Instruction* instr);
1524 : void StartBlock(RpoNumber rpo);
1525 : void EndBlock(RpoNumber rpo);
1526 :
1527 : int AddConstant(int virtual_register, Constant constant) {
1528 : // TODO(titzer): allow RPO numbers as constants?
1529 : DCHECK_NE(Constant::kRpoNumber, constant.type());
1530 : DCHECK(virtual_register >= 0 && virtual_register < next_virtual_register_);
1531 : DCHECK(constants_.find(virtual_register) == constants_.end());
1532 12528165 : constants_.insert(std::make_pair(virtual_register, constant));
1533 : return virtual_register;
1534 : }
1535 : Constant GetConstant(int virtual_register) const {
1536 : ConstantMap::const_iterator it = constants_.find(virtual_register);
1537 : DCHECK(it != constants_.end());
1538 : DCHECK_EQ(virtual_register, it->first);
1539 18561431 : return it->second;
1540 : }
1541 :
1542 : typedef ZoneVector<Constant> Immediates;
1543 : Immediates& immediates() { return immediates_; }
1544 :
1545 100378744 : ImmediateOperand AddImmediate(const Constant& constant) {
1546 81586679 : if (constant.type() == Constant::kInt32 &&
1547 : RelocInfo::IsNone(constant.rmode())) {
1548 18792065 : return ImmediateOperand(ImmediateOperand::INLINE, constant.ToInt32());
1549 : }
1550 88005124 : int index = static_cast<int>(immediates_.size());
1551 44002562 : immediates_.push_back(constant);
1552 44002840 : return ImmediateOperand(ImmediateOperand::INDEXED, index);
1553 : }
1554 :
1555 63591644 : Constant GetImmediate(const ImmediateOperand* op) const {
1556 63591644 : switch (op->type()) {
1557 : case ImmediateOperand::INLINE:
1558 17199643 : return Constant(op->inline_value());
1559 : case ImmediateOperand::INDEXED: {
1560 : int index = op->indexed_value();
1561 : DCHECK_LE(0, index);
1562 : DCHECK_GT(immediates_.size(), index);
1563 92784002 : return immediates_[index];
1564 : }
1565 : }
1566 0 : UNREACHABLE();
1567 : }
1568 :
1569 : int AddDeoptimizationEntry(FrameStateDescriptor* descriptor,
1570 : DeoptimizeKind kind, DeoptimizeReason reason,
1571 : VectorSlotPair const& feedback);
1572 : DeoptimizationEntry const& GetDeoptimizationEntry(int deoptimization_id);
1573 : int GetDeoptimizationEntryCount() const {
1574 506 : return static_cast<int>(deoptimization_entries_.size());
1575 : }
1576 :
1577 : RpoNumber InputRpo(Instruction* instr, size_t index);
1578 :
1579 : bool GetSourcePosition(const Instruction* instr,
1580 : SourcePosition* result) const;
1581 : void SetSourcePosition(const Instruction* instr, SourcePosition value);
1582 :
1583 : bool ContainsCall() const {
1584 : for (Instruction* instr : instructions_) {
1585 : if (instr->IsCall()) return true;
1586 : }
1587 : return false;
1588 : }
1589 :
1590 : // APIs to aid debugging. For general-stream APIs, use operator<<.
1591 : void Print() const;
1592 :
1593 : void PrintBlock(int block_id) const;
1594 :
1595 : void ValidateEdgeSplitForm() const;
1596 : void ValidateDeferredBlockExitPaths() const;
1597 : void ValidateDeferredBlockEntryPaths() const;
1598 : void ValidateSSA() const;
1599 :
1600 : static void SetRegisterConfigurationForTesting(
1601 : const RegisterConfiguration* regConfig);
1602 : static void ClearRegisterConfigurationForTesting();
1603 :
1604 : void RecomputeAssemblyOrderForTesting();
1605 :
1606 : private:
1607 : friend V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
1608 : const InstructionSequence&);
1609 :
1610 : typedef ZoneMap<const Instruction*, SourcePosition> SourcePositionMap;
1611 :
1612 : static const RegisterConfiguration* RegisterConfigurationForTesting();
1613 : static const RegisterConfiguration* registerConfigurationForTesting_;
1614 :
1615 : // Puts the deferred blocks last and may rotate loops.
1616 : void ComputeAssemblyOrder();
1617 :
1618 : Isolate* isolate_;
1619 : Zone* const zone_;
1620 : InstructionBlocks* const instruction_blocks_;
1621 : InstructionBlocks* ao_blocks_;
1622 : SourcePositionMap source_positions_;
1623 : ConstantMap constants_;
1624 : Immediates immediates_;
1625 : InstructionDeque instructions_;
1626 : int next_virtual_register_;
1627 : ReferenceMapDeque reference_maps_;
1628 : ZoneVector<MachineRepresentation> representations_;
1629 : int representation_mask_;
1630 : DeoptimizationVector deoptimization_entries_;
1631 :
1632 : // Used at construction time
1633 : InstructionBlock* current_block_;
1634 :
1635 : DISALLOW_COPY_AND_ASSIGN(InstructionSequence);
1636 : };
1637 :
1638 : V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&,
1639 : const InstructionSequence&);
1640 :
1641 : } // namespace compiler
1642 : } // namespace internal
1643 : } // namespace v8
1644 :
1645 : #endif // V8_COMPILER_BACKEND_INSTRUCTION_H_
|