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