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