| 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 17 matching lines...) Expand all Loading... |
| 28 const InstructionCode kSourcePositionInstruction = -2; | 28 const InstructionCode kSourcePositionInstruction = -2; |
| 29 | 29 |
| 30 #define INSTRUCTION_OPERAND_LIST(V) \ | 30 #define INSTRUCTION_OPERAND_LIST(V) \ |
| 31 V(Constant, CONSTANT, 0) \ | 31 V(Constant, CONSTANT, 0) \ |
| 32 V(Immediate, IMMEDIATE, 0) \ | 32 V(Immediate, IMMEDIATE, 0) \ |
| 33 V(StackSlot, STACK_SLOT, 128) \ | 33 V(StackSlot, STACK_SLOT, 128) \ |
| 34 V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \ | 34 V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \ |
| 35 V(Register, REGISTER, RegisterConfiguration::kMaxGeneralRegisters) \ | 35 V(Register, REGISTER, RegisterConfiguration::kMaxGeneralRegisters) \ |
| 36 V(DoubleRegister, DOUBLE_REGISTER, RegisterConfiguration::kMaxDoubleRegisters) | 36 V(DoubleRegister, DOUBLE_REGISTER, RegisterConfiguration::kMaxDoubleRegisters) |
| 37 | 37 |
| 38 class InstructionOperand : public ZoneObject { | 38 class InstructionOperand { |
| 39 public: | 39 public: |
| 40 static const int kInvalidVirtualRegister = -1; | 40 static const int kInvalidVirtualRegister = -1; |
| 41 | 41 |
| 42 enum Kind { | 42 enum Kind { |
| 43 INVALID, | 43 INVALID, |
| 44 UNALLOCATED, | 44 UNALLOCATED, |
| 45 CONSTANT, | 45 CONSTANT, |
| 46 IMMEDIATE, | 46 IMMEDIATE, |
| 47 STACK_SLOT, | 47 STACK_SLOT, |
| 48 DOUBLE_STACK_SLOT, | 48 DOUBLE_STACK_SLOT, |
| 49 REGISTER, | 49 REGISTER, |
| 50 DOUBLE_REGISTER | 50 DOUBLE_REGISTER |
| 51 }; | 51 }; |
| 52 | 52 |
| 53 InstructionOperand() : virtual_register_(kInvalidVirtualRegister) { |
| 54 ConvertTo(INVALID, 0); |
| 55 } |
| 56 |
| 53 InstructionOperand(Kind kind, int index) | 57 InstructionOperand(Kind kind, int index) |
| 54 : virtual_register_(kInvalidVirtualRegister) { | 58 : virtual_register_(kInvalidVirtualRegister) { |
| 55 DCHECK(kind != INVALID); | 59 DCHECK(kind != INVALID); |
| 56 ConvertTo(kind, index); | 60 ConvertTo(kind, index); |
| 57 } | 61 } |
| 58 | 62 |
| 59 Kind kind() const { return KindField::decode(value_); } | 63 Kind kind() const { return KindField::decode(value_); } |
| 60 int index() const { return static_cast<int>(value_) >> KindField::kSize; } | 64 int index() const { return static_cast<int>(value_) >> KindField::kSize; } |
| 61 #define INSTRUCTION_OPERAND_PREDICATE(name, type, number) \ | 65 #define INSTRUCTION_OPERAND_PREDICATE(name, type, number) \ |
| 62 bool Is##name() const { return kind() == type; } | 66 bool Is##name() const { return kind() == type; } |
| 63 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE) | 67 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE) |
| 64 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0) | 68 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0) |
| 69 INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID, 0) |
| 65 #undef INSTRUCTION_OPERAND_PREDICATE | 70 #undef INSTRUCTION_OPERAND_PREDICATE |
| 66 bool Equals(const InstructionOperand* other) const { | 71 bool Equals(const InstructionOperand* other) const { |
| 67 return value_ == other->value_; | 72 return value_ == other->value_; |
| 68 } | 73 } |
| 69 | 74 |
| 70 void ConvertTo(Kind kind, int index) { | 75 void ConvertTo(Kind kind, int index) { |
| 71 if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0); | 76 if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0); |
| 72 value_ = KindField::encode(kind); | 77 value_ = KindField::encode(kind); |
| 73 value_ |= bit_cast<unsigned>(index << KindField::kSize); | 78 value_ |= bit_cast<unsigned>(index << KindField::kSize); |
| 74 DCHECK(this->index() == index); | 79 DCHECK(this->index() == index); |
| 75 if (kind != UNALLOCATED) virtual_register_ = kInvalidVirtualRegister; | 80 if (kind != UNALLOCATED) virtual_register_ = kInvalidVirtualRegister; |
| 76 } | 81 } |
| 77 | 82 |
| 78 // Calls SetUpCache()/TearDownCache() for each subclass. | 83 // Calls SetUpCache()/TearDownCache() for each subclass. |
| 79 static void SetUpCaches(); | 84 static void SetUpCaches(); |
| 80 static void TearDownCaches(); | 85 static void TearDownCaches(); |
| 81 | 86 |
| 87 // TODO(dcarney): get rid of these |
| 88 void* operator new(size_t, void* location) { return location; } |
| 89 void* operator new(size_t size, Zone* zone) { |
| 90 return zone->New(static_cast<int>(size)); |
| 91 } |
| 92 |
| 82 protected: | 93 protected: |
| 83 InstructionOperand(Kind kind, int index, int virtual_register) | 94 InstructionOperand(Kind kind, int index, int virtual_register) |
| 84 : virtual_register_(virtual_register) { | 95 : virtual_register_(virtual_register) { |
| 85 ConvertTo(kind, index); | 96 ConvertTo(kind, index); |
| 86 } | 97 } |
| 87 typedef BitField<Kind, 0, 3> KindField; | 98 typedef BitField<Kind, 0, 3> KindField; |
| 88 | 99 |
| 89 uint32_t value_; | 100 uint32_t value_; |
| 90 // TODO(dcarney): this should really be unsigned. | 101 // TODO(dcarney): this should really be unsigned. |
| 91 int32_t virtual_register_; | 102 int32_t virtual_register_; |
| 92 }; | 103 }; |
| 93 | 104 |
| 94 typedef ZoneVector<InstructionOperand*> InstructionOperandVector; | |
| 95 | |
| 96 struct PrintableInstructionOperand { | 105 struct PrintableInstructionOperand { |
| 97 const RegisterConfiguration* register_configuration_; | 106 const RegisterConfiguration* register_configuration_; |
| 98 const InstructionOperand* op_; | 107 const InstructionOperand* op_; |
| 99 }; | 108 }; |
| 100 | 109 |
| 101 std::ostream& operator<<(std::ostream& os, | 110 std::ostream& operator<<(std::ostream& os, |
| 102 const PrintableInstructionOperand& op); | 111 const PrintableInstructionOperand& op); |
| 103 | 112 |
| 104 class UnallocatedOperand : public InstructionOperand { | 113 class UnallocatedOperand : public InstructionOperand { |
| 105 public: | 114 public: |
| (...skipping 18 matching lines...) Expand all Loading... |
| 124 | 133 |
| 125 // USED_AT_END operand is treated as live until the end of | 134 // USED_AT_END operand is treated as live until the end of |
| 126 // instruction. This means that register allocator will not reuse it's | 135 // instruction. This means that register allocator will not reuse it's |
| 127 // register for any other operand inside instruction. | 136 // register for any other operand inside instruction. |
| 128 USED_AT_END | 137 USED_AT_END |
| 129 }; | 138 }; |
| 130 | 139 |
| 131 // TODO(dcarney): remove this. | 140 // TODO(dcarney): remove this. |
| 132 static const int kInvalidVirtualRegister = -1; | 141 static const int kInvalidVirtualRegister = -1; |
| 133 | 142 |
| 134 // This is only for array initialization. | |
| 135 UnallocatedOperand() | |
| 136 : InstructionOperand(INVALID, 0, kInvalidVirtualRegister) {} | |
| 137 | |
| 138 UnallocatedOperand(ExtendedPolicy policy, int virtual_register) | 143 UnallocatedOperand(ExtendedPolicy policy, int virtual_register) |
| 139 : InstructionOperand(UNALLOCATED, 0, virtual_register) { | 144 : InstructionOperand(UNALLOCATED, 0, virtual_register) { |
| 140 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | 145 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); |
| 141 value_ |= ExtendedPolicyField::encode(policy); | 146 value_ |= ExtendedPolicyField::encode(policy); |
| 142 value_ |= LifetimeField::encode(USED_AT_END); | 147 value_ |= LifetimeField::encode(USED_AT_END); |
| 143 } | 148 } |
| 144 | 149 |
| 145 UnallocatedOperand(BasicPolicy policy, int index, int virtual_register) | 150 UnallocatedOperand(BasicPolicy policy, int index, int virtual_register) |
| 146 : InstructionOperand(UNALLOCATED, 0, virtual_register) { | 151 : InstructionOperand(UNALLOCATED, 0, virtual_register) { |
| 147 DCHECK(policy == FIXED_SLOT); | 152 DCHECK(policy == FIXED_SLOT); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 174 static const UnallocatedOperand* cast(const InstructionOperand* op) { | 179 static const UnallocatedOperand* cast(const InstructionOperand* op) { |
| 175 DCHECK(op->IsUnallocated()); | 180 DCHECK(op->IsUnallocated()); |
| 176 return static_cast<const UnallocatedOperand*>(op); | 181 return static_cast<const UnallocatedOperand*>(op); |
| 177 } | 182 } |
| 178 | 183 |
| 179 static UnallocatedOperand* cast(InstructionOperand* op) { | 184 static UnallocatedOperand* cast(InstructionOperand* op) { |
| 180 DCHECK(op->IsUnallocated()); | 185 DCHECK(op->IsUnallocated()); |
| 181 return static_cast<UnallocatedOperand*>(op); | 186 return static_cast<UnallocatedOperand*>(op); |
| 182 } | 187 } |
| 183 | 188 |
| 189 static UnallocatedOperand cast(const InstructionOperand& op) { |
| 190 DCHECK(op.IsUnallocated()); |
| 191 return *static_cast<const UnallocatedOperand*>(&op); |
| 192 } |
| 193 |
| 184 // The encoding used for UnallocatedOperand operands depends on the policy | 194 // The encoding used for UnallocatedOperand operands depends on the policy |
| 185 // that is | 195 // that is |
| 186 // stored within the operand. The FIXED_SLOT policy uses a compact encoding | 196 // stored within the operand. The FIXED_SLOT policy uses a compact encoding |
| 187 // because it accommodates a larger pay-load. | 197 // because it accommodates a larger pay-load. |
| 188 // | 198 // |
| 189 // For FIXED_SLOT policy: | 199 // For FIXED_SLOT policy: |
| 190 // +-----------------------------+ | 200 // +-----------------------------+ |
| 191 // | slot_index | 0 | 001 | | 201 // | slot_index | 0 | 001 | |
| 192 // +-----------------------------+ | 202 // +-----------------------------+ |
| 193 // | 203 // |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 const MoveOperands* move_operands_; | 344 const MoveOperands* move_operands_; |
| 335 }; | 345 }; |
| 336 | 346 |
| 337 | 347 |
| 338 std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo); | 348 std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo); |
| 339 | 349 |
| 340 | 350 |
| 341 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands> | 351 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands> |
| 342 class SubKindOperand FINAL : public InstructionOperand { | 352 class SubKindOperand FINAL : public InstructionOperand { |
| 343 public: | 353 public: |
| 354 explicit SubKindOperand(int index) |
| 355 : InstructionOperand(kOperandKind, index) {} |
| 356 |
| 344 static SubKindOperand* Create(int index, Zone* zone) { | 357 static SubKindOperand* Create(int index, Zone* zone) { |
| 345 DCHECK(index >= 0); | 358 DCHECK(index >= 0); |
| 346 if (index < kNumCachedOperands) return &cache[index]; | 359 if (index < kNumCachedOperands) return &cache[index]; |
| 347 return new (zone) SubKindOperand(index); | 360 return new (zone) SubKindOperand(index); |
| 348 } | 361 } |
| 349 | 362 |
| 350 static SubKindOperand* cast(InstructionOperand* op) { | 363 static SubKindOperand* cast(InstructionOperand* op) { |
| 351 DCHECK(op->kind() == kOperandKind); | 364 DCHECK(op->kind() == kOperandKind); |
| 352 return reinterpret_cast<SubKindOperand*>(op); | 365 return reinterpret_cast<SubKindOperand*>(op); |
| 353 } | 366 } |
| 354 | 367 |
| 355 static const SubKindOperand* cast(const InstructionOperand* op) { | 368 static const SubKindOperand* cast(const InstructionOperand* op) { |
| 356 DCHECK(op->kind() == kOperandKind); | 369 DCHECK(op->kind() == kOperandKind); |
| 357 return reinterpret_cast<const SubKindOperand*>(op); | 370 return reinterpret_cast<const SubKindOperand*>(op); |
| 358 } | 371 } |
| 359 | 372 |
| 373 static SubKindOperand cast(const InstructionOperand& op) { |
| 374 DCHECK(op.kind() == kOperandKind); |
| 375 return *static_cast<const SubKindOperand*>(&op); |
| 376 } |
| 377 |
| 360 static void SetUpCache(); | 378 static void SetUpCache(); |
| 361 static void TearDownCache(); | 379 static void TearDownCache(); |
| 362 | 380 |
| 363 private: | 381 private: |
| 364 static SubKindOperand* cache; | 382 static SubKindOperand* cache; |
| 365 | 383 |
| 366 SubKindOperand() : InstructionOperand(kOperandKind, 0) {} // For the caches. | 384 SubKindOperand() : InstructionOperand(kOperandKind, 0) {} // For the caches. |
| 367 explicit SubKindOperand(int index) | |
| 368 : InstructionOperand(kOperandKind, index) {} | |
| 369 }; | 385 }; |
| 370 | 386 |
| 371 | 387 |
| 372 #define INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number) \ | 388 #define INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number) \ |
| 373 typedef SubKindOperand<InstructionOperand::type, number> name##Operand; | 389 typedef SubKindOperand<InstructionOperand::type, number> name##Operand; |
| 374 INSTRUCTION_OPERAND_LIST(INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS) | 390 INSTRUCTION_OPERAND_LIST(INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS) |
| 375 #undef INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS | 391 #undef INSTRUCTION_TYPEDEF_SUBKIND_OPERAND_CLASS |
| 376 | 392 |
| 377 | 393 |
| 378 class ParallelMove FINAL : public ZoneObject { | 394 class ParallelMove FINAL : public ZoneObject { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 FlagsCondition flags_condition() const { | 501 FlagsCondition flags_condition() const { |
| 486 return FlagsConditionField::decode(opcode()); | 502 return FlagsConditionField::decode(opcode()); |
| 487 } | 503 } |
| 488 | 504 |
| 489 // TODO(titzer): make control and call into flags. | 505 // TODO(titzer): make control and call into flags. |
| 490 static Instruction* New(Zone* zone, InstructionCode opcode) { | 506 static Instruction* New(Zone* zone, InstructionCode opcode) { |
| 491 return New(zone, opcode, 0, NULL, 0, NULL, 0, NULL); | 507 return New(zone, opcode, 0, NULL, 0, NULL, 0, NULL); |
| 492 } | 508 } |
| 493 | 509 |
| 494 static Instruction* New(Zone* zone, InstructionCode opcode, | 510 static Instruction* New(Zone* zone, InstructionCode opcode, |
| 495 size_t output_count, InstructionOperand** outputs, | 511 size_t output_count, InstructionOperand* outputs, |
| 496 size_t input_count, InstructionOperand** inputs, | 512 size_t input_count, InstructionOperand* inputs, |
| 497 size_t temp_count, InstructionOperand** temps) { | 513 size_t temp_count, InstructionOperand* temps) { |
| 498 DCHECK(opcode >= 0); | 514 DCHECK(opcode >= 0); |
| 499 DCHECK(output_count == 0 || outputs != NULL); | 515 DCHECK(output_count == 0 || outputs != NULL); |
| 500 DCHECK(input_count == 0 || inputs != NULL); | 516 DCHECK(input_count == 0 || inputs != NULL); |
| 501 DCHECK(temp_count == 0 || temps != NULL); | 517 DCHECK(temp_count == 0 || temps != NULL); |
| 502 size_t total_extra_ops = output_count + input_count + temp_count; | 518 size_t total_extra_ops = output_count + input_count + temp_count; |
| 503 if (total_extra_ops != 0) total_extra_ops--; | 519 if (total_extra_ops != 0) total_extra_ops--; |
| 504 int size = static_cast<int>( | 520 int size = static_cast<int>( |
| 505 RoundUp(sizeof(Instruction), sizeof(UnallocatedOperand)) + | 521 RoundUp(sizeof(Instruction), sizeof(InstructionOperand)) + |
| 506 total_extra_ops * sizeof(UnallocatedOperand)); | 522 total_extra_ops * sizeof(InstructionOperand)); |
| 507 return new (zone->New(size)) Instruction( | 523 return new (zone->New(size)) Instruction( |
| 508 opcode, output_count, outputs, input_count, inputs, temp_count, temps); | 524 opcode, output_count, outputs, input_count, inputs, temp_count, temps); |
| 509 } | 525 } |
| 510 | 526 |
| 511 // TODO(titzer): another holdover from lithium days; register allocator | 527 // TODO(titzer): another holdover from lithium days; register allocator |
| 512 // should not need to know about control instructions. | 528 // should not need to know about control instructions. |
| 513 Instruction* MarkAsControl() { | 529 Instruction* MarkAsControl() { |
| 514 bit_field_ = IsControlField::update(bit_field_, true); | 530 bit_field_ = IsControlField::update(bit_field_, true); |
| 515 return this; | 531 return this; |
| 516 } | 532 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 } | 568 } |
| 553 | 569 |
| 554 bool IsNop() const { | 570 bool IsNop() const { |
| 555 return arch_opcode() == kArchNop && InputCount() == 0 && | 571 return arch_opcode() == kArchNop && InputCount() == 0 && |
| 556 OutputCount() == 0 && TempCount() == 0; | 572 OutputCount() == 0 && TempCount() == 0; |
| 557 } | 573 } |
| 558 | 574 |
| 559 protected: | 575 protected: |
| 560 explicit Instruction(InstructionCode opcode); | 576 explicit Instruction(InstructionCode opcode); |
| 561 Instruction(InstructionCode opcode, size_t output_count, | 577 Instruction(InstructionCode opcode, size_t output_count, |
| 562 InstructionOperand** outputs, size_t input_count, | 578 InstructionOperand* outputs, size_t input_count, |
| 563 InstructionOperand** inputs, size_t temp_count, | 579 InstructionOperand* inputs, size_t temp_count, |
| 564 InstructionOperand** temps); | 580 InstructionOperand* temps); |
| 565 | 581 |
| 566 protected: | 582 protected: |
| 567 typedef BitField<size_t, 0, 8> OutputCountField; | 583 typedef BitField<size_t, 0, 8> OutputCountField; |
| 568 typedef BitField<size_t, 8, 16> InputCountField; | 584 typedef BitField<size_t, 8, 16> InputCountField; |
| 569 typedef BitField<size_t, 24, 6> TempCountField; | 585 typedef BitField<size_t, 24, 6> TempCountField; |
| 570 typedef BitField<bool, 30, 1> IsCallField; | 586 typedef BitField<bool, 30, 1> IsCallField; |
| 571 typedef BitField<bool, 31, 1> IsControlField; | 587 typedef BitField<bool, 31, 1> IsControlField; |
| 572 | 588 |
| 573 InstructionCode opcode_; | 589 InstructionCode opcode_; |
| 574 uint32_t bit_field_; | 590 uint32_t bit_field_; |
| 575 PointerMap* pointer_map_; | 591 PointerMap* pointer_map_; |
| 576 UnallocatedOperand operands_[1]; | 592 InstructionOperand operands_[1]; |
| 577 }; | 593 }; |
| 578 | 594 |
| 579 | 595 |
| 580 struct PrintableInstruction { | 596 struct PrintableInstruction { |
| 581 const RegisterConfiguration* register_configuration_; | 597 const RegisterConfiguration* register_configuration_; |
| 582 const Instruction* instr_; | 598 const Instruction* instr_; |
| 583 }; | 599 }; |
| 584 std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr); | 600 std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr); |
| 585 | 601 |
| 586 | 602 |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1068 | 1084 |
| 1069 | 1085 |
| 1070 std::ostream& operator<<(std::ostream& os, | 1086 std::ostream& operator<<(std::ostream& os, |
| 1071 const PrintableInstructionSequence& code); | 1087 const PrintableInstructionSequence& code); |
| 1072 | 1088 |
| 1073 } // namespace compiler | 1089 } // namespace compiler |
| 1074 } // namespace internal | 1090 } // namespace internal |
| 1075 } // namespace v8 | 1091 } // namespace v8 |
| 1076 | 1092 |
| 1077 #endif // V8_COMPILER_INSTRUCTION_H_ | 1093 #endif // V8_COMPILER_INSTRUCTION_H_ |
| OLD | NEW |