OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_COMPILER_INSTRUCTION_H_ | 5 #ifndef V8_COMPILER_INSTRUCTION_H_ |
6 #define V8_COMPILER_INSTRUCTION_H_ | 6 #define V8_COMPILER_INSTRUCTION_H_ |
7 | 7 |
8 #include <deque> | 8 #include <deque> |
9 #include <iosfwd> | 9 #include <iosfwd> |
10 #include <map> | 10 #include <map> |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) | 43 INSTRUCTION_OPERAND_PREDICATE(Constant, CONSTANT) |
44 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) | 44 INSTRUCTION_OPERAND_PREDICATE(Immediate, IMMEDIATE) |
45 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) | 45 INSTRUCTION_OPERAND_PREDICATE(Allocated, ALLOCATED) |
46 #undef INSTRUCTION_OPERAND_PREDICATE | 46 #undef INSTRUCTION_OPERAND_PREDICATE |
47 | 47 |
48 inline bool IsRegister() const; | 48 inline bool IsRegister() const; |
49 inline bool IsDoubleRegister() const; | 49 inline bool IsDoubleRegister() const; |
50 inline bool IsStackSlot() const; | 50 inline bool IsStackSlot() const; |
51 inline bool IsDoubleStackSlot() const; | 51 inline bool IsDoubleStackSlot() const; |
52 | 52 |
53 bool Equals(const InstructionOperand* other) const { | |
54 return value_ == other->value_; | |
55 } | |
56 | |
57 // Useful for map/set keys. | 53 // Useful for map/set keys. |
58 bool operator<(const InstructionOperand& op) const { | 54 bool operator<(const InstructionOperand& op) const { |
59 return value_ < op.value_; | 55 return value_ < op.value_; |
60 } | 56 } |
61 | 57 |
62 bool operator==(const InstructionOperand& op) const { | 58 bool operator==(const InstructionOperand& op) const { |
63 return value_ == op.value_; | 59 return value_ == op.value_; |
64 } | 60 } |
65 | 61 |
| 62 bool operator!=(const InstructionOperand& op) const { |
| 63 return value_ != op.value_; |
| 64 } |
| 65 |
66 template <typename SubKindOperand> | 66 template <typename SubKindOperand> |
67 static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { | 67 static SubKindOperand* New(Zone* zone, const SubKindOperand& op) { |
68 void* buffer = zone->New(sizeof(op)); | 68 void* buffer = zone->New(sizeof(op)); |
69 return new (buffer) SubKindOperand(op); | 69 return new (buffer) SubKindOperand(op); |
70 } | 70 } |
71 | 71 |
72 static void ReplaceWith(InstructionOperand* dest, | 72 static void ReplaceWith(InstructionOperand* dest, |
73 const InstructionOperand* src) { | 73 const InstructionOperand* src) { |
74 *dest = *src; | 74 *dest = *src; |
75 } | 75 } |
76 | 76 |
77 protected: | 77 protected: |
78 explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} | 78 explicit InstructionOperand(Kind kind) : value_(KindField::encode(kind)) {} |
79 | 79 |
80 class KindField : public BitField64<Kind, 0, 3> {}; | 80 class KindField : public BitField64<Kind, 0, 3> {}; |
81 | 81 |
82 uint64_t value_; | 82 uint64_t value_; |
83 }; | 83 }; |
84 | 84 |
85 struct PrintableInstructionOperand { | 85 struct PrintableInstructionOperand { |
86 const RegisterConfiguration* register_configuration_; | 86 const RegisterConfiguration* register_configuration_; |
87 const InstructionOperand* op_; | 87 InstructionOperand op_; |
88 }; | 88 }; |
89 | 89 |
90 std::ostream& operator<<(std::ostream& os, | 90 std::ostream& operator<<(std::ostream& os, |
91 const PrintableInstructionOperand& op); | 91 const PrintableInstructionOperand& op); |
92 | 92 |
93 #define INSTRUCTION_OPERAND_CASTS(OperandType, OperandKind) \ | 93 #define INSTRUCTION_OPERAND_CASTS(OperandType, OperandKind) \ |
94 \ | 94 \ |
95 static OperandType* cast(InstructionOperand* op) { \ | 95 static OperandType* cast(InstructionOperand* op) { \ |
96 DCHECK_EQ(OperandKind, op->kind()); \ | 96 DCHECK_EQ(OperandKind, op->kind()); \ |
97 return static_cast<OperandType*>(op); \ | 97 return static_cast<OperandType*>(op); \ |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 } | 160 } |
161 | 161 |
162 UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime, | 162 UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime, |
163 int virtual_register) | 163 int virtual_register) |
164 : UnallocatedOperand(virtual_register) { | 164 : UnallocatedOperand(virtual_register) { |
165 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | 165 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); |
166 value_ |= ExtendedPolicyField::encode(policy); | 166 value_ |= ExtendedPolicyField::encode(policy); |
167 value_ |= LifetimeField::encode(lifetime); | 167 value_ |= LifetimeField::encode(lifetime); |
168 } | 168 } |
169 | 169 |
170 UnallocatedOperand* Copy(Zone* zone) { return New(zone, *this); } | |
171 | |
172 UnallocatedOperand* CopyUnconstrained(Zone* zone) { | |
173 return New(zone, UnallocatedOperand(ANY, virtual_register())); | |
174 } | |
175 | |
176 // Predicates for the operand policy. | 170 // Predicates for the operand policy. |
177 bool HasAnyPolicy() const { | 171 bool HasAnyPolicy() const { |
178 return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY; | 172 return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY; |
179 } | 173 } |
180 bool HasFixedPolicy() const { | 174 bool HasFixedPolicy() const { |
181 return basic_policy() == FIXED_SLOT || | 175 return basic_policy() == FIXED_SLOT || |
182 extended_policy() == FIXED_REGISTER || | 176 extended_policy() == FIXED_REGISTER || |
183 extended_policy() == FIXED_DOUBLE_REGISTER; | 177 extended_policy() == FIXED_DOUBLE_REGISTER; |
184 } | 178 } |
185 bool HasRegisterPolicy() const { | 179 bool HasRegisterPolicy() const { |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 \ | 422 \ |
429 static SubKind##Operand cast(const InstructionOperand& op) { \ | 423 static SubKind##Operand cast(const InstructionOperand& op) { \ |
430 DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op).allocated_kind()); \ | 424 DCHECK_EQ(kOperandKind, AllocatedOperand::cast(op).allocated_kind()); \ |
431 return *static_cast<const SubKind##Operand*>(&op); \ | 425 return *static_cast<const SubKind##Operand*>(&op); \ |
432 } \ | 426 } \ |
433 }; | 427 }; |
434 ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_CLASS) | 428 ALLOCATED_OPERAND_LIST(ALLOCATED_OPERAND_CLASS) |
435 #undef ALLOCATED_OPERAND_CLASS | 429 #undef ALLOCATED_OPERAND_CLASS |
436 | 430 |
437 | 431 |
438 class MoveOperands FINAL { | 432 class MoveOperands FINAL : public ZoneObject { |
439 public: | 433 public: |
440 MoveOperands(InstructionOperand* source, InstructionOperand* destination) | 434 MoveOperands(const InstructionOperand& source, |
441 : source_(source), destination_(destination) {} | 435 const InstructionOperand& destination) |
| 436 : source_(source), destination_(destination) { |
| 437 DCHECK(!source.IsInvalid() && !destination.IsInvalid()); |
| 438 } |
442 | 439 |
443 InstructionOperand* source() const { return source_; } | 440 const InstructionOperand& source() const { return source_; } |
444 void set_source(InstructionOperand* operand) { source_ = operand; } | 441 InstructionOperand& source() { return source_; } |
| 442 void set_source(const InstructionOperand& operand) { source_ = operand; } |
445 | 443 |
446 InstructionOperand* destination() const { return destination_; } | 444 const InstructionOperand& destination() const { return destination_; } |
447 void set_destination(InstructionOperand* operand) { destination_ = operand; } | 445 InstructionOperand& destination() { return destination_; } |
| 446 void set_destination(const InstructionOperand& operand) { |
| 447 destination_ = operand; |
| 448 } |
448 | 449 |
449 // The gap resolver marks moves as "in-progress" by clearing the | 450 // The gap resolver marks moves as "in-progress" by clearing the |
450 // destination (but not the source). | 451 // destination (but not the source). |
451 bool IsPending() const { return destination_ == NULL && source_ != NULL; } | 452 bool IsPending() const { |
| 453 return destination_.IsInvalid() && !source_.IsInvalid(); |
| 454 } |
| 455 void SetPending() { destination_ = InstructionOperand(); } |
452 | 456 |
453 // True if this move a move into the given destination operand. | 457 // True if this move a move into the given destination operand. |
454 bool Blocks(InstructionOperand* operand) const { | 458 bool Blocks(const InstructionOperand& operand) const { |
455 return !IsEliminated() && source()->Equals(operand); | 459 return !IsEliminated() && source() == operand; |
456 } | 460 } |
457 | 461 |
458 // A move is redundant if it's been eliminated or if its source and | 462 // A move is redundant if it's been eliminated or if its source and |
459 // destination are the same. | 463 // destination are the same. |
460 bool IsRedundant() const { | 464 bool IsRedundant() const { |
461 DCHECK_IMPLIES(destination_ != nullptr, !destination_->IsConstant()); | 465 DCHECK_IMPLIES(!destination_.IsInvalid(), !destination_.IsConstant()); |
462 return IsEliminated() || source_->Equals(destination_); | 466 return IsEliminated() || source_ == destination_; |
463 } | 467 } |
464 | 468 |
465 // We clear both operands to indicate move that's been eliminated. | 469 // We clear both operands to indicate move that's been eliminated. |
466 void Eliminate() { source_ = destination_ = NULL; } | 470 void Eliminate() { source_ = destination_ = InstructionOperand(); } |
467 bool IsEliminated() const { | 471 bool IsEliminated() const { |
468 DCHECK(source_ != NULL || destination_ == NULL); | 472 DCHECK_IMPLIES(source_.IsInvalid(), destination_.IsInvalid()); |
469 return source_ == NULL; | 473 return source_.IsInvalid(); |
470 } | 474 } |
471 | 475 |
472 private: | 476 private: |
473 InstructionOperand* source_; | 477 InstructionOperand source_; |
474 InstructionOperand* destination_; | 478 InstructionOperand destination_; |
| 479 |
| 480 DISALLOW_COPY_AND_ASSIGN(MoveOperands); |
475 }; | 481 }; |
476 | 482 |
477 | 483 |
478 struct PrintableMoveOperands { | 484 struct PrintableMoveOperands { |
479 const RegisterConfiguration* register_configuration_; | 485 const RegisterConfiguration* register_configuration_; |
480 const MoveOperands* move_operands_; | 486 const MoveOperands* move_operands_; |
481 }; | 487 }; |
482 | 488 |
483 | 489 |
484 std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo); | 490 std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo); |
485 | 491 |
486 | 492 |
487 class ParallelMove FINAL : public ZoneObject { | 493 class ParallelMove FINAL : public ZoneVector<MoveOperands*>, public ZoneObject { |
488 public: | 494 public: |
489 explicit ParallelMove(Zone* zone) : move_operands_(4, zone) {} | 495 explicit ParallelMove(Zone* zone) : ZoneVector<MoveOperands*>(zone) { |
| 496 reserve(4); |
| 497 } |
490 | 498 |
491 void AddMove(InstructionOperand* from, InstructionOperand* to, Zone* zone) { | 499 MoveOperands* AddMove(const InstructionOperand& from, |
492 move_operands_.Add(MoveOperands(from, to), zone); | 500 const InstructionOperand& to) { |
| 501 auto zone = get_allocator().zone(); |
| 502 auto move = new (zone) MoveOperands(from, to); |
| 503 push_back(move); |
| 504 return move; |
493 } | 505 } |
494 | 506 |
495 bool IsRedundant() const; | 507 bool IsRedundant() const; |
496 | 508 |
497 ZoneList<MoveOperands>* move_operands() { return &move_operands_; } | |
498 const ZoneList<MoveOperands>* move_operands() const { | |
499 return &move_operands_; | |
500 } | |
501 | |
502 // Prepare this ParallelMove to insert move as if it happened in a subsequent | 509 // Prepare this ParallelMove to insert move as if it happened in a subsequent |
503 // ParallelMove. move->source() may be changed. The MoveOperand returned | 510 // ParallelMove. move->source() may be changed. The MoveOperand returned |
504 // must be Eliminated and, as it points directly into move_operands_, it must | 511 // must be Eliminated. |
505 // be Eliminated before any further mutation. | |
506 MoveOperands* PrepareInsertAfter(MoveOperands* move) const; | 512 MoveOperands* PrepareInsertAfter(MoveOperands* move) const; |
507 | 513 |
508 private: | 514 private: |
509 ZoneList<MoveOperands> move_operands_; | 515 DISALLOW_COPY_AND_ASSIGN(ParallelMove); |
510 }; | 516 }; |
511 | 517 |
512 | 518 |
513 struct PrintableParallelMove { | 519 struct PrintableParallelMove { |
514 const RegisterConfiguration* register_configuration_; | 520 const RegisterConfiguration* register_configuration_; |
515 const ParallelMove* parallel_move_; | 521 const ParallelMove* parallel_move_; |
516 }; | 522 }; |
517 | 523 |
518 | 524 |
519 std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm); | 525 std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm); |
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
849 public: | 855 public: |
850 typedef ZoneVector<InstructionOperand> Inputs; | 856 typedef ZoneVector<InstructionOperand> Inputs; |
851 | 857 |
852 PhiInstruction(Zone* zone, int virtual_register, size_t input_count); | 858 PhiInstruction(Zone* zone, int virtual_register, size_t input_count); |
853 | 859 |
854 void SetInput(size_t offset, int virtual_register); | 860 void SetInput(size_t offset, int virtual_register); |
855 | 861 |
856 int virtual_register() const { return virtual_register_; } | 862 int virtual_register() const { return virtual_register_; } |
857 const IntVector& operands() const { return operands_; } | 863 const IntVector& operands() const { return operands_; } |
858 | 864 |
| 865 // TODO(dcarney): this has no real business being here, since it's internal to |
| 866 // the register allocator, but putting it here was convenient. |
859 const InstructionOperand& output() const { return output_; } | 867 const InstructionOperand& output() const { return output_; } |
860 InstructionOperand& output() { return output_; } | 868 InstructionOperand& output() { return output_; } |
861 const Inputs& inputs() const { return inputs_; } | |
862 Inputs& inputs() { return inputs_; } | |
863 | 869 |
864 private: | 870 private: |
865 // TODO(dcarney): some of these fields are only for verification, move them to | |
866 // verifier. | |
867 const int virtual_register_; | 871 const int virtual_register_; |
868 InstructionOperand output_; | 872 InstructionOperand output_; |
869 IntVector operands_; | 873 IntVector operands_; |
870 Inputs inputs_; | |
871 }; | 874 }; |
872 | 875 |
873 | 876 |
874 // Analogue of BasicBlock for Instructions instead of Nodes. | 877 // Analogue of BasicBlock for Instructions instead of Nodes. |
875 class InstructionBlock FINAL : public ZoneObject { | 878 class InstructionBlock FINAL : public ZoneObject { |
876 public: | 879 public: |
877 InstructionBlock(Zone* zone, RpoNumber rpo_number, RpoNumber loop_header, | 880 InstructionBlock(Zone* zone, RpoNumber rpo_number, RpoNumber loop_header, |
878 RpoNumber loop_end, bool deferred); | 881 RpoNumber loop_end, bool deferred); |
879 | 882 |
880 // Instruction indexes (used by the register allocator). | 883 // Instruction indexes (used by the register allocator). |
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1111 | 1114 |
1112 | 1115 |
1113 std::ostream& operator<<(std::ostream& os, | 1116 std::ostream& operator<<(std::ostream& os, |
1114 const PrintableInstructionSequence& code); | 1117 const PrintableInstructionSequence& code); |
1115 | 1118 |
1116 } // namespace compiler | 1119 } // namespace compiler |
1117 } // namespace internal | 1120 } // namespace internal |
1118 } // namespace v8 | 1121 } // namespace v8 |
1119 | 1122 |
1120 #endif // V8_COMPILER_INSTRUCTION_H_ | 1123 #endif // V8_COMPILER_INSTRUCTION_H_ |
OLD | NEW |