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