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