instruction.h 46.6 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_INSTRUCTION_H_
#define V8_COMPILER_INSTRUCTION_H_

#include <deque>
9
#include <iosfwd>
10 11 12 13 14 15 16
#include <map>
#include <set>

#include "src/compiler/common-operator.h"
#include "src/compiler/frame.h"
#include "src/compiler/instruction-codes.h"
#include "src/compiler/opcodes.h"
17
#include "src/compiler/source-position.h"
18 19
#include "src/macro-assembler.h"
#include "src/register-configuration.h"
20 21 22 23 24 25
#include "src/zone-allocator.h"

namespace v8 {
namespace internal {
namespace compiler {

26
// Forward declarations.
27 28
class Schedule;

29

30
class InstructionOperand {
31
 public:
32 33
  static const int kInvalidVirtualRegister = -1;

34 35
  // TODO(dcarney): recover bit. INVALID can be represented as UNALLOCATED with
  // kInvalidVirtualRegister and some DCHECKS.
36
  enum Kind { INVALID, UNALLOCATED, CONSTANT, IMMEDIATE, EXPLICIT, ALLOCATED };
37

38
  InstructionOperand() : InstructionOperand(INVALID) {}
39

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 46
  // UnallocatedOperands are place-holder operands created before register
  // allocation. They later are assigned registers and become AllocatedOperands.
47
  INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
48 49 50 51
  // Constant operands participate in register allocation. They are allocated to
  // registers but have a special "spilling" behavior. When a ConstantOperand
  // value must be rematerialized, it is loaded from an immediate constant
  // rather from an unspilled slot.
52
  INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT)
53 54 55
  // ImmediateOperands do not participate in register allocation and are only
  // embedded directly in instructions, e.g. small integers and on some
  // platforms Objects.
56
  INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE)
57 58 59 60 61 62 63
  // ExplicitOperands do not participate in register allocation. They are
  // created by the instruction selector for direct access to registers and
  // stack slots, completely bypassing the register allocator. They are never
  // associated with a virtual register
  INSTRUCTION_OPERAND_PREDICATE(Explicit, EXPLICIT)
  // AllocatedOperands are registers or stack slots that are assigned by the
  // 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 69
  inline bool IsRegister() const;
  inline bool IsDoubleRegister() const;
70
  inline bool IsSimd128Register() const;
71 72
  inline bool IsStackSlot() const;
  inline bool IsDoubleStackSlot() const;
73
  inline bool IsSimd128StackSlot() const;
74

75 76 77 78
  template <typename SubKindOperand>
  static SubKindOperand* New(Zone* zone, const SubKindOperand& op) {
    void* buffer = zone->New(sizeof(op));
    return new (buffer) SubKindOperand(op);
79 80
  }

81 82 83
  static void ReplaceWith(InstructionOperand* dest,
                          const InstructionOperand* src) {
    *dest = *src;
84 85
  }

86 87 88 89 90 91 92 93
  bool Equals(const InstructionOperand& that) const {
    return this->value_ == that.value_;
  }

  bool Compare(const InstructionOperand& that) const {
    return this->value_ < that.value_;
  }

94 95
  bool EqualsCanonicalized(const InstructionOperand& that) const {
    return this->GetCanonicalizedValue() == that.GetCanonicalizedValue();
96 97
  }

98 99
  bool CompareCanonicalized(const InstructionOperand& that) const {
    return this->GetCanonicalizedValue() < that.GetCanonicalizedValue();
100 101
  }

102 103 104
  void Print(const RegisterConfiguration* config) const;
  void Print() const;

105
 protected:
106
  explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {}
107

108
  inline uint64_t GetCanonicalizedValue() const;
109

110
  class KindField : public BitField64<Kind, 0, 3> {};
111 112

  uint64_t value_;
113 114
};

115

116 117 118
typedef ZoneVector<InstructionOperand> InstructionOperandVector;


119 120
struct PrintableInstructionOperand {
  const RegisterConfiguration* register_configuration_;
121
  InstructionOperand op_;
122 123
};

124

125 126
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionOperand& op);
127

128

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
#define INSTRUCTION_OPERAND_CASTS(OperandType, OperandKind)      \
                                                                 \
  static OperandType* cast(InstructionOperand* op) {             \
    DCHECK_EQ(OperandKind, op->kind());                          \
    return static_cast<OperandType*>(op);                        \
  }                                                              \
                                                                 \
  static const OperandType* cast(const InstructionOperand* op) { \
    DCHECK_EQ(OperandKind, op->kind());                          \
    return static_cast<const OperandType*>(op);                  \
  }                                                              \
                                                                 \
  static OperandType cast(const InstructionOperand& op) {        \
    DCHECK_EQ(OperandKind, op.kind());                           \
    return *static_cast<const OperandType*>(&op);                \
  }

146 147 148 149 150 151 152 153 154 155
class UnallocatedOperand : public InstructionOperand {
 public:
  enum BasicPolicy { FIXED_SLOT, EXTENDED_POLICY };

  enum ExtendedPolicy {
    NONE,
    ANY,
    FIXED_REGISTER,
    FIXED_DOUBLE_REGISTER,
    MUST_HAVE_REGISTER,
156
    MUST_HAVE_SLOT,
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    SAME_AS_FIRST_INPUT
  };

  // Lifetime of operand inside the instruction.
  enum Lifetime {
    // USED_AT_START operand is guaranteed to be live only at
    // instruction start. Register allocator is free to assign the same register
    // to some other operand used inside instruction (i.e. temporary or
    // output).
    USED_AT_START,

    // USED_AT_END operand is treated as live until the end of
    // instruction. This means that register allocator will not reuse it's
    // register for any other operand inside instruction.
    USED_AT_END
  };

174
  UnallocatedOperand(ExtendedPolicy policy, int virtual_register)
175
      : UnallocatedOperand(virtual_register) {
176 177 178 179 180
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(USED_AT_END);
  }

181
  UnallocatedOperand(BasicPolicy policy, int index, int virtual_register)
182
      : UnallocatedOperand(virtual_register) {
183
    DCHECK(policy == FIXED_SLOT);
184
    value_ |= BasicPolicyField::encode(policy);
185
    value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift;
186
    DCHECK(this->fixed_slot_index() == index);
187 188
  }

189
  UnallocatedOperand(ExtendedPolicy policy, int index, int virtual_register)
190
      : UnallocatedOperand(virtual_register) {
191
    DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
192 193 194 195 196 197
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(USED_AT_END);
    value_ |= FixedRegisterField::encode(index);
  }

198 199
  UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime,
                     int virtual_register)
200
      : UnallocatedOperand(virtual_register) {
201 202 203 204 205
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(lifetime);
  }

206 207 208 209 210 211
  UnallocatedOperand(int reg_id, int slot_id, int virtual_register)
      : UnallocatedOperand(FIXED_REGISTER, reg_id, virtual_register) {
    value_ |= HasSecondaryStorageField::encode(true);
    value_ |= SecondaryStorageField::encode(slot_id);
  }

212 213 214 215 216 217 218 219 220 221 222 223 224
  // Predicates for the operand policy.
  bool HasAnyPolicy() const {
    return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY;
  }
  bool HasFixedPolicy() const {
    return basic_policy() == FIXED_SLOT ||
           extended_policy() == FIXED_REGISTER ||
           extended_policy() == FIXED_DOUBLE_REGISTER;
  }
  bool HasRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == MUST_HAVE_REGISTER;
  }
225 226 227 228
  bool HasSlotPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == MUST_HAVE_SLOT;
  }
229 230 231 232 233 234 235 236 237 238 239 240 241
  bool HasSameAsInputPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == SAME_AS_FIRST_INPUT;
  }
  bool HasFixedSlotPolicy() const { return basic_policy() == FIXED_SLOT; }
  bool HasFixedRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == FIXED_REGISTER;
  }
  bool HasFixedDoubleRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == FIXED_DOUBLE_REGISTER;
  }
242 243 244 245 246 247 248 249 250
  bool HasSecondaryStorage() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == FIXED_REGISTER &&
           HasSecondaryStorageField::decode(value_);
  }
  int GetSecondaryStorage() const {
    DCHECK(HasSecondaryStorage());
    return SecondaryStorageField::decode(value_);
  }
251 252

  // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
253 254 255 256
  BasicPolicy basic_policy() const {
    DCHECK_EQ(UNALLOCATED, kind());
    return BasicPolicyField::decode(value_);
  }
257 258 259

  // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
  ExtendedPolicy extended_policy() const {
260
    DCHECK(basic_policy() == EXTENDED_POLICY);
261 262 263 264 265
    return ExtendedPolicyField::decode(value_);
  }

  // [fixed_slot_index]: Only for FIXED_SLOT.
  int fixed_slot_index() const {
266
    DCHECK(HasFixedSlotPolicy());
267
    return static_cast<int>(static_cast<int64_t>(value_) >>
268
                            FixedSlotIndexField::kShift);
269 270 271 272
  }

  // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
  int fixed_register_index() const {
273
    DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
274 275 276 277
    return FixedRegisterField::decode(value_);
  }

  // [virtual_register]: The virtual register ID for this operand.
278 279
  int32_t virtual_register() const {
    DCHECK_EQ(UNALLOCATED, kind());
280
    return static_cast<int32_t>(VirtualRegisterField::decode(value_));
281 282 283 284 285
  }

  // TODO(dcarney): remove this.
  void set_virtual_register(int32_t id) {
    DCHECK_EQ(UNALLOCATED, kind());
286
    value_ = VirtualRegisterField::update(value_, static_cast<uint32_t>(id));
287
  }
288 289

  // [lifetime]: Only for non-FIXED_SLOT.
290
  bool IsUsedAtStart() const {
291
    DCHECK(basic_policy() == EXTENDED_POLICY);
292 293
    return LifetimeField::decode(value_) == USED_AT_START;
  }
294 295

  INSTRUCTION_OPERAND_CASTS(UnallocatedOperand, UNALLOCATED);
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

  // The encoding used for UnallocatedOperand operands depends on the policy
  // that is
  // stored within the operand. The FIXED_SLOT policy uses a compact encoding
  // because it accommodates a larger pay-load.
  //
  // For FIXED_SLOT policy:
  //     +------------------------------------------------+
  //     |      slot_index   | 0 | virtual_register | 001 |
  //     +------------------------------------------------+
  //
  // For all other (extended) policies:
  //     +-----------------------------------------------------+
  //     |  reg_index  | L | PPP |  1 | virtual_register | 001 |
  //     +-----------------------------------------------------+
  //     L ... Lifetime
  //     P ... Policy
  //
  // The slot index is a signed value which requires us to decode it manually
  // instead of using the BitField utility class.

  STATIC_ASSERT(KindField::kSize == 3);

  class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {};

  // BitFields for all unallocated operands.
  class BasicPolicyField : public BitField64<BasicPolicy, 35, 1> {};

  // BitFields specific to BasicPolicy::FIXED_SLOT.
  class FixedSlotIndexField : public BitField64<int, 36, 28> {};

  // BitFields specific to BasicPolicy::EXTENDED_POLICY.
  class ExtendedPolicyField : public BitField64<ExtendedPolicy, 36, 3> {};
  class LifetimeField : public BitField64<Lifetime, 39, 1> {};
330 331 332
  class HasSecondaryStorageField : public BitField64<bool, 40, 1> {};
  class FixedRegisterField : public BitField64<int, 41, 6> {};
  class SecondaryStorageField : public BitField64<int, 47, 3> {};
333 334 335 336 337 338 339

 private:
  explicit UnallocatedOperand(int virtual_register)
      : InstructionOperand(UNALLOCATED) {
    value_ |=
        VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register));
  }
340 341 342
};


343 344 345
class ConstantOperand : public InstructionOperand {
 public:
  explicit ConstantOperand(int virtual_register)
346 347 348 349
      : InstructionOperand(CONSTANT) {
    value_ |=
        VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register));
  }
350 351 352 353 354 355 356 357 358

  int32_t virtual_register() const {
    return static_cast<int32_t>(VirtualRegisterField::decode(value_));
  }

  static ConstantOperand* New(Zone* zone, int virtual_register) {
    return InstructionOperand::New(zone, ConstantOperand(virtual_register));
  }

359
  INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT);
360 361 362

  STATIC_ASSERT(KindField::kSize == 3);
  class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {};
363 364 365 366 367
};


class ImmediateOperand : public InstructionOperand {
 public:
368 369 370 371 372 373
  enum ImmediateType { INLINE, INDEXED };

  explicit ImmediateOperand(ImmediateType type, int32_t value)
      : InstructionOperand(IMMEDIATE) {
    value_ |= TypeField::encode(type);
    value_ |= static_cast<int64_t>(value) << ValueField::kShift;
374
  }
375

376 377 378 379 380 381 382 383 384 385
  ImmediateType type() const { return TypeField::decode(value_); }

  int32_t inline_value() const {
    DCHECK_EQ(INLINE, type());
    return static_cast<int64_t>(value_) >> ValueField::kShift;
  }

  int32_t indexed_value() const {
    DCHECK_EQ(INDEXED, type());
    return static_cast<int64_t>(value_) >> ValueField::kShift;
386 387
  }

388 389
  static ImmediateOperand* New(Zone* zone, ImmediateType type, int32_t value) {
    return InstructionOperand::New(zone, ImmediateOperand(type, value));
390 391
  }

392
  INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE);
393 394

  STATIC_ASSERT(KindField::kSize == 3);
395 396
  class TypeField : public BitField64<ImmediateType, 3, 1> {};
  class ValueField : public BitField64<int32_t, 32, 32> {};
397 398 399
};


400
class LocationOperand : public InstructionOperand {
401
 public:
402
  enum LocationKind { REGISTER, STACK_SLOT };
403

404 405
  LocationOperand(InstructionOperand::Kind operand_kind,
                  LocationOperand::LocationKind location_kind,
406
                  MachineRepresentation rep, int index)
407 408
      : InstructionOperand(operand_kind) {
    DCHECK_IMPLIES(location_kind == REGISTER, index >= 0);
409
    DCHECK(IsSupportedRepresentation(rep));
410
    value_ |= LocationKindField::encode(location_kind);
411
    value_ |= RepresentationField::encode(rep);
412
    value_ |= static_cast<int64_t>(index) << IndexField::kShift;
413 414
  }

415
  int index() const {
416
    DCHECK(IsStackSlot() || IsDoubleStackSlot() || IsSimd128StackSlot());
417 418 419
    return static_cast<int64_t>(value_) >> IndexField::kShift;
  }

420
  Register GetRegister() const {
421
    DCHECK(IsRegister());
422 423 424 425 426
    return Register::from_code(static_cast<int64_t>(value_) >>
                               IndexField::kShift);
  }

  DoubleRegister GetDoubleRegister() const {
427
    DCHECK(IsDoubleRegister());
428 429 430 431
    return DoubleRegister::from_code(static_cast<int64_t>(value_) >>
                                     IndexField::kShift);
  }

432 433 434 435 436 437
  Simd128Register GetSimd128Register() const {
    DCHECK(IsSimd128Register());
    return Simd128Register::from_code(static_cast<int64_t>(value_) >>
                                      IndexField::kShift);
  }

438 439
  LocationKind location_kind() const {
    return LocationKindField::decode(value_);
440 441
  }

442 443 444
  MachineRepresentation representation() const {
    return RepresentationField::decode(value_);
  }
445

446 447 448 449 450 451
  static bool IsSupportedRepresentation(MachineRepresentation rep) {
    switch (rep) {
      case MachineRepresentation::kWord32:
      case MachineRepresentation::kWord64:
      case MachineRepresentation::kFloat32:
      case MachineRepresentation::kFloat64:
452
      case MachineRepresentation::kSimd128:
453
      case MachineRepresentation::kTagged:
454
        return true;
455 456 457 458
      case MachineRepresentation::kBit:
      case MachineRepresentation::kWord8:
      case MachineRepresentation::kWord16:
      case MachineRepresentation::kNone:
459 460
        return false;
    }
461 462
    UNREACHABLE();
    return false;
463 464
  }

465 466 467 468 469 470 471 472 473 474 475 476 477 478
  static LocationOperand* cast(InstructionOperand* op) {
    DCHECK(ALLOCATED == op->kind() || EXPLICIT == op->kind());
    return static_cast<LocationOperand*>(op);
  }

  static const LocationOperand* cast(const InstructionOperand* op) {
    DCHECK(ALLOCATED == op->kind() || EXPLICIT == op->kind());
    return static_cast<const LocationOperand*>(op);
  }

  static LocationOperand cast(const InstructionOperand& op) {
    DCHECK(ALLOCATED == op.kind() || EXPLICIT == op.kind());
    return *static_cast<const LocationOperand*>(&op);
  }
479

480
  STATIC_ASSERT(KindField::kSize == 3);
481
  class LocationKindField : public BitField64<LocationKind, 3, 2> {};
482
  class RepresentationField : public BitField64<MachineRepresentation, 5, 8> {};
483
  class IndexField : public BitField64<int32_t, 35, 29> {};
484
};
485 486


487 488
class ExplicitOperand : public LocationOperand {
 public:
489
  ExplicitOperand(LocationKind kind, MachineRepresentation rep, int index);
490 491

  static ExplicitOperand* New(Zone* zone, LocationKind kind,
492 493
                              MachineRepresentation rep, int index) {
    return InstructionOperand::New(zone, ExplicitOperand(kind, rep, index));
494 495 496 497 498 499 500 501
  }

  INSTRUCTION_OPERAND_CASTS(ExplicitOperand, EXPLICIT);
};


class AllocatedOperand : public LocationOperand {
 public:
502 503
  AllocatedOperand(LocationKind kind, MachineRepresentation rep, int index)
      : LocationOperand(ALLOCATED, kind, rep, index) {}
504 505

  static AllocatedOperand* New(Zone* zone, LocationKind kind,
506 507
                               MachineRepresentation rep, int index) {
    return InstructionOperand::New(zone, AllocatedOperand(kind, rep, index));
508 509 510 511 512 513
  }

  INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED);
};


514 515 516
#undef INSTRUCTION_OPERAND_CASTS


517
bool InstructionOperand::IsAnyRegister() const {
518 519
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
520 521 522 523 524 525
             LocationOperand::REGISTER;
}


bool InstructionOperand::IsRegister() const {
  return IsAnyRegister() &&
526
         !IsFloatingPoint(LocationOperand::cast(this)->representation());
527
}
528

529
bool InstructionOperand::IsDoubleRegister() const {
530
  return IsAnyRegister() &&
531
         IsFloatingPoint(LocationOperand::cast(this)->representation());
532 533
}

534 535 536 537 538 539
bool InstructionOperand::IsSimd128Register() const {
  return IsAnyRegister() &&
         LocationOperand::cast(this)->representation() ==
             MachineRepresentation::kSimd128;
}

540 541 542 543
bool InstructionOperand::IsStackSlot() const {
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
             LocationOperand::STACK_SLOT &&
544
         !IsFloatingPoint(LocationOperand::cast(this)->representation());
545 546 547 548 549 550
}

bool InstructionOperand::IsDoubleStackSlot() const {
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
             LocationOperand::STACK_SLOT &&
551
         IsFloatingPoint(LocationOperand::cast(this)->representation());
552
}
553

554 555 556 557 558 559 560 561
bool InstructionOperand::IsSimd128StackSlot() const {
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
             LocationOperand::STACK_SLOT &&
         LocationOperand::cast(this)->representation() ==
             MachineRepresentation::kSimd128;
}

562 563
uint64_t InstructionOperand::GetCanonicalizedValue() const {
  if (IsAllocated() || IsExplicit()) {
564
    // TODO(dcarney): put machine type last and mask.
565 566 567 568
    MachineRepresentation canonicalized_representation =
        IsFloatingPoint(LocationOperand::cast(this)->representation())
            ? MachineRepresentation::kFloat64
            : MachineRepresentation::kNone;
569
    return InstructionOperand::KindField::update(
570 571
        LocationOperand::RepresentationField::update(
            this->value_, canonicalized_representation),
572
        LocationOperand::EXPLICIT);
573 574 575 576 577 578 579 580 581
  }
  return this->value_;
}


// Required for maps that don't care about machine type.
struct CompareOperandModuloType {
  bool operator()(const InstructionOperand& a,
                  const InstructionOperand& b) const {
582
    return a.CompareCanonicalized(b);
583 584 585 586
  }
};


587
class MoveOperands final : public ZoneObject {
588
 public:
589 590 591 592 593
  MoveOperands(const InstructionOperand& source,
               const InstructionOperand& destination)
      : source_(source), destination_(destination) {
    DCHECK(!source.IsInvalid() && !destination.IsInvalid());
  }
594

595 596 597
  const InstructionOperand& source() const { return source_; }
  InstructionOperand& source() { return source_; }
  void set_source(const InstructionOperand& operand) { source_ = operand; }
598

599 600 601 602 603
  const InstructionOperand& destination() const { return destination_; }
  InstructionOperand& destination() { return destination_; }
  void set_destination(const InstructionOperand& operand) {
    destination_ = operand;
  }
604 605 606

  // The gap resolver marks moves as "in-progress" by clearing the
  // destination (but not the source).
607 608 609 610
  bool IsPending() const {
    return destination_.IsInvalid() && !source_.IsInvalid();
  }
  void SetPending() { destination_ = InstructionOperand(); }
611 612

  // True if this move a move into the given destination operand.
613
  bool Blocks(const InstructionOperand& operand) const {
614
    return !IsEliminated() && source().EqualsCanonicalized(operand);
615 616
  }

617 618
  // A move is redundant if it's been eliminated or if its source and
  // destination are the same.
619
  bool IsRedundant() const {
620
    DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant());
621
    return IsEliminated() || source_.EqualsCanonicalized(destination_);
622 623 624
  }

  // We clear both operands to indicate move that's been eliminated.
625
  void Eliminate() { source_ = destination_ = InstructionOperand(); }
626
  bool IsEliminated() const {
627 628
    DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid());
    return source_.IsInvalid();
629 630
  }

631 632 633
  void Print(const RegisterConfiguration* config) const;
  void Print() const;

634
 private:
635 636 637 638
  InstructionOperand source_;
  InstructionOperand destination_;

  DISALLOW_COPY_AND_ASSIGN(MoveOperands);
639 640
};

641 642 643 644 645 646 647 648 649

struct PrintableMoveOperands {
  const RegisterConfiguration* register_configuration_;
  const MoveOperands* move_operands_;
};


std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo);

650

651
class ParallelMove final : public ZoneVector<MoveOperands*>, public ZoneObject {
652
 public:
653 654 655
  explicit ParallelMove(Zone* zone) : ZoneVector<MoveOperands*>(zone) {
    reserve(4);
  }
656

657 658
  MoveOperands* AddMove(const InstructionOperand& from,
                        const InstructionOperand& to) {
659 660 661 662 663 664 665 666
    Zone* zone = get_allocator().zone();
    return AddMove(from, to, zone);
  }

  MoveOperands* AddMove(const InstructionOperand& from,
                        const InstructionOperand& to,
                        Zone* operand_allocation_zone) {
    MoveOperands* move = new (operand_allocation_zone) MoveOperands(from, to);
667 668
    push_back(move);
    return move;
669 670 671 672
  }

  bool IsRedundant() const;

dcarney's avatar
dcarney committed
673 674
  // Prepare this ParallelMove to insert move as if it happened in a subsequent
  // ParallelMove.  move->source() may be changed.  The MoveOperand returned
675
  // must be Eliminated.
dcarney's avatar
dcarney committed
676 677
  MoveOperands* PrepareInsertAfter(MoveOperands* move) const;

678
 private:
679
  DISALLOW_COPY_AND_ASSIGN(ParallelMove);
680 681
};

682 683 684 685 686 687 688 689 690

struct PrintableParallelMove {
  const RegisterConfiguration* register_configuration_;
  const ParallelMove* parallel_move_;
};


std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm);

691

692
class ReferenceMap final : public ZoneObject {
693
 public:
694 695 696 697 698
  explicit ReferenceMap(Zone* zone)
      : reference_operands_(8, zone), instruction_position_(-1) {}

  const ZoneVector<InstructionOperand>& reference_operands() const {
    return reference_operands_;
699 700 701 702
  }
  int instruction_position() const { return instruction_position_; }

  void set_instruction_position(int pos) {
703
    DCHECK(instruction_position_ == -1);
704 705 706
    instruction_position_ = pos;
  }

707
  void RecordReference(const AllocatedOperand& op);
708 709

 private:
710
  friend std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm);
711

712
  ZoneVector<InstructionOperand> reference_operands_;
713 714 715
  int instruction_position_;
};

716
std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm);
717

718
class Instruction final {
719 720
 public:
  size_t OutputCount() const { return OutputCountField::decode(bit_field_); }
721 722 723 724 725
  const InstructionOperand* OutputAt(size_t i) const {
    DCHECK(i < OutputCount());
    return &operands_[i];
  }
  InstructionOperand* OutputAt(size_t i) {
726
    DCHECK(i < OutputCount());
727
    return &operands_[i];
728 729
  }

730
  bool HasOutput() const { return OutputCount() == 1; }
731 732
  const InstructionOperand* Output() const { return OutputAt(0); }
  InstructionOperand* Output() { return OutputAt(0); }
733

734
  size_t InputCount() const { return InputCountField::decode(bit_field_); }
735
  const InstructionOperand* InputAt(size_t i) const {
736
    DCHECK(i < InputCount());
737
    return &operands_[OutputCount() + i];
738
  }
739
  InstructionOperand* InputAt(size_t i) {
740
    DCHECK(i < InputCount());
741
    return &operands_[OutputCount() + i];
742
  }
743 744

  size_t TempCount() const { return TempCountField::decode(bit_field_); }
745 746 747 748 749
  const InstructionOperand* TempAt(size_t i) const {
    DCHECK(i < TempCount());
    return &operands_[OutputCount() + InputCount() + i];
  }
  InstructionOperand* TempAt(size_t i) {
750
    DCHECK(i < TempCount());
751
    return &operands_[OutputCount() + InputCount() + i];
752 753 754 755 756 757 758 759 760 761 762 763 764
  }

  InstructionCode opcode() const { return opcode_; }
  ArchOpcode arch_opcode() const { return ArchOpcodeField::decode(opcode()); }
  AddressingMode addressing_mode() const {
    return AddressingModeField::decode(opcode());
  }
  FlagsMode flags_mode() const { return FlagsModeField::decode(opcode()); }
  FlagsCondition flags_condition() const {
    return FlagsConditionField::decode(opcode());
  }

  static Instruction* New(Zone* zone, InstructionCode opcode) {
765
    return New(zone, opcode, 0, nullptr, 0, nullptr, 0, nullptr);
766 767 768
  }

  static Instruction* New(Zone* zone, InstructionCode opcode,
769 770 771
                          size_t output_count, InstructionOperand* outputs,
                          size_t input_count, InstructionOperand* inputs,
                          size_t temp_count, InstructionOperand* temps) {
772
    DCHECK(opcode >= 0);
773 774 775
    DCHECK(output_count == 0 || outputs != nullptr);
    DCHECK(input_count == 0 || inputs != nullptr);
    DCHECK(temp_count == 0 || temps != nullptr);
776 777 778
    size_t total_extra_ops = output_count + input_count + temp_count;
    if (total_extra_ops != 0) total_extra_ops--;
    int size = static_cast<int>(
779 780
        RoundUp(sizeof(Instruction), sizeof(InstructionOperand)) +
        total_extra_ops * sizeof(InstructionOperand));
781 782 783 784 785 786 787 788 789
    return new (zone->New(size)) Instruction(
        opcode, output_count, outputs, input_count, inputs, temp_count, temps);
  }

  Instruction* MarkAsCall() {
    bit_field_ = IsCallField::update(bit_field_, true);
    return this;
  }
  bool IsCall() const { return IsCallField::decode(bit_field_); }
790
  bool NeedsReferenceMap() const { return IsCall(); }
791
  bool HasReferenceMap() const { return reference_map_ != nullptr; }
792 793 794 795

  bool ClobbersRegisters() const { return IsCall(); }
  bool ClobbersTemps() const { return IsCall(); }
  bool ClobbersDoubleRegisters() const { return IsCall(); }
796
  ReferenceMap* reference_map() const { return reference_map_; }
797

798 799 800 801
  void set_reference_map(ReferenceMap* map) {
    DCHECK(NeedsReferenceMap());
    DCHECK(!reference_map_);
    reference_map_ = map;
802 803
  }

804 805 806
  void OverwriteWithNop() {
    opcode_ = ArchOpcodeField::encode(kArchNop);
    bit_field_ = 0;
807
    reference_map_ = nullptr;
808 809 810 811 812 813 814
  }

  bool IsNop() const {
    return arch_opcode() == kArchNop && InputCount() == 0 &&
           OutputCount() == 0 && TempCount() == 0;
  }

815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
  bool IsDeoptimizeCall() const {
    return arch_opcode() == ArchOpcode::kArchDeoptimize ||
           FlagsModeField::decode(opcode()) == kFlags_deoptimize;
  }

  bool IsJump() const { return arch_opcode() == ArchOpcode::kArchJmp; }
  bool IsRet() const { return arch_opcode() == ArchOpcode::kArchRet; }
  bool IsTailCall() const {
    return arch_opcode() == ArchOpcode::kArchTailCallCodeObject ||
           arch_opcode() == ArchOpcode::kArchTailCallCodeObjectFromJSFunction ||
           arch_opcode() == ArchOpcode::kArchTailCallJSFunction ||
           arch_opcode() == ArchOpcode::kArchTailCallJSFunctionFromJSFunction;
  }
  bool IsThrow() const {
    return arch_opcode() == ArchOpcode::kArchThrowTerminator;
  }

832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
  enum GapPosition {
    START,
    END,
    FIRST_GAP_POSITION = START,
    LAST_GAP_POSITION = END
  };

  ParallelMove* GetOrCreateParallelMove(GapPosition pos, Zone* zone) {
    if (parallel_moves_[pos] == nullptr) {
      parallel_moves_[pos] = new (zone) ParallelMove(zone);
    }
    return parallel_moves_[pos];
  }

  ParallelMove* GetParallelMove(GapPosition pos) {
    return parallel_moves_[pos];
  }

  const ParallelMove* GetParallelMove(GapPosition pos) const {
    return parallel_moves_[pos];
  }

  bool AreMovesRedundant() const;

  ParallelMove* const* parallel_moves() const { return &parallel_moves_[0]; }
  ParallelMove** parallel_moves() { return &parallel_moves_[0]; }

859 860 861
  void Print(const RegisterConfiguration* config) const;
  void Print() const;

862
 private:
863
  explicit Instruction(InstructionCode opcode);
864

865
  Instruction(InstructionCode opcode, size_t output_count,
866 867 868
              InstructionOperand* outputs, size_t input_count,
              InstructionOperand* inputs, size_t temp_count,
              InstructionOperand* temps);
869 870 871 872 873 874 875 876

  typedef BitField<size_t, 0, 8> OutputCountField;
  typedef BitField<size_t, 8, 16> InputCountField;
  typedef BitField<size_t, 24, 6> TempCountField;
  typedef BitField<bool, 30, 1> IsCallField;

  InstructionCode opcode_;
  uint32_t bit_field_;
877
  ParallelMove* parallel_moves_[2];
878
  ReferenceMap* reference_map_;
879
  InstructionOperand operands_[1];
880 881

  DISALLOW_COPY_AND_ASSIGN(Instruction);
882 883
};

884 885 886 887 888 889 890

struct PrintableInstruction {
  const RegisterConfiguration* register_configuration_;
  const Instruction* instr_;
};
std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);

891

892
class RpoNumber final {
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
 public:
  static const int kInvalidRpoNumber = -1;
  int ToInt() const {
    DCHECK(IsValid());
    return index_;
  }
  size_t ToSize() const {
    DCHECK(IsValid());
    return static_cast<size_t>(index_);
  }
  bool IsValid() const { return index_ >= 0; }
  static RpoNumber FromInt(int index) { return RpoNumber(index); }
  static RpoNumber Invalid() { return RpoNumber(kInvalidRpoNumber); }

  bool IsNext(const RpoNumber other) const {
    DCHECK(IsValid());
    return other.index_ == this->index_ + 1;
  }

912 913 914 915 916 917 918
  // Comparison operators.
  bool operator==(RpoNumber other) const { return index_ == other.index_; }
  bool operator!=(RpoNumber other) const { return index_ != other.index_; }
  bool operator>(RpoNumber other) const { return index_ > other.index_; }
  bool operator<(RpoNumber other) const { return index_ < other.index_; }
  bool operator<=(RpoNumber other) const { return index_ <= other.index_; }
  bool operator>=(RpoNumber other) const { return index_ >= other.index_; }
919 920 921 922 923 924 925 926 927 928

 private:
  explicit RpoNumber(int32_t index) : index_(index) {}
  int32_t index_;
};


std::ostream& operator<<(std::ostream&, const RpoNumber&);


929
class Constant final {
930
 public:
931 932 933 934 935 936
  enum Type {
    kInt32,
    kInt64,
    kFloat32,
    kFloat64,
    kExternalReference,
937 938
    kHeapObject,
    kRpoNumber
939
  };
940

941
  explicit Constant(int32_t v);
942
  explicit Constant(int64_t v) : type_(kInt64), value_(v) {}
943
  explicit Constant(float v) : type_(kFloat32), value_(bit_cast<int32_t>(v)) {}
944
  explicit Constant(double v) : type_(kFloat64), value_(bit_cast<int64_t>(v)) {}
945
  explicit Constant(ExternalReference ref)
946
      : type_(kExternalReference), value_(bit_cast<intptr_t>(ref)) {}
947
  explicit Constant(Handle<HeapObject> obj)
948
      : type_(kHeapObject), value_(bit_cast<intptr_t>(obj)) {}
949
  explicit Constant(RpoNumber rpo) : type_(kRpoNumber), value_(rpo.ToInt()) {}
950 951 952 953

  Type type() const { return type_; }

  int32_t ToInt32() const {
954 955 956 957
    DCHECK(type() == kInt32 || type() == kInt64);
    const int32_t value = static_cast<int32_t>(value_);
    DCHECK_EQ(value_, static_cast<int64_t>(value));
    return value;
958 959 960 961
  }

  int64_t ToInt64() const {
    if (type() == kInt32) return ToInt32();
962
    DCHECK_EQ(kInt64, type());
963 964 965
    return value_;
  }

966 967 968 969 970
  float ToFloat32() const {
    DCHECK_EQ(kFloat32, type());
    return bit_cast<float>(static_cast<int32_t>(value_));
  }

971 972
  double ToFloat64() const {
    if (type() == kInt32) return ToInt32();
973
    DCHECK_EQ(kFloat64, type());
974
    return bit_cast<double>(value_);
975 976 977
  }

  ExternalReference ToExternalReference() const {
978
    DCHECK_EQ(kExternalReference, type());
979
    return bit_cast<ExternalReference>(static_cast<intptr_t>(value_));
980 981
  }

982
  RpoNumber ToRpoNumber() const {
983
    DCHECK_EQ(kRpoNumber, type());
984
    return RpoNumber::FromInt(static_cast<int>(value_));
985 986
  }

987
  Handle<HeapObject> ToHeapObject() const {
988
    DCHECK_EQ(kHeapObject, type());
989
    return bit_cast<Handle<HeapObject> >(static_cast<intptr_t>(value_));
990 991 992 993 994 995 996
  }

 private:
  Type type_;
  int64_t value_;
};

997

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
std::ostream& operator<<(std::ostream& os, const Constant& constant);


// Forward declarations.
class FrameStateDescriptor;


enum class StateValueKind { kPlain, kNested, kDuplicate };


class StateValueDescriptor {
 public:
  explicit StateValueDescriptor(Zone* zone)
      : kind_(StateValueKind::kPlain),
        type_(MachineType::AnyTagged()),
        id_(0),
        fields_(zone) {}

  static StateValueDescriptor Plain(Zone* zone, MachineType type) {
    return StateValueDescriptor(StateValueKind::kPlain, zone, type, 0);
  }
  static StateValueDescriptor Recursive(Zone* zone, size_t id) {
    return StateValueDescriptor(StateValueKind::kNested, zone,
                                MachineType::AnyTagged(), id);
  }
  static StateValueDescriptor Duplicate(Zone* zone, size_t id) {
    return StateValueDescriptor(StateValueKind::kDuplicate, zone,
                                MachineType::AnyTagged(), id);
  }

  size_t size() { return fields_.size(); }
  ZoneVector<StateValueDescriptor>& fields() { return fields_; }
  int IsPlain() { return kind_ == StateValueKind::kPlain; }
  int IsNested() { return kind_ == StateValueKind::kNested; }
  int IsDuplicate() { return kind_ == StateValueKind::kDuplicate; }
  MachineType type() const { return type_; }
  MachineType GetOperandType(size_t index) const {
    return fields_[index].type_;
  }
  size_t id() const { return id_; }

 private:
  StateValueDescriptor(StateValueKind kind, Zone* zone, MachineType type,
                       size_t id)
      : kind_(kind), type_(type), id_(id), fields_(zone) {}

  StateValueKind kind_;
  MachineType type_;
  size_t id_;
  ZoneVector<StateValueDescriptor> fields_;
};


1051 1052
class FrameStateDescriptor : public ZoneObject {
 public:
1053 1054
  FrameStateDescriptor(Zone* zone, FrameStateType type, BailoutId bailout_id,
                       OutputFrameStateCombine state_combine,
1055 1056
                       size_t parameters_count, size_t locals_count,
                       size_t stack_count,
1057
                       MaybeHandle<SharedFunctionInfo> shared_info,
1058
                       FrameStateDescriptor* outer_state = nullptr);
1059

1060
  FrameStateType type() const { return type_; }
1061
  BailoutId bailout_id() const { return bailout_id_; }
1062
  OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
1063 1064 1065
  size_t parameters_count() const { return parameters_count_; }
  size_t locals_count() const { return locals_count_; }
  size_t stack_count() const { return stack_count_; }
1066
  MaybeHandle<SharedFunctionInfo> shared_info() const { return shared_info_; }
1067
  FrameStateDescriptor* outer_state() const { return outer_state_; }
1068
  bool HasContext() const {
1069
    return FrameStateFunctionInfo::IsJSFunctionType(type_);
1070
  }
1071

1072
  size_t GetSize(OutputFrameStateCombine combine =
1073 1074 1075 1076
                     OutputFrameStateCombine::Ignore()) const;
  size_t GetTotalSize() const;
  size_t GetFrameCount() const;
  size_t GetJSFrameCount() const;
1077

1078 1079 1080 1081
  MachineType GetType(size_t index) const {
    return values_.GetOperandType(index);
  }
  StateValueDescriptor* GetStateValueDescriptor() { return &values_; }
1082

1083
 private:
1084
  FrameStateType type_;
1085
  BailoutId bailout_id_;
1086
  OutputFrameStateCombine frame_state_combine_;
1087 1088 1089
  size_t parameters_count_;
  size_t locals_count_;
  size_t stack_count_;
1090
  StateValueDescriptor values_;
1091
  MaybeHandle<SharedFunctionInfo> const shared_info_;
1092
  FrameStateDescriptor* outer_state_;
1093 1094
};

1095 1096

typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
1097

1098

1099
class PhiInstruction final : public ZoneObject {
1100
 public:
1101
  typedef ZoneVector<InstructionOperand> Inputs;
1102

1103 1104 1105
  PhiInstruction(Zone* zone, int virtual_register, size_t input_count);

  void SetInput(size_t offset, int virtual_register);
1106 1107 1108

  int virtual_register() const { return virtual_register_; }
  const IntVector& operands() const { return operands_; }
1109

1110 1111
  // TODO(dcarney): this has no real business being here, since it's internal to
  // the register allocator, but putting it here was convenient.
1112 1113
  const InstructionOperand& output() const { return output_; }
  InstructionOperand& output() { return output_; }
1114 1115 1116

 private:
  const int virtual_register_;
1117
  InstructionOperand output_;
1118 1119 1120 1121 1122
  IntVector operands_;
};


// Analogue of BasicBlock for Instructions instead of Nodes.
1123
class InstructionBlock final : public ZoneObject {
1124
 public:
1125
  InstructionBlock(Zone* zone, RpoNumber rpo_number, RpoNumber loop_header,
1126
                   RpoNumber loop_end, bool deferred, bool handler);
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147

  // Instruction indexes (used by the register allocator).
  int first_instruction_index() const {
    DCHECK(code_start_ >= 0);
    DCHECK(code_end_ > 0);
    DCHECK(code_end_ >= code_start_);
    return code_start_;
  }
  int last_instruction_index() const {
    DCHECK(code_start_ >= 0);
    DCHECK(code_end_ > 0);
    DCHECK(code_end_ >= code_start_);
    return code_end_ - 1;
  }

  int32_t code_start() const { return code_start_; }
  void set_code_start(int32_t start) { code_start_ = start; }

  int32_t code_end() const { return code_end_; }
  void set_code_end(int32_t end) { code_end_ = end; }

1148
  bool IsDeferred() const { return deferred_; }
1149
  bool IsHandler() const { return handler_; }
1150

1151 1152 1153 1154
  RpoNumber ao_number() const { return ao_number_; }
  RpoNumber rpo_number() const { return rpo_number_; }
  RpoNumber loop_header() const { return loop_header_; }
  RpoNumber loop_end() const {
1155 1156 1157 1158 1159
    DCHECK(IsLoopHeader());
    return loop_end_;
  }
  inline bool IsLoopHeader() const { return loop_end_.IsValid(); }

1160
  typedef ZoneVector<RpoNumber> Predecessors;
1161
  Predecessors& predecessors() { return predecessors_; }
1162 1163
  const Predecessors& predecessors() const { return predecessors_; }
  size_t PredecessorCount() const { return predecessors_.size(); }
1164
  size_t PredecessorIndexOf(RpoNumber rpo_number) const;
1165

1166
  typedef ZoneVector<RpoNumber> Successors;
1167
  Successors& successors() { return successors_; }
1168 1169 1170 1171 1172 1173 1174
  const Successors& successors() const { return successors_; }
  size_t SuccessorCount() const { return successors_.size(); }

  typedef ZoneVector<PhiInstruction*> PhiInstructions;
  const PhiInstructions& phis() const { return phis_; }
  void AddPhi(PhiInstruction* phi) { phis_.push_back(phi); }

1175
  void set_ao_number(RpoNumber ao_number) { ao_number_ = ao_number; }
1176

1177 1178 1179 1180 1181 1182 1183 1184 1185
  bool needs_frame() const { return needs_frame_; }
  void mark_needs_frame() { needs_frame_ = true; }

  bool must_construct_frame() const { return must_construct_frame_; }
  void mark_must_construct_frame() { must_construct_frame_ = true; }

  bool must_deconstruct_frame() const { return must_deconstruct_frame_; }
  void mark_must_deconstruct_frame() { must_deconstruct_frame_ = true; }

1186 1187 1188
  void set_last_deferred(RpoNumber last) { last_deferred_ = last; }
  RpoNumber last_deferred() const { return last_deferred_; }

1189 1190 1191 1192
 private:
  Successors successors_;
  Predecessors predecessors_;
  PhiInstructions phis_;
1193 1194 1195 1196
  RpoNumber ao_number_;  // Assembly order number.
  const RpoNumber rpo_number_;
  const RpoNumber loop_header_;
  const RpoNumber loop_end_;
1197 1198 1199
  int32_t code_start_;   // start index of arch-specific code.
  int32_t code_end_;     // end index of arch-specific code.
  const bool deferred_;  // Block contains deferred code.
1200
  const bool handler_;   // Block is a handler entry point.
1201 1202 1203
  bool needs_frame_;
  bool must_construct_frame_;
  bool must_deconstruct_frame_;
1204
  RpoNumber last_deferred_;
1205 1206
};

1207
typedef ZoneDeque<Constant> ConstantDeque;
1208
typedef std::map<int, Constant, std::less<int>,
1209
                 zone_allocator<std::pair<const int, Constant> > > ConstantMap;
1210

1211
typedef ZoneDeque<Instruction*> InstructionDeque;
1212
typedef ZoneDeque<ReferenceMap*> ReferenceMapDeque;
1213
typedef ZoneVector<InstructionBlock*> InstructionBlocks;
1214

1215 1216

// Forward declarations.
1217 1218 1219
struct PrintableInstructionSequence;


1220 1221
// Represents architecture-specific generated code before, during, and after
// register allocation.
1222
class InstructionSequence final : public ZoneObject {
1223
 public:
1224 1225
  static InstructionBlocks* InstructionBlocksFor(Zone* zone,
                                                 const Schedule* schedule);
1226 1227
  // Puts the deferred blocks last.
  static void ComputeAssemblyOrder(InstructionBlocks* blocks);
1228

1229 1230
  InstructionSequence(Isolate* isolate, Zone* zone,
                      InstructionBlocks* instruction_blocks);
1231

1232
  int NextVirtualRegister();
1233 1234
  int VirtualRegisterCount() const { return next_virtual_register_; }

1235
  const InstructionBlocks& instruction_blocks() const {
1236
    return *instruction_blocks_;
1237 1238
  }

1239
  int InstructionBlockCount() const {
1240
    return static_cast<int>(instruction_blocks_->size());
1241 1242
  }

1243
  InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) {
1244
    return instruction_blocks_->at(rpo_number.ToSize());
1245 1246
  }

1247
  int LastLoopInstructionIndex(const InstructionBlock* block) {
1248
    return instruction_blocks_->at(block->loop_end().ToSize() - 1)
1249 1250 1251
        ->last_instruction_index();
  }

1252
  const InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) const {
1253
    return instruction_blocks_->at(rpo_number.ToSize());
1254 1255
  }

1256
  InstructionBlock* GetInstructionBlock(int instruction_index) const;
1257

1258 1259
  static MachineRepresentation DefaultRepresentation() {
    return MachineType::PointerRepresentation();
1260
  }
1261 1262
  MachineRepresentation GetRepresentation(int virtual_register) const;
  void MarkAsRepresentation(MachineRepresentation rep, int virtual_register);
1263

1264
  bool IsReference(int virtual_register) const {
1265 1266
    return GetRepresentation(virtual_register) ==
           MachineRepresentation::kTagged;
1267 1268
  }
  bool IsFloat(int virtual_register) const {
1269
    return IsFloatingPoint(GetRepresentation(virtual_register));
1270
  }
1271

1272
  Instruction* GetBlockStart(RpoNumber rpo) const;
1273 1274 1275 1276

  typedef InstructionDeque::const_iterator const_iterator;
  const_iterator begin() const { return instructions_.begin(); }
  const_iterator end() const { return instructions_.end(); }
1277
  const InstructionDeque& instructions() const { return instructions_; }
1278 1279 1280
  int LastInstructionIndex() const {
    return static_cast<int>(instructions().size()) - 1;
  }
1281 1282

  Instruction* InstructionAt(int index) const {
1283 1284
    DCHECK(index >= 0);
    DCHECK(index < static_cast<int>(instructions_.size()));
1285 1286 1287
    return instructions_[index];
  }

1288
  Isolate* isolate() const { return isolate_; }
1289
  const ReferenceMapDeque* reference_maps() const { return &reference_maps_; }
1290
  Zone* zone() const { return zone_; }
1291

1292 1293
  // Used by the instruction selector while adding instructions.
  int AddInstruction(Instruction* instr);
1294 1295
  void StartBlock(RpoNumber rpo);
  void EndBlock(RpoNumber rpo);
1296

1297
  int AddConstant(int virtual_register, Constant constant) {
1298 1299
    // TODO(titzer): allow RPO numbers as constants?
    DCHECK(constant.type() != Constant::kRpoNumber);
1300
    DCHECK(virtual_register >= 0 && virtual_register < next_virtual_register_);
1301
    DCHECK(constants_.find(virtual_register) == constants_.end());
1302
    constants_.insert(std::make_pair(virtual_register, constant));
1303
    return virtual_register;
1304 1305 1306
  }
  Constant GetConstant(int virtual_register) const {
    ConstantMap::const_iterator it = constants_.find(virtual_register);
1307 1308
    DCHECK(it != constants_.end());
    DCHECK_EQ(virtual_register, it->first);
1309 1310 1311
    return it->second;
  }

1312 1313
  typedef ZoneVector<Constant> Immediates;
  Immediates& immediates() { return immediates_; }
1314

1315 1316 1317 1318
  ImmediateOperand AddImmediate(const Constant& constant) {
    if (constant.type() == Constant::kInt32) {
      return ImmediateOperand(ImmediateOperand::INLINE, constant.ToInt32());
    }
1319
    int index = static_cast<int>(immediates_.size());
1320
    immediates_.push_back(constant);
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
    return ImmediateOperand(ImmediateOperand::INDEXED, index);
  }

  Constant GetImmediate(const ImmediateOperand* op) const {
    switch (op->type()) {
      case ImmediateOperand::INLINE:
        return Constant(op->inline_value());
      case ImmediateOperand::INDEXED: {
        int index = op->indexed_value();
        DCHECK(index >= 0);
        DCHECK(index < static_cast<int>(immediates_.size()));
        return immediates_[index];
      }
    }
    UNREACHABLE();
    return Constant(static_cast<int32_t>(0));
1337 1338
  }

1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
  class StateId {
   public:
    static StateId FromInt(int id) { return StateId(id); }
    int ToInt() const { return id_; }

   private:
    explicit StateId(int id) : id_(id) {}
    int id_;
  };

  StateId AddFrameStateDescriptor(FrameStateDescriptor* descriptor);
  FrameStateDescriptor* GetFrameStateDescriptor(StateId deoptimization_id);
  int GetFrameStateDescriptorCount();
1352 1353 1354
  DeoptimizationVector const& frame_state_descriptors() const {
    return deoptimization_entries_;
  }
1355

1356
  RpoNumber InputRpo(Instruction* instr, size_t index);
1357

1358 1359 1360 1361
  bool GetSourcePosition(const Instruction* instr,
                         SourcePosition* result) const;
  void SetSourcePosition(const Instruction* instr, SourcePosition value);

1362 1363 1364 1365 1366 1367
  bool ContainsCall() const {
    for (Instruction* instr : instructions_) {
      if (instr->IsCall()) return true;
    }
    return false;
  }
1368 1369
  void Print(const RegisterConfiguration* config) const;
  void Print() const;
1370

1371 1372 1373
  void PrintBlock(const RegisterConfiguration* config, int block_id) const;
  void PrintBlock(int block_id) const;

1374
  void ValidateEdgeSplitForm();
1375
  void ValidateDeferredBlockExitPaths();
1376
  void ValidateSSA();
1377

1378
 private:
1379
  friend std::ostream& operator<<(std::ostream& os,
1380
                                  const PrintableInstructionSequence& code);
1381

1382
  typedef ZoneMap<const Instruction*, SourcePosition> SourcePositionMap;
1383

1384
  Isolate* isolate_;
1385
  Zone* const zone_;
1386
  InstructionBlocks* const instruction_blocks_;
1387
  SourcePositionMap source_positions_;
1388
  IntVector block_starts_;
1389
  ConstantMap constants_;
1390
  Immediates immediates_;
1391 1392
  InstructionDeque instructions_;
  int next_virtual_register_;
1393
  ReferenceMapDeque reference_maps_;
1394
  ZoneVector<MachineRepresentation> representations_;
1395
  DeoptimizationVector deoptimization_entries_;
1396 1397

  DISALLOW_COPY_AND_ASSIGN(InstructionSequence);
1398 1399
};

1400 1401 1402 1403 1404 1405 1406 1407 1408

struct PrintableInstructionSequence {
  const RegisterConfiguration* register_configuration_;
  const InstructionSequence* sequence_;
};


std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionSequence& code);
1409 1410 1411 1412 1413 1414

}  // namespace compiler
}  // namespace internal
}  // namespace v8

#endif  // V8_COMPILER_INSTRUCTION_H_