instruction.h 49.4 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
  inline bool IsRegister() const;
69 70
  inline bool IsFPRegister() const;
  inline bool IsFloatRegister() const;
71
  inline bool IsDoubleRegister() const;
72
  inline bool IsSimd128Register() const;
73
  inline bool IsStackSlot() const;
74 75
  inline bool IsFPStackSlot() const;
  inline bool IsFloatStackSlot() const;
76
  inline bool IsDoubleStackSlot() const;
77
  inline bool IsSimd128StackSlot() const;
78

79 80 81 82
  template <typename SubKindOperand>
  static SubKindOperand* New(Zone* zone, const SubKindOperand& op) {
    void* buffer = zone->New(sizeof(op));
    return new (buffer) SubKindOperand(op);
83 84
  }

85 86 87
  static void ReplaceWith(InstructionOperand* dest,
                          const InstructionOperand* src) {
    *dest = *src;
88 89
  }

90 91 92 93 94 95 96 97
  bool Equals(const InstructionOperand& that) const {
    return this->value_ == that.value_;
  }

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

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

102 103
  bool CompareCanonicalized(const InstructionOperand& that) const {
    return this->GetCanonicalizedValue() < that.GetCanonicalizedValue();
104 105
  }

106 107
  bool InterferesWith(const InstructionOperand& that) const;

108 109 110
  void Print(const RegisterConfiguration* config) const;
  void Print() const;

111
 protected:
112
  explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {}
113

114
  inline uint64_t GetCanonicalizedValue() const;
115

116
  class KindField : public BitField64<Kind, 0, 3> {};
117 118

  uint64_t value_;
119 120
};

121

122 123 124
typedef ZoneVector<InstructionOperand> InstructionOperandVector;


125 126
struct PrintableInstructionOperand {
  const RegisterConfiguration* register_configuration_;
127
  InstructionOperand op_;
128 129
};

130

131 132
std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionOperand& op);
133

134

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
#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);                \
  }

152 153 154 155 156 157 158 159
class UnallocatedOperand : public InstructionOperand {
 public:
  enum BasicPolicy { FIXED_SLOT, EXTENDED_POLICY };

  enum ExtendedPolicy {
    NONE,
    ANY,
    FIXED_REGISTER,
160
    FIXED_FP_REGISTER,
161
    MUST_HAVE_REGISTER,
162
    MUST_HAVE_SLOT,
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    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
  };

180
  UnallocatedOperand(ExtendedPolicy policy, int virtual_register)
181
      : UnallocatedOperand(virtual_register) {
182 183 184 185 186
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(USED_AT_END);
  }

187
  UnallocatedOperand(BasicPolicy policy, int index, int virtual_register)
188
      : UnallocatedOperand(virtual_register) {
189
    DCHECK(policy == FIXED_SLOT);
190
    value_ |= BasicPolicyField::encode(policy);
191
    value_ |= static_cast<int64_t>(index) << FixedSlotIndexField::kShift;
192
    DCHECK(this->fixed_slot_index() == index);
193 194
  }

195
  UnallocatedOperand(ExtendedPolicy policy, int index, int virtual_register)
196
      : UnallocatedOperand(virtual_register) {
197
    DCHECK(policy == FIXED_REGISTER || policy == FIXED_FP_REGISTER);
198 199 200 201 202 203
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(USED_AT_END);
    value_ |= FixedRegisterField::encode(index);
  }

204 205
  UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime,
                     int virtual_register)
206
      : UnallocatedOperand(virtual_register) {
207 208 209 210 211
    value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
    value_ |= ExtendedPolicyField::encode(policy);
    value_ |= LifetimeField::encode(lifetime);
  }

212 213 214 215 216 217
  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);
  }

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 ||
225
           extended_policy() == FIXED_FP_REGISTER;
226 227 228 229 230
  }
  bool HasRegisterPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == MUST_HAVE_REGISTER;
  }
231 232 233 234
  bool HasSlotPolicy() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == MUST_HAVE_SLOT;
  }
235 236 237 238 239 240 241 242 243
  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;
  }
244
  bool HasFixedFPRegisterPolicy() const {
245
    return basic_policy() == EXTENDED_POLICY &&
246
           extended_policy() == FIXED_FP_REGISTER;
247
  }
248 249 250 251 252 253 254 255 256
  bool HasSecondaryStorage() const {
    return basic_policy() == EXTENDED_POLICY &&
           extended_policy() == FIXED_REGISTER &&
           HasSecondaryStorageField::decode(value_);
  }
  int GetSecondaryStorage() const {
    DCHECK(HasSecondaryStorage());
    return SecondaryStorageField::decode(value_);
  }
257 258

  // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
259 260 261 262
  BasicPolicy basic_policy() const {
    DCHECK_EQ(UNALLOCATED, kind());
    return BasicPolicyField::decode(value_);
  }
263 264 265

  // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
  ExtendedPolicy extended_policy() const {
266
    DCHECK(basic_policy() == EXTENDED_POLICY);
267 268 269 270 271
    return ExtendedPolicyField::decode(value_);
  }

  // [fixed_slot_index]: Only for FIXED_SLOT.
  int fixed_slot_index() const {
272
    DCHECK(HasFixedSlotPolicy());
273
    return static_cast<int>(static_cast<int64_t>(value_) >>
274
                            FixedSlotIndexField::kShift);
275 276
  }

277
  // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_FP_REGISTER.
278
  int fixed_register_index() const {
279
    DCHECK(HasFixedRegisterPolicy() || HasFixedFPRegisterPolicy());
280 281 282 283
    return FixedRegisterField::decode(value_);
  }

  // [virtual_register]: The virtual register ID for this operand.
284 285
  int32_t virtual_register() const {
    DCHECK_EQ(UNALLOCATED, kind());
286
    return static_cast<int32_t>(VirtualRegisterField::decode(value_));
287 288 289 290 291
  }

  // TODO(dcarney): remove this.
  void set_virtual_register(int32_t id) {
    DCHECK_EQ(UNALLOCATED, kind());
292
    value_ = VirtualRegisterField::update(value_, static_cast<uint32_t>(id));
293
  }
294 295

  // [lifetime]: Only for non-FIXED_SLOT.
296
  bool IsUsedAtStart() const {
297
    DCHECK(basic_policy() == EXTENDED_POLICY);
298 299
    return LifetimeField::decode(value_) == USED_AT_START;
  }
300 301

  INSTRUCTION_OPERAND_CASTS(UnallocatedOperand, UNALLOCATED);
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 330 331 332 333 334 335

  // 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> {};
336 337 338
  class HasSecondaryStorageField : public BitField64<bool, 40, 1> {};
  class FixedRegisterField : public BitField64<int, 41, 6> {};
  class SecondaryStorageField : public BitField64<int, 47, 3> {};
339 340 341 342 343 344 345

 private:
  explicit UnallocatedOperand(int virtual_register)
      : InstructionOperand(UNALLOCATED) {
    value_ |=
        VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register));
  }
346 347 348
};


349 350 351
class ConstantOperand : public InstructionOperand {
 public:
  explicit ConstantOperand(int virtual_register)
352 353 354 355
      : InstructionOperand(CONSTANT) {
    value_ |=
        VirtualRegisterField::encode(static_cast<uint32_t>(virtual_register));
  }
356 357 358 359 360 361 362 363 364

  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));
  }

365
  INSTRUCTION_OPERAND_CASTS(ConstantOperand, CONSTANT);
366 367 368

  STATIC_ASSERT(KindField::kSize == 3);
  class VirtualRegisterField : public BitField64<uint32_t, 3, 32> {};
369 370 371 372 373
};


class ImmediateOperand : public InstructionOperand {
 public:
374 375 376 377 378 379
  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;
380
  }
381

382 383 384 385 386 387 388 389 390 391
  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;
392 393
  }

394 395
  static ImmediateOperand* New(Zone* zone, ImmediateType type, int32_t value) {
    return InstructionOperand::New(zone, ImmediateOperand(type, value));
396 397
  }

398
  INSTRUCTION_OPERAND_CASTS(ImmediateOperand, IMMEDIATE);
399 400

  STATIC_ASSERT(KindField::kSize == 3);
401 402
  class TypeField : public BitField64<ImmediateType, 3, 1> {};
  class ValueField : public BitField64<int32_t, 32, 32> {};
403 404 405
};


406
class LocationOperand : public InstructionOperand {
407
 public:
408
  enum LocationKind { REGISTER, STACK_SLOT };
409

410 411
  LocationOperand(InstructionOperand::Kind operand_kind,
                  LocationOperand::LocationKind location_kind,
412
                  MachineRepresentation rep, int index)
413 414
      : InstructionOperand(operand_kind) {
    DCHECK_IMPLIES(location_kind == REGISTER, index >= 0);
415
    DCHECK(IsSupportedRepresentation(rep));
416
    value_ |= LocationKindField::encode(location_kind);
417
    value_ |= RepresentationField::encode(rep);
418
    value_ |= static_cast<int64_t>(index) << IndexField::kShift;
419 420
  }

421
  int index() const {
422
    DCHECK(IsStackSlot() || IsFPStackSlot());
423 424 425
    return static_cast<int64_t>(value_) >> IndexField::kShift;
  }

426 427 428 429 430
  int register_code() const {
    DCHECK(IsRegister() || IsFPRegister());
    return static_cast<int64_t>(value_) >> IndexField::kShift;
  }

431
  Register GetRegister() const {
432
    DCHECK(IsRegister());
433
    return Register::from_code(register_code());
434 435
  }

436 437
  FloatRegister GetFloatRegister() const {
    DCHECK(IsFloatRegister());
438
    return FloatRegister::from_code(register_code());
439 440
  }

441
  DoubleRegister GetDoubleRegister() const {
442 443 444
    // On platforms where FloatRegister, DoubleRegister, and Simd128Register
    // are all the same type, it's convenient to treat everything as a
    // DoubleRegister, so be lax about type checking here.
445
    DCHECK(IsFPRegister());
446
    return DoubleRegister::from_code(register_code());
447 448
  }

449 450
  Simd128Register GetSimd128Register() const {
    DCHECK(IsSimd128Register());
451
    return Simd128Register::from_code(register_code());
452 453
  }

454 455
  LocationKind location_kind() const {
    return LocationKindField::decode(value_);
456 457
  }

458 459 460
  MachineRepresentation representation() const {
    return RepresentationField::decode(value_);
  }
461

462 463 464 465 466 467
  static bool IsSupportedRepresentation(MachineRepresentation rep) {
    switch (rep) {
      case MachineRepresentation::kWord32:
      case MachineRepresentation::kWord64:
      case MachineRepresentation::kFloat32:
      case MachineRepresentation::kFloat64:
468
      case MachineRepresentation::kSimd128:
469 470
      case MachineRepresentation::kTaggedSigned:
      case MachineRepresentation::kTaggedPointer:
471
      case MachineRepresentation::kTagged:
472
        return true;
473 474 475 476
      case MachineRepresentation::kBit:
      case MachineRepresentation::kWord8:
      case MachineRepresentation::kWord16:
      case MachineRepresentation::kNone:
477 478
        return false;
    }
479 480
    UNREACHABLE();
    return false;
481 482
  }

483 484 485 486 487 488 489 490 491 492 493 494 495 496
  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);
  }
497

498
  STATIC_ASSERT(KindField::kSize == 3);
499
  class LocationKindField : public BitField64<LocationKind, 3, 2> {};
500
  class RepresentationField : public BitField64<MachineRepresentation, 5, 8> {};
501
  class IndexField : public BitField64<int32_t, 35, 29> {};
502
};
503 504


505 506
class ExplicitOperand : public LocationOperand {
 public:
507
  ExplicitOperand(LocationKind kind, MachineRepresentation rep, int index);
508 509

  static ExplicitOperand* New(Zone* zone, LocationKind kind,
510 511
                              MachineRepresentation rep, int index) {
    return InstructionOperand::New(zone, ExplicitOperand(kind, rep, index));
512 513 514 515 516 517 518 519
  }

  INSTRUCTION_OPERAND_CASTS(ExplicitOperand, EXPLICIT);
};


class AllocatedOperand : public LocationOperand {
 public:
520 521
  AllocatedOperand(LocationKind kind, MachineRepresentation rep, int index)
      : LocationOperand(ALLOCATED, kind, rep, index) {}
522 523

  static AllocatedOperand* New(Zone* zone, LocationKind kind,
524 525
                               MachineRepresentation rep, int index) {
    return InstructionOperand::New(zone, AllocatedOperand(kind, rep, index));
526 527 528 529 530 531
  }

  INSTRUCTION_OPERAND_CASTS(AllocatedOperand, ALLOCATED);
};


532 533 534
#undef INSTRUCTION_OPERAND_CASTS


535
bool InstructionOperand::IsAnyRegister() const {
536 537
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
538 539 540 541 542 543
             LocationOperand::REGISTER;
}


bool InstructionOperand::IsRegister() const {
  return IsAnyRegister() &&
544
         !IsFloatingPoint(LocationOperand::cast(this)->representation());
545
}
546

547
bool InstructionOperand::IsFPRegister() const {
548
  return IsAnyRegister() &&
549
         IsFloatingPoint(LocationOperand::cast(this)->representation());
550 551
}

552 553 554 555 556 557 558 559 560 561 562 563
bool InstructionOperand::IsFloatRegister() const {
  return IsAnyRegister() &&
         LocationOperand::cast(this)->representation() ==
             MachineRepresentation::kFloat32;
}

bool InstructionOperand::IsDoubleRegister() const {
  return IsAnyRegister() &&
         LocationOperand::cast(this)->representation() ==
             MachineRepresentation::kFloat64;
}

564 565 566 567 568 569
bool InstructionOperand::IsSimd128Register() const {
  return IsAnyRegister() &&
         LocationOperand::cast(this)->representation() ==
             MachineRepresentation::kSimd128;
}

570 571 572 573
bool InstructionOperand::IsStackSlot() const {
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
             LocationOperand::STACK_SLOT &&
574
         !IsFloatingPoint(LocationOperand::cast(this)->representation());
575 576
}

577
bool InstructionOperand::IsFPStackSlot() const {
578 579 580
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
             LocationOperand::STACK_SLOT &&
581
         IsFloatingPoint(LocationOperand::cast(this)->representation());
582
}
583

584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
bool InstructionOperand::IsFloatStackSlot() const {
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
             LocationOperand::STACK_SLOT &&
         LocationOperand::cast(this)->representation() ==
             MachineRepresentation::kFloat32;
}

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

600 601 602 603 604 605 606 607
bool InstructionOperand::IsSimd128StackSlot() const {
  return (IsAllocated() || IsExplicit()) &&
         LocationOperand::cast(this)->location_kind() ==
             LocationOperand::STACK_SLOT &&
         LocationOperand::cast(this)->representation() ==
             MachineRepresentation::kSimd128;
}

608 609
uint64_t InstructionOperand::GetCanonicalizedValue() const {
  if (IsAllocated() || IsExplicit()) {
610
    MachineRepresentation canonical = MachineRepresentation::kNone;
611
    if (IsFPRegister()) {
612 613
      // We treat all FP register operands the same for simple aliasing.
      canonical = MachineRepresentation::kFloat64;
614
    }
615
    return InstructionOperand::KindField::update(
616
        LocationOperand::RepresentationField::update(this->value_, canonical),
617
        LocationOperand::EXPLICIT);
618 619 620 621 622 623 624 625
  }
  return this->value_;
}

// Required for maps that don't care about machine type.
struct CompareOperandModuloType {
  bool operator()(const InstructionOperand& a,
                  const InstructionOperand& b) const {
626
    return a.CompareCanonicalized(b);
627 628 629 630
  }
};


631
class MoveOperands final : public ZoneObject {
632
 public:
633 634 635 636 637
  MoveOperands(const InstructionOperand& source,
               const InstructionOperand& destination)
      : source_(source), destination_(destination) {
    DCHECK(!source.IsInvalid() && !destination.IsInvalid());
  }
638

639 640 641
  const InstructionOperand& source() const { return source_; }
  InstructionOperand& source() { return source_; }
  void set_source(const InstructionOperand& operand) { source_ = operand; }
642

643 644 645 646 647
  const InstructionOperand& destination() const { return destination_; }
  InstructionOperand& destination() { return destination_; }
  void set_destination(const InstructionOperand& operand) {
    destination_ = operand;
  }
648 649 650

  // The gap resolver marks moves as "in-progress" by clearing the
  // destination (but not the source).
651 652 653 654
  bool IsPending() const {
    return destination_.IsInvalid() && !source_.IsInvalid();
  }
  void SetPending() { destination_ = InstructionOperand(); }
655

656 657 658
  // True if this move is a move into the given destination operand.
  bool Blocks(const InstructionOperand& destination) const {
    return !IsEliminated() && source().InterferesWith(destination);
659 660
  }

661 662
  // A move is redundant if it's been eliminated or if its source and
  // destination are the same.
663
  bool IsRedundant() const {
664
    DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant());
665
    return IsEliminated() || source_.EqualsCanonicalized(destination_);
666 667 668
  }

  // We clear both operands to indicate move that's been eliminated.
669
  void Eliminate() { source_ = destination_ = InstructionOperand(); }
670
  bool IsEliminated() const {
671 672
    DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid());
    return source_.IsInvalid();
673 674
  }

675 676 677
  void Print(const RegisterConfiguration* config) const;
  void Print() const;

678
 private:
679 680 681 682
  InstructionOperand source_;
  InstructionOperand destination_;

  DISALLOW_COPY_AND_ASSIGN(MoveOperands);
683 684
};

685 686 687 688 689 690 691 692 693

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


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

694

695
class ParallelMove final : public ZoneVector<MoveOperands*>, public ZoneObject {
696
 public:
697 698 699
  explicit ParallelMove(Zone* zone) : ZoneVector<MoveOperands*>(zone) {
    reserve(4);
  }
700

701 702
  MoveOperands* AddMove(const InstructionOperand& from,
                        const InstructionOperand& to) {
703 704 705 706 707 708 709 710
    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);
711 712
    push_back(move);
    return move;
713 714 715 716
  }

  bool IsRedundant() const;

dcarney's avatar
dcarney committed
717 718
  // Prepare this ParallelMove to insert move as if it happened in a subsequent
  // ParallelMove.  move->source() may be changed.  The MoveOperand returned
719
  // must be Eliminated.
dcarney's avatar
dcarney committed
720 721
  MoveOperands* PrepareInsertAfter(MoveOperands* move) const;

722
 private:
723
  DISALLOW_COPY_AND_ASSIGN(ParallelMove);
724 725
};

726 727 728 729 730 731 732 733 734

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


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

735

736
class ReferenceMap final : public ZoneObject {
737
 public:
738 739 740 741 742
  explicit ReferenceMap(Zone* zone)
      : reference_operands_(8, zone), instruction_position_(-1) {}

  const ZoneVector<InstructionOperand>& reference_operands() const {
    return reference_operands_;
743 744 745 746
  }
  int instruction_position() const { return instruction_position_; }

  void set_instruction_position(int pos) {
747
    DCHECK(instruction_position_ == -1);
748 749 750
    instruction_position_ = pos;
  }

751
  void RecordReference(const AllocatedOperand& op);
752 753

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

756
  ZoneVector<InstructionOperand> reference_operands_;
757 758 759
  int instruction_position_;
};

760
std::ostream& operator<<(std::ostream& os, const ReferenceMap& pm);
761

762 763
class InstructionBlock;

764
class Instruction final {
765 766
 public:
  size_t OutputCount() const { return OutputCountField::decode(bit_field_); }
767 768 769 770 771
  const InstructionOperand* OutputAt(size_t i) const {
    DCHECK(i < OutputCount());
    return &operands_[i];
  }
  InstructionOperand* OutputAt(size_t i) {
772
    DCHECK(i < OutputCount());
773
    return &operands_[i];
774 775
  }

776
  bool HasOutput() const { return OutputCount() == 1; }
777 778
  const InstructionOperand* Output() const { return OutputAt(0); }
  InstructionOperand* Output() { return OutputAt(0); }
779

780
  size_t InputCount() const { return InputCountField::decode(bit_field_); }
781
  const InstructionOperand* InputAt(size_t i) const {
782
    DCHECK(i < InputCount());
783
    return &operands_[OutputCount() + i];
784
  }
785
  InstructionOperand* InputAt(size_t i) {
786
    DCHECK(i < InputCount());
787
    return &operands_[OutputCount() + i];
788
  }
789 790

  size_t TempCount() const { return TempCountField::decode(bit_field_); }
791 792 793 794 795
  const InstructionOperand* TempAt(size_t i) const {
    DCHECK(i < TempCount());
    return &operands_[OutputCount() + InputCount() + i];
  }
  InstructionOperand* TempAt(size_t i) {
796
    DCHECK(i < TempCount());
797
    return &operands_[OutputCount() + InputCount() + i];
798 799 800 801 802 803 804 805 806 807 808 809 810
  }

  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) {
811
    return New(zone, opcode, 0, nullptr, 0, nullptr, 0, nullptr);
812 813 814
  }

  static Instruction* New(Zone* zone, InstructionCode opcode,
815 816 817
                          size_t output_count, InstructionOperand* outputs,
                          size_t input_count, InstructionOperand* inputs,
                          size_t temp_count, InstructionOperand* temps) {
818
    DCHECK(opcode >= 0);
819 820 821
    DCHECK(output_count == 0 || outputs != nullptr);
    DCHECK(input_count == 0 || inputs != nullptr);
    DCHECK(temp_count == 0 || temps != nullptr);
822 823 824
    // TODO(jarin/mstarzinger): Handle this gracefully. See crbug.com/582702.
    CHECK(InputCountField::is_valid(input_count));

825 826 827
    size_t total_extra_ops = output_count + input_count + temp_count;
    if (total_extra_ops != 0) total_extra_ops--;
    int size = static_cast<int>(
828 829
        RoundUp(sizeof(Instruction), sizeof(InstructionOperand)) +
        total_extra_ops * sizeof(InstructionOperand));
830 831 832 833 834 835 836 837 838
    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_); }
839
  bool NeedsReferenceMap() const { return IsCall(); }
840
  bool HasReferenceMap() const { return reference_map_ != nullptr; }
841 842 843 844

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

847 848 849 850
  void set_reference_map(ReferenceMap* map) {
    DCHECK(NeedsReferenceMap());
    DCHECK(!reference_map_);
    reference_map_ = map;
851 852
  }

853 854 855
  void OverwriteWithNop() {
    opcode_ = ArchOpcodeField::encode(kArchNop);
    bit_field_ = 0;
856
    reference_map_ = nullptr;
857 858
  }

859
  bool IsNop() const { return arch_opcode() == kArchNop; }
860

861 862 863 864 865 866 867 868 869 870 871
  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 ||
872 873
           arch_opcode() == ArchOpcode::kArchTailCallJSFunctionFromJSFunction ||
           arch_opcode() == ArchOpcode::kArchTailCallAddress;
874 875 876 877 878
  }
  bool IsThrow() const {
    return arch_opcode() == ArchOpcode::kArchThrowTerminator;
  }

879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
  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]; }

906 907 908 909 910 911 912 913 914
  // The block_id may be invalidated in JumpThreading. It is only important for
  // register allocation, to avoid searching for blocks from instruction
  // indexes.
  InstructionBlock* block() const { return block_; }
  void set_block(InstructionBlock* block) {
    DCHECK_NOT_NULL(block);
    block_ = block;
  }

915 916 917
  void Print(const RegisterConfiguration* config) const;
  void Print() const;

918
 private:
919
  explicit Instruction(InstructionCode opcode);
920

921
  Instruction(InstructionCode opcode, size_t output_count,
922 923 924
              InstructionOperand* outputs, size_t input_count,
              InstructionOperand* inputs, size_t temp_count,
              InstructionOperand* temps);
925 926 927 928 929 930 931 932

  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_;
933
  ParallelMove* parallel_moves_[2];
934
  ReferenceMap* reference_map_;
935
  InstructionBlock* block_;
936
  InstructionOperand operands_[1];
937 938

  DISALLOW_COPY_AND_ASSIGN(Instruction);
939 940
};

941 942 943 944 945 946 947

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

948

949
class RpoNumber final {
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
 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;
  }

969 970 971 972 973 974 975
  // 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_; }
976 977 978 979 980 981 982 983 984 985

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


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


986
class Constant final {
987
 public:
988 989 990 991 992 993
  enum Type {
    kInt32,
    kInt64,
    kFloat32,
    kFloat64,
    kExternalReference,
994 995
    kHeapObject,
    kRpoNumber
996
  };
997

998
  explicit Constant(int32_t v);
999
  explicit Constant(int64_t v) : type_(kInt64), value_(v) {}
1000
  explicit Constant(float v) : type_(kFloat32), value_(bit_cast<int32_t>(v)) {}
1001
  explicit Constant(double v) : type_(kFloat64), value_(bit_cast<int64_t>(v)) {}
1002
  explicit Constant(ExternalReference ref)
1003
      : type_(kExternalReference), value_(bit_cast<intptr_t>(ref)) {}
1004
  explicit Constant(Handle<HeapObject> obj)
1005
      : type_(kHeapObject), value_(bit_cast<intptr_t>(obj)) {}
1006
  explicit Constant(RpoNumber rpo) : type_(kRpoNumber), value_(rpo.ToInt()) {}
1007
  explicit Constant(RelocatablePtrConstantInfo info);
1008 1009 1010

  Type type() const { return type_; }

1011 1012
  RelocInfo::Mode rmode() const { return rmode_; }

1013
  int32_t ToInt32() const {
1014 1015 1016 1017
    DCHECK(type() == kInt32 || type() == kInt64);
    const int32_t value = static_cast<int32_t>(value_);
    DCHECK_EQ(value_, static_cast<int64_t>(value));
    return value;
1018 1019 1020 1021
  }

  int64_t ToInt64() const {
    if (type() == kInt32) return ToInt32();
1022
    DCHECK_EQ(kInt64, type());
1023 1024 1025
    return value_;
  }

1026 1027 1028 1029 1030
  float ToFloat32() const {
    DCHECK_EQ(kFloat32, type());
    return bit_cast<float>(static_cast<int32_t>(value_));
  }

1031 1032
  double ToFloat64() const {
    if (type() == kInt32) return ToInt32();
1033
    DCHECK_EQ(kFloat64, type());
1034
    return bit_cast<double>(value_);
1035 1036 1037
  }

  ExternalReference ToExternalReference() const {
1038
    DCHECK_EQ(kExternalReference, type());
1039
    return bit_cast<ExternalReference>(static_cast<intptr_t>(value_));
1040 1041
  }

1042
  RpoNumber ToRpoNumber() const {
1043
    DCHECK_EQ(kRpoNumber, type());
1044
    return RpoNumber::FromInt(static_cast<int>(value_));
1045 1046
  }

1047
  Handle<HeapObject> ToHeapObject() const;
1048 1049 1050 1051

 private:
  Type type_;
  int64_t value_;
1052 1053 1054 1055 1056
#if V8_TARGET_ARCH_32_BIT
  RelocInfo::Mode rmode_ = RelocInfo::NONE32;
#else
  RelocInfo::Mode rmode_ = RelocInfo::NONE64;
#endif
1057 1058
};

1059

1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
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_;
};


1113 1114
class FrameStateDescriptor : public ZoneObject {
 public:
1115 1116
  FrameStateDescriptor(Zone* zone, FrameStateType type, BailoutId bailout_id,
                       OutputFrameStateCombine state_combine,
1117 1118
                       size_t parameters_count, size_t locals_count,
                       size_t stack_count,
1119
                       MaybeHandle<SharedFunctionInfo> shared_info,
1120
                       FrameStateDescriptor* outer_state = nullptr);
1121

1122
  FrameStateType type() const { return type_; }
1123
  BailoutId bailout_id() const { return bailout_id_; }
1124
  OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
1125 1126 1127
  size_t parameters_count() const { return parameters_count_; }
  size_t locals_count() const { return locals_count_; }
  size_t stack_count() const { return stack_count_; }
1128
  MaybeHandle<SharedFunctionInfo> shared_info() const { return shared_info_; }
1129
  FrameStateDescriptor* outer_state() const { return outer_state_; }
1130
  bool HasContext() const {
1131
    return FrameStateFunctionInfo::IsJSFunctionType(type_);
1132
  }
1133

1134
  size_t GetSize(OutputFrameStateCombine combine =
1135 1136 1137 1138
                     OutputFrameStateCombine::Ignore()) const;
  size_t GetTotalSize() const;
  size_t GetFrameCount() const;
  size_t GetJSFrameCount() const;
1139

1140 1141 1142 1143
  MachineType GetType(size_t index) const {
    return values_.GetOperandType(index);
  }
  StateValueDescriptor* GetStateValueDescriptor() { return &values_; }
1144

1145 1146
  static const int kImpossibleValue = 0xdead;

1147
 private:
1148
  FrameStateType type_;
1149
  BailoutId bailout_id_;
1150
  OutputFrameStateCombine frame_state_combine_;
1151 1152 1153
  size_t parameters_count_;
  size_t locals_count_;
  size_t stack_count_;
1154
  StateValueDescriptor values_;
1155
  MaybeHandle<SharedFunctionInfo> const shared_info_;
1156
  FrameStateDescriptor* outer_state_;
1157 1158
};

1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
// A deoptimization entry is a pair of the reason why we deoptimize and the
// frame state descriptor that we have to go back to.
class DeoptimizationEntry final {
 public:
  DeoptimizationEntry() {}
  DeoptimizationEntry(FrameStateDescriptor* descriptor, DeoptimizeReason reason)
      : descriptor_(descriptor), reason_(reason) {}

  FrameStateDescriptor* descriptor() const { return descriptor_; }
  DeoptimizeReason reason() const { return reason_; }
1169

1170 1171 1172 1173
 private:
  FrameStateDescriptor* descriptor_ = nullptr;
  DeoptimizeReason reason_ = DeoptimizeReason::kNoReason;
};
1174

1175
typedef ZoneVector<DeoptimizationEntry> DeoptimizationVector;
1176

1177
class PhiInstruction final : public ZoneObject {
1178
 public:
1179
  typedef ZoneVector<InstructionOperand> Inputs;
1180

1181 1182 1183
  PhiInstruction(Zone* zone, int virtual_register, size_t input_count);

  void SetInput(size_t offset, int virtual_register);
1184 1185 1186

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

1188 1189
  // TODO(dcarney): this has no real business being here, since it's internal to
  // the register allocator, but putting it here was convenient.
1190 1191
  const InstructionOperand& output() const { return output_; }
  InstructionOperand& output() { return output_; }
1192 1193 1194

 private:
  const int virtual_register_;
1195
  InstructionOperand output_;
1196 1197 1198 1199 1200
  IntVector operands_;
};


// Analogue of BasicBlock for Instructions instead of Nodes.
1201
class InstructionBlock final : public ZoneObject {
1202
 public:
1203
  InstructionBlock(Zone* zone, RpoNumber rpo_number, RpoNumber loop_header,
1204
                   RpoNumber loop_end, bool deferred, bool handler);
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225

  // 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; }

1226
  bool IsDeferred() const { return deferred_; }
1227
  bool IsHandler() const { return handler_; }
1228

1229 1230 1231 1232
  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 {
1233 1234 1235 1236 1237
    DCHECK(IsLoopHeader());
    return loop_end_;
  }
  inline bool IsLoopHeader() const { return loop_end_.IsValid(); }

1238
  typedef ZoneVector<RpoNumber> Predecessors;
1239
  Predecessors& predecessors() { return predecessors_; }
1240 1241
  const Predecessors& predecessors() const { return predecessors_; }
  size_t PredecessorCount() const { return predecessors_.size(); }
1242
  size_t PredecessorIndexOf(RpoNumber rpo_number) const;
1243

1244
  typedef ZoneVector<RpoNumber> Successors;
1245
  Successors& successors() { return successors_; }
1246 1247 1248 1249 1250 1251 1252
  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); }

1253
  void set_ao_number(RpoNumber ao_number) { ao_number_ = ao_number; }
1254

1255 1256 1257 1258 1259 1260 1261 1262 1263
  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; }

1264 1265 1266
  void set_last_deferred(RpoNumber last) { last_deferred_ = last; }
  RpoNumber last_deferred() const { return last_deferred_; }

1267 1268 1269 1270
 private:
  Successors successors_;
  Predecessors predecessors_;
  PhiInstructions phis_;
1271 1272 1273 1274
  RpoNumber ao_number_;  // Assembly order number.
  const RpoNumber rpo_number_;
  const RpoNumber loop_header_;
  const RpoNumber loop_end_;
1275 1276 1277
  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.
1278
  const bool handler_;   // Block is a handler entry point.
1279 1280 1281
  bool needs_frame_;
  bool must_construct_frame_;
  bool must_deconstruct_frame_;
1282
  RpoNumber last_deferred_;
1283 1284
};

1285
typedef ZoneDeque<Constant> ConstantDeque;
1286
typedef std::map<int, Constant, std::less<int>,
1287
                 zone_allocator<std::pair<const int, Constant> > > ConstantMap;
1288

1289
typedef ZoneDeque<Instruction*> InstructionDeque;
1290
typedef ZoneDeque<ReferenceMap*> ReferenceMapDeque;
1291
typedef ZoneVector<InstructionBlock*> InstructionBlocks;
1292

1293 1294

// Forward declarations.
1295 1296 1297
struct PrintableInstructionSequence;


1298 1299
// Represents architecture-specific generated code before, during, and after
// register allocation.
1300
class InstructionSequence final : public ZoneObject {
1301
 public:
1302 1303
  static InstructionBlocks* InstructionBlocksFor(Zone* zone,
                                                 const Schedule* schedule);
1304 1305
  // Puts the deferred blocks last.
  static void ComputeAssemblyOrder(InstructionBlocks* blocks);
1306

1307 1308
  InstructionSequence(Isolate* isolate, Zone* zone,
                      InstructionBlocks* instruction_blocks);
1309

1310
  int NextVirtualRegister();
1311 1312
  int VirtualRegisterCount() const { return next_virtual_register_; }

1313
  const InstructionBlocks& instruction_blocks() const {
1314
    return *instruction_blocks_;
1315 1316
  }

1317
  int InstructionBlockCount() const {
1318
    return static_cast<int>(instruction_blocks_->size());
1319 1320
  }

1321
  InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) {
1322
    return instruction_blocks_->at(rpo_number.ToSize());
1323 1324
  }

1325
  int LastLoopInstructionIndex(const InstructionBlock* block) {
1326
    return instruction_blocks_->at(block->loop_end().ToSize() - 1)
1327 1328 1329
        ->last_instruction_index();
  }

1330
  const InstructionBlock* InstructionBlockAt(RpoNumber rpo_number) const {
1331
    return instruction_blocks_->at(rpo_number.ToSize());
1332 1333
  }

1334
  InstructionBlock* GetInstructionBlock(int instruction_index) const;
1335

1336 1337
  static MachineRepresentation DefaultRepresentation() {
    return MachineType::PointerRepresentation();
1338
  }
1339 1340
  MachineRepresentation GetRepresentation(int virtual_register) const;
  void MarkAsRepresentation(MachineRepresentation rep, int virtual_register);
1341

1342
  bool IsReference(int virtual_register) const {
1343
    return CanBeTaggedPointer(GetRepresentation(virtual_register));
1344
  }
1345
  bool IsFP(int virtual_register) const {
1346
    return IsFloatingPoint(GetRepresentation(virtual_register));
1347
  }
1348 1349 1350 1351 1352 1353 1354 1355
  bool IsFloat(int virtual_register) const {
    return GetRepresentation(virtual_register) ==
           MachineRepresentation::kFloat32;
  }
  bool IsDouble(int virtual_register) const {
    return GetRepresentation(virtual_register) ==
           MachineRepresentation::kFloat64;
  }
1356

1357
  Instruction* GetBlockStart(RpoNumber rpo) const;
1358 1359 1360 1361

  typedef InstructionDeque::const_iterator const_iterator;
  const_iterator begin() const { return instructions_.begin(); }
  const_iterator end() const { return instructions_.end(); }
1362
  const InstructionDeque& instructions() const { return instructions_; }
1363 1364 1365
  int LastInstructionIndex() const {
    return static_cast<int>(instructions().size()) - 1;
  }
1366 1367

  Instruction* InstructionAt(int index) const {
1368 1369
    DCHECK(index >= 0);
    DCHECK(index < static_cast<int>(instructions_.size()));
1370 1371 1372
    return instructions_[index];
  }

1373
  Isolate* isolate() const { return isolate_; }
1374
  const ReferenceMapDeque* reference_maps() const { return &reference_maps_; }
1375
  Zone* zone() const { return zone_; }
1376

1377 1378
  // Used by the instruction selector while adding instructions.
  int AddInstruction(Instruction* instr);
1379 1380
  void StartBlock(RpoNumber rpo);
  void EndBlock(RpoNumber rpo);
1381

1382
  int AddConstant(int virtual_register, Constant constant) {
1383 1384
    // TODO(titzer): allow RPO numbers as constants?
    DCHECK(constant.type() != Constant::kRpoNumber);
1385
    DCHECK(virtual_register >= 0 && virtual_register < next_virtual_register_);
1386
    DCHECK(constants_.find(virtual_register) == constants_.end());
1387
    constants_.insert(std::make_pair(virtual_register, constant));
1388
    return virtual_register;
1389 1390 1391
  }
  Constant GetConstant(int virtual_register) const {
    ConstantMap::const_iterator it = constants_.find(virtual_register);
1392 1393
    DCHECK(it != constants_.end());
    DCHECK_EQ(virtual_register, it->first);
1394 1395 1396
    return it->second;
  }

1397 1398
  typedef ZoneVector<Constant> Immediates;
  Immediates& immediates() { return immediates_; }
1399

1400
  ImmediateOperand AddImmediate(const Constant& constant) {
1401 1402
    if (constant.type() == Constant::kInt32 &&
        RelocInfo::IsNone(constant.rmode())) {
1403 1404
      return ImmediateOperand(ImmediateOperand::INLINE, constant.ToInt32());
    }
1405
    int index = static_cast<int>(immediates_.size());
1406
    immediates_.push_back(constant);
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422
    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));
1423 1424
  }

1425 1426 1427 1428 1429
  int AddDeoptimizationEntry(FrameStateDescriptor* descriptor,
                             DeoptimizeReason reason);
  DeoptimizationEntry const& GetDeoptimizationEntry(int deoptimization_id);
  int GetDeoptimizationEntryCount() const {
    return static_cast<int>(deoptimization_entries_.size());
1430
  }
1431

1432
  RpoNumber InputRpo(Instruction* instr, size_t index);
1433

1434 1435 1436 1437
  bool GetSourcePosition(const Instruction* instr,
                         SourcePosition* result) const;
  void SetSourcePosition(const Instruction* instr, SourcePosition value);

1438 1439 1440 1441 1442 1443
  bool ContainsCall() const {
    for (Instruction* instr : instructions_) {
      if (instr->IsCall()) return true;
    }
    return false;
  }
1444 1445
  void Print(const RegisterConfiguration* config) const;
  void Print() const;
1446

1447 1448 1449
  void PrintBlock(const RegisterConfiguration* config, int block_id) const;
  void PrintBlock(int block_id) const;

1450 1451 1452 1453
  void ValidateEdgeSplitForm() const;
  void ValidateDeferredBlockExitPaths() const;
  void ValidateDeferredBlockEntryPaths() const;
  void ValidateSSA() const;
1454

1455
 private:
1456
  friend std::ostream& operator<<(std::ostream& os,
1457
                                  const PrintableInstructionSequence& code);
1458

1459
  typedef ZoneMap<const Instruction*, SourcePosition> SourcePositionMap;
1460

1461
  Isolate* isolate_;
1462
  Zone* const zone_;
1463
  InstructionBlocks* const instruction_blocks_;
1464
  SourcePositionMap source_positions_;
1465
  ConstantMap constants_;
1466
  Immediates immediates_;
1467 1468
  InstructionDeque instructions_;
  int next_virtual_register_;
1469
  ReferenceMapDeque reference_maps_;
1470
  ZoneVector<MachineRepresentation> representations_;
1471
  DeoptimizationVector deoptimization_entries_;
1472

1473 1474 1475
  // Used at construction time
  InstructionBlock* current_block_;

1476
  DISALLOW_COPY_AND_ASSIGN(InstructionSequence);
1477 1478
};

1479 1480 1481 1482 1483 1484 1485 1486 1487

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


std::ostream& operator<<(std::ostream& os,
                         const PrintableInstructionSequence& code);
1488 1489 1490 1491 1492 1493

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

#endif  // V8_COMPILER_INSTRUCTION_H_