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