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