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