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.
5 #ifndef V8_COMPILER_INSTRUCTION_H_
6 #define V8_COMPILER_INSTRUCTION_H_
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/register-configuration.h"
18 #include "src/compiler/schedule.h"
19 #include "src/compiler/source-position.h"
20 #include "src/zone-allocator.h"
26 // A couple of reserved opcodes are used for internal use.
27 const InstructionCode kGapInstruction = -1;
28 const InstructionCode kSourcePositionInstruction = -2;
30 #define INSTRUCTION_OPERAND_LIST(V) \
31 V(Constant, CONSTANT) \
32 V(Immediate, IMMEDIATE) \
33 V(StackSlot, STACK_SLOT) \
34 V(DoubleStackSlot, DOUBLE_STACK_SLOT) \
35 V(Register, REGISTER) \
36 V(DoubleRegister, DOUBLE_REGISTER)
38 class InstructionOperand {
40 static const int kInvalidVirtualRegister = -1;
53 InstructionOperand() : virtual_register_(kInvalidVirtualRegister) {
54 ConvertTo(INVALID, 0);
57 InstructionOperand(Kind kind, int index)
58 : virtual_register_(kInvalidVirtualRegister) {
59 DCHECK(kind != INVALID);
60 ConvertTo(kind, index);
63 static InstructionOperand* New(Zone* zone, Kind kind, int index) {
64 return New(zone, InstructionOperand(kind, index));
67 Kind kind() const { return KindField::decode(value_); }
68 int index() const { return static_cast<int>(value_) >> KindField::kSize; }
69 #define INSTRUCTION_OPERAND_PREDICATE(name, type) \
70 bool Is##name() const { return kind() == type; }
71 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_PREDICATE)
72 INSTRUCTION_OPERAND_PREDICATE(Unallocated, UNALLOCATED)
73 INSTRUCTION_OPERAND_PREDICATE(Invalid, INVALID)
74 #undef INSTRUCTION_OPERAND_PREDICATE
75 bool Equals(const InstructionOperand* other) const {
76 return value_ == other->value_;
79 void ConvertTo(Kind kind, int index) {
80 if (kind == REGISTER || kind == DOUBLE_REGISTER) DCHECK(index >= 0);
81 value_ = KindField::encode(kind);
82 value_ |= bit_cast<unsigned>(index << KindField::kSize);
83 DCHECK(this->index() == index);
84 if (kind != UNALLOCATED) virtual_register_ = kInvalidVirtualRegister;
88 template <typename SubKindOperand>
89 static SubKindOperand* New(Zone* zone, const SubKindOperand& op) {
90 void* buffer = zone->New(sizeof(op));
91 return new (buffer) SubKindOperand(op);
94 InstructionOperand(Kind kind, int index, int virtual_register)
95 : virtual_register_(virtual_register) {
96 ConvertTo(kind, index);
98 typedef BitField<Kind, 0, 3> KindField;
101 // TODO(dcarney): this should really be unsigned.
102 int32_t virtual_register_;
105 struct PrintableInstructionOperand {
106 const RegisterConfiguration* register_configuration_;
107 const InstructionOperand* op_;
110 std::ostream& operator<<(std::ostream& os,
111 const PrintableInstructionOperand& op);
113 class UnallocatedOperand : public InstructionOperand {
115 enum BasicPolicy { FIXED_SLOT, EXTENDED_POLICY };
117 enum ExtendedPolicy {
121 FIXED_DOUBLE_REGISTER,
126 // Lifetime of operand inside the instruction.
128 // USED_AT_START operand is guaranteed to be live only at
129 // instruction start. Register allocator is free to assign the same register
130 // to some other operand used inside instruction (i.e. temporary or
134 // USED_AT_END operand is treated as live until the end of
135 // instruction. This means that register allocator will not reuse it's
136 // register for any other operand inside instruction.
140 UnallocatedOperand(ExtendedPolicy policy, int virtual_register)
141 : InstructionOperand(UNALLOCATED, 0, virtual_register) {
142 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
143 value_ |= ExtendedPolicyField::encode(policy);
144 value_ |= LifetimeField::encode(USED_AT_END);
147 UnallocatedOperand(BasicPolicy policy, int index, int virtual_register)
148 : InstructionOperand(UNALLOCATED, 0, virtual_register) {
149 DCHECK(policy == FIXED_SLOT);
150 value_ |= BasicPolicyField::encode(policy);
151 value_ |= static_cast<int32_t>(index) << FixedSlotIndexField::kShift;
152 DCHECK(this->fixed_slot_index() == index);
155 UnallocatedOperand(ExtendedPolicy policy, int index, int virtual_register)
156 : InstructionOperand(UNALLOCATED, 0, virtual_register) {
157 DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER);
158 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
159 value_ |= ExtendedPolicyField::encode(policy);
160 value_ |= LifetimeField::encode(USED_AT_END);
161 value_ |= FixedRegisterField::encode(index);
164 UnallocatedOperand(ExtendedPolicy policy, Lifetime lifetime,
165 int virtual_register)
166 : InstructionOperand(UNALLOCATED, 0, virtual_register) {
167 value_ |= BasicPolicyField::encode(EXTENDED_POLICY);
168 value_ |= ExtendedPolicyField::encode(policy);
169 value_ |= LifetimeField::encode(lifetime);
172 UnallocatedOperand* Copy(Zone* zone) { return New(zone, *this); }
174 UnallocatedOperand* CopyUnconstrained(Zone* zone) {
175 return New(zone, UnallocatedOperand(ANY, virtual_register()));
178 static const UnallocatedOperand* cast(const InstructionOperand* op) {
179 DCHECK(op->IsUnallocated());
180 return static_cast<const UnallocatedOperand*>(op);
183 static UnallocatedOperand* cast(InstructionOperand* op) {
184 DCHECK(op->IsUnallocated());
185 return static_cast<UnallocatedOperand*>(op);
188 static UnallocatedOperand cast(const InstructionOperand& op) {
189 DCHECK(op.IsUnallocated());
190 return *static_cast<const UnallocatedOperand*>(&op);
193 // The encoding used for UnallocatedOperand operands depends on the policy
195 // stored within the operand. The FIXED_SLOT policy uses a compact encoding
196 // because it accommodates a larger pay-load.
198 // For FIXED_SLOT policy:
199 // +-----------------------------+
200 // | slot_index | 0 | 001 |
201 // +-----------------------------+
203 // For all other (extended) policies:
204 // +----------------------------------+
205 // | reg_index | L | PPP | 1 | 001 | L ... Lifetime
206 // +----------------------------------+ P ... Policy
208 // The slot index is a signed value which requires us to decode it manually
209 // instead of using the BitField utility class.
211 // The superclass has a KindField.
212 STATIC_ASSERT(KindField::kSize == 3);
214 // BitFields for all unallocated operands.
215 class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {};
217 // BitFields specific to BasicPolicy::FIXED_SLOT.
218 class FixedSlotIndexField : public BitField<int, 4, 28> {};
220 // BitFields specific to BasicPolicy::EXTENDED_POLICY.
221 class ExtendedPolicyField : public BitField<ExtendedPolicy, 4, 3> {};
222 class LifetimeField : public BitField<Lifetime, 7, 1> {};
223 class FixedRegisterField : public BitField<int, 8, 6> {};
225 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize;
226 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1;
227 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1));
229 // Predicates for the operand policy.
230 bool HasAnyPolicy() const {
231 return basic_policy() == EXTENDED_POLICY && extended_policy() == ANY;
233 bool HasFixedPolicy() const {
234 return basic_policy() == FIXED_SLOT ||
235 extended_policy() == FIXED_REGISTER ||
236 extended_policy() == FIXED_DOUBLE_REGISTER;
238 bool HasRegisterPolicy() const {
239 return basic_policy() == EXTENDED_POLICY &&
240 extended_policy() == MUST_HAVE_REGISTER;
242 bool HasSameAsInputPolicy() const {
243 return basic_policy() == EXTENDED_POLICY &&
244 extended_policy() == SAME_AS_FIRST_INPUT;
246 bool HasFixedSlotPolicy() const { return basic_policy() == FIXED_SLOT; }
247 bool HasFixedRegisterPolicy() const {
248 return basic_policy() == EXTENDED_POLICY &&
249 extended_policy() == FIXED_REGISTER;
251 bool HasFixedDoubleRegisterPolicy() const {
252 return basic_policy() == EXTENDED_POLICY &&
253 extended_policy() == FIXED_DOUBLE_REGISTER;
256 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies.
257 BasicPolicy basic_policy() const {
258 DCHECK_EQ(UNALLOCATED, kind());
259 return BasicPolicyField::decode(value_);
262 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy.
263 ExtendedPolicy extended_policy() const {
264 DCHECK(basic_policy() == EXTENDED_POLICY);
265 return ExtendedPolicyField::decode(value_);
268 // [fixed_slot_index]: Only for FIXED_SLOT.
269 int fixed_slot_index() const {
270 DCHECK(HasFixedSlotPolicy());
271 return static_cast<int>(bit_cast<int32_t>(value_) >>
272 FixedSlotIndexField::kShift);
275 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER.
276 int fixed_register_index() const {
277 DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy());
278 return FixedRegisterField::decode(value_);
281 // [virtual_register]: The virtual register ID for this operand.
282 int32_t virtual_register() const {
283 DCHECK_EQ(UNALLOCATED, kind());
284 return virtual_register_;
287 // TODO(dcarney): remove this.
288 void set_virtual_register(int32_t id) {
289 DCHECK_EQ(UNALLOCATED, kind());
290 virtual_register_ = id;
293 // [lifetime]: Only for non-FIXED_SLOT.
294 bool IsUsedAtStart() const {
295 DCHECK(basic_policy() == EXTENDED_POLICY);
296 return LifetimeField::decode(value_) == USED_AT_START;
301 class MoveOperands FINAL {
303 MoveOperands(InstructionOperand* source, InstructionOperand* destination)
304 : source_(source), destination_(destination) {}
306 InstructionOperand* source() const { return source_; }
307 void set_source(InstructionOperand* operand) { source_ = operand; }
309 InstructionOperand* destination() const { return destination_; }
310 void set_destination(InstructionOperand* operand) { destination_ = operand; }
312 // The gap resolver marks moves as "in-progress" by clearing the
313 // destination (but not the source).
314 bool IsPending() const { return destination_ == NULL && source_ != NULL; }
316 // True if this move a move into the given destination operand.
317 bool Blocks(InstructionOperand* operand) const {
318 return !IsEliminated() && source()->Equals(operand);
321 // A move is redundant if it's been eliminated, if its source and
322 // destination are the same, or if its destination is constant.
323 bool IsRedundant() const {
324 return IsEliminated() || source_->Equals(destination_) ||
325 (destination_ != NULL && destination_->IsConstant());
328 // We clear both operands to indicate move that's been eliminated.
329 void Eliminate() { source_ = destination_ = NULL; }
330 bool IsEliminated() const {
331 DCHECK(source_ != NULL || destination_ == NULL);
332 return source_ == NULL;
336 InstructionOperand* source_;
337 InstructionOperand* destination_;
341 struct PrintableMoveOperands {
342 const RegisterConfiguration* register_configuration_;
343 const MoveOperands* move_operands_;
347 std::ostream& operator<<(std::ostream& os, const PrintableMoveOperands& mo);
350 #define INSTRUCTION_SUBKIND_OPERAND_CLASS(SubKind, kOperandKind) \
351 class SubKind##Operand FINAL : public InstructionOperand { \
353 explicit SubKind##Operand(int index) \
354 : InstructionOperand(kOperandKind, index) {} \
356 static SubKind##Operand* New(int index, Zone* zone) { \
357 return InstructionOperand::New(zone, SubKind##Operand(index)); \
360 static SubKind##Operand* cast(InstructionOperand* op) { \
361 DCHECK(op->kind() == kOperandKind); \
362 return reinterpret_cast<SubKind##Operand*>(op); \
365 static const SubKind##Operand* cast(const InstructionOperand* op) { \
366 DCHECK(op->kind() == kOperandKind); \
367 return reinterpret_cast<const SubKind##Operand*>(op); \
370 static SubKind##Operand cast(const InstructionOperand& op) { \
371 DCHECK(op.kind() == kOperandKind); \
372 return *static_cast<const SubKind##Operand*>(&op); \
375 INSTRUCTION_OPERAND_LIST(INSTRUCTION_SUBKIND_OPERAND_CLASS)
376 #undef INSTRUCTION_SUBKIND_OPERAND_CLASS
379 class ParallelMove FINAL : public ZoneObject {
381 explicit ParallelMove(Zone* zone) : move_operands_(4, zone) {}
383 void AddMove(InstructionOperand* from, InstructionOperand* to, Zone* zone) {
384 move_operands_.Add(MoveOperands(from, to), zone);
387 bool IsRedundant() const;
389 ZoneList<MoveOperands>* move_operands() { return &move_operands_; }
390 const ZoneList<MoveOperands>* move_operands() const {
391 return &move_operands_;
395 ZoneList<MoveOperands> move_operands_;
399 struct PrintableParallelMove {
400 const RegisterConfiguration* register_configuration_;
401 const ParallelMove* parallel_move_;
405 std::ostream& operator<<(std::ostream& os, const PrintableParallelMove& pm);
408 class PointerMap FINAL : public ZoneObject {
410 explicit PointerMap(Zone* zone)
411 : pointer_operands_(8, zone),
412 untagged_operands_(0, zone),
413 instruction_position_(-1) {}
415 const ZoneList<InstructionOperand*>* GetNormalizedOperands() {
416 for (int i = 0; i < untagged_operands_.length(); ++i) {
417 RemovePointer(untagged_operands_[i]);
419 untagged_operands_.Clear();
420 return &pointer_operands_;
422 int instruction_position() const { return instruction_position_; }
424 void set_instruction_position(int pos) {
425 DCHECK(instruction_position_ == -1);
426 instruction_position_ = pos;
429 void RecordPointer(InstructionOperand* op, Zone* zone);
430 void RemovePointer(InstructionOperand* op);
431 void RecordUntagged(InstructionOperand* op, Zone* zone);
434 friend std::ostream& operator<<(std::ostream& os, const PointerMap& pm);
436 ZoneList<InstructionOperand*> pointer_operands_;
437 ZoneList<InstructionOperand*> untagged_operands_;
438 int instruction_position_;
441 std::ostream& operator<<(std::ostream& os, const PointerMap& pm);
443 // TODO(titzer): s/PointerMap/ReferenceMap/
446 size_t OutputCount() const { return OutputCountField::decode(bit_field_); }
447 const InstructionOperand* OutputAt(size_t i) const {
448 DCHECK(i < OutputCount());
449 return &operands_[i];
451 InstructionOperand* OutputAt(size_t i) {
452 DCHECK(i < OutputCount());
453 return &operands_[i];
456 bool HasOutput() const { return OutputCount() == 1; }
457 const InstructionOperand* Output() const { return OutputAt(0); }
458 InstructionOperand* Output() { return OutputAt(0); }
460 size_t InputCount() const { return InputCountField::decode(bit_field_); }
461 const InstructionOperand* InputAt(size_t i) const {
462 DCHECK(i < InputCount());
463 return &operands_[OutputCount() + i];
465 InstructionOperand* InputAt(size_t i) {
466 DCHECK(i < InputCount());
467 return &operands_[OutputCount() + i];
470 size_t TempCount() const { return TempCountField::decode(bit_field_); }
471 const InstructionOperand* TempAt(size_t i) const {
472 DCHECK(i < TempCount());
473 return &operands_[OutputCount() + InputCount() + i];
475 InstructionOperand* TempAt(size_t i) {
476 DCHECK(i < TempCount());
477 return &operands_[OutputCount() + InputCount() + i];
480 InstructionCode opcode() const { return opcode_; }
481 ArchOpcode arch_opcode() const { return ArchOpcodeField::decode(opcode()); }
482 AddressingMode addressing_mode() const {
483 return AddressingModeField::decode(opcode());
485 FlagsMode flags_mode() const { return FlagsModeField::decode(opcode()); }
486 FlagsCondition flags_condition() const {
487 return FlagsConditionField::decode(opcode());
490 // TODO(titzer): make control and call into flags.
491 static Instruction* New(Zone* zone, InstructionCode opcode) {
492 return New(zone, opcode, 0, NULL, 0, NULL, 0, NULL);
495 static Instruction* New(Zone* zone, InstructionCode opcode,
496 size_t output_count, InstructionOperand* outputs,
497 size_t input_count, InstructionOperand* inputs,
498 size_t temp_count, InstructionOperand* temps) {
500 DCHECK(output_count == 0 || outputs != NULL);
501 DCHECK(input_count == 0 || inputs != NULL);
502 DCHECK(temp_count == 0 || temps != NULL);
503 size_t total_extra_ops = output_count + input_count + temp_count;
504 if (total_extra_ops != 0) total_extra_ops--;
505 int size = static_cast<int>(
506 RoundUp(sizeof(Instruction), sizeof(InstructionOperand)) +
507 total_extra_ops * sizeof(InstructionOperand));
508 return new (zone->New(size)) Instruction(
509 opcode, output_count, outputs, input_count, inputs, temp_count, temps);
512 // TODO(titzer): another holdover from lithium days; register allocator
513 // should not need to know about control instructions.
514 Instruction* MarkAsControl() {
515 bit_field_ = IsControlField::update(bit_field_, true);
518 Instruction* MarkAsCall() {
519 bit_field_ = IsCallField::update(bit_field_, true);
522 bool IsControl() const { return IsControlField::decode(bit_field_); }
523 bool IsCall() const { return IsCallField::decode(bit_field_); }
524 bool NeedsPointerMap() const { return IsCall(); }
525 bool HasPointerMap() const { return pointer_map_ != NULL; }
527 bool IsGapMoves() const { return opcode() == kGapInstruction; }
528 bool IsSourcePosition() const {
529 return opcode() == kSourcePositionInstruction;
532 bool ClobbersRegisters() const { return IsCall(); }
533 bool ClobbersTemps() const { return IsCall(); }
534 bool ClobbersDoubleRegisters() const { return IsCall(); }
535 PointerMap* pointer_map() const { return pointer_map_; }
537 void set_pointer_map(PointerMap* map) {
538 DCHECK(NeedsPointerMap());
539 DCHECK(!pointer_map_);
543 void OverwriteWithNop() {
544 opcode_ = ArchOpcodeField::encode(kArchNop);
550 return arch_opcode() == kArchNop && InputCount() == 0 &&
551 OutputCount() == 0 && TempCount() == 0;
555 explicit Instruction(InstructionCode opcode);
556 Instruction(InstructionCode opcode, size_t output_count,
557 InstructionOperand* outputs, size_t input_count,
558 InstructionOperand* inputs, size_t temp_count,
559 InstructionOperand* temps);
561 typedef BitField<size_t, 0, 8> OutputCountField;
562 typedef BitField<size_t, 8, 16> InputCountField;
563 typedef BitField<size_t, 24, 6> TempCountField;
564 typedef BitField<bool, 30, 1> IsCallField;
565 typedef BitField<bool, 31, 1> IsControlField;
567 InstructionCode opcode_;
569 PointerMap* pointer_map_;
570 InstructionOperand operands_[1];
573 DISALLOW_COPY_AND_ASSIGN(Instruction);
577 struct PrintableInstruction {
578 const RegisterConfiguration* register_configuration_;
579 const Instruction* instr_;
581 std::ostream& operator<<(std::ostream& os, const PrintableInstruction& instr);
584 // Represents moves inserted before an instruction due to register allocation.
585 // TODO(titzer): squash GapInstruction back into Instruction, since essentially
586 // every instruction can possibly have moves inserted before it.
587 class GapInstruction : public Instruction {
594 FIRST_INNER_POSITION = BEFORE,
595 LAST_INNER_POSITION = AFTER
598 ParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone) {
599 if (parallel_moves_[pos] == NULL) {
600 parallel_moves_[pos] = new (zone) ParallelMove(zone);
602 return parallel_moves_[pos];
605 ParallelMove* GetParallelMove(InnerPosition pos) {
606 return parallel_moves_[pos];
609 const ParallelMove* GetParallelMove(InnerPosition pos) const {
610 return parallel_moves_[pos];
613 bool IsRedundant() const;
615 ParallelMove** parallel_moves() { return parallel_moves_; }
617 static GapInstruction* New(Zone* zone) {
618 void* buffer = zone->New(sizeof(GapInstruction));
619 return new (buffer) GapInstruction(kGapInstruction);
622 static GapInstruction* cast(Instruction* instr) {
623 DCHECK(instr->IsGapMoves());
624 return static_cast<GapInstruction*>(instr);
627 static const GapInstruction* cast(const Instruction* instr) {
628 DCHECK(instr->IsGapMoves());
629 return static_cast<const GapInstruction*>(instr);
633 explicit GapInstruction(InstructionCode opcode) : Instruction(opcode) {
634 parallel_moves_[BEFORE] = NULL;
635 parallel_moves_[START] = NULL;
636 parallel_moves_[END] = NULL;
637 parallel_moves_[AFTER] = NULL;
641 friend std::ostream& operator<<(std::ostream& os,
642 const PrintableInstruction& instr);
643 ParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
647 class SourcePositionInstruction FINAL : public Instruction {
649 static SourcePositionInstruction* New(Zone* zone, SourcePosition position) {
650 void* buffer = zone->New(sizeof(SourcePositionInstruction));
651 return new (buffer) SourcePositionInstruction(position);
654 SourcePosition source_position() const { return source_position_; }
656 static SourcePositionInstruction* cast(Instruction* instr) {
657 DCHECK(instr->IsSourcePosition());
658 return static_cast<SourcePositionInstruction*>(instr);
661 static const SourcePositionInstruction* cast(const Instruction* instr) {
662 DCHECK(instr->IsSourcePosition());
663 return static_cast<const SourcePositionInstruction*>(instr);
667 explicit SourcePositionInstruction(SourcePosition source_position)
668 : Instruction(kSourcePositionInstruction),
669 source_position_(source_position) {
670 DCHECK(!source_position_.IsInvalid());
671 DCHECK(!source_position_.IsUnknown());
674 SourcePosition source_position_;
678 class Constant FINAL {
690 explicit Constant(int32_t v) : type_(kInt32), value_(v) {}
691 explicit Constant(int64_t v) : type_(kInt64), value_(v) {}
692 explicit Constant(float v) : type_(kFloat32), value_(bit_cast<int32_t>(v)) {}
693 explicit Constant(double v) : type_(kFloat64), value_(bit_cast<int64_t>(v)) {}
694 explicit Constant(ExternalReference ref)
695 : type_(kExternalReference), value_(bit_cast<intptr_t>(ref)) {}
696 explicit Constant(Handle<HeapObject> obj)
697 : type_(kHeapObject), value_(bit_cast<intptr_t>(obj)) {}
698 explicit Constant(BasicBlock::RpoNumber rpo)
699 : type_(kRpoNumber), value_(rpo.ToInt()) {}
701 Type type() const { return type_; }
703 int32_t ToInt32() const {
704 DCHECK(type() == kInt32 || type() == kInt64);
705 const int32_t value = static_cast<int32_t>(value_);
706 DCHECK_EQ(value_, static_cast<int64_t>(value));
710 int64_t ToInt64() const {
711 if (type() == kInt32) return ToInt32();
712 DCHECK_EQ(kInt64, type());
716 float ToFloat32() const {
717 DCHECK_EQ(kFloat32, type());
718 return bit_cast<float>(static_cast<int32_t>(value_));
721 double ToFloat64() const {
722 if (type() == kInt32) return ToInt32();
723 DCHECK_EQ(kFloat64, type());
724 return bit_cast<double>(value_);
727 ExternalReference ToExternalReference() const {
728 DCHECK_EQ(kExternalReference, type());
729 return bit_cast<ExternalReference>(static_cast<intptr_t>(value_));
732 BasicBlock::RpoNumber ToRpoNumber() const {
733 DCHECK_EQ(kRpoNumber, type());
734 return BasicBlock::RpoNumber::FromInt(static_cast<int>(value_));
737 Handle<HeapObject> ToHeapObject() const {
738 DCHECK_EQ(kHeapObject, type());
739 return bit_cast<Handle<HeapObject> >(static_cast<intptr_t>(value_));
748 class FrameStateDescriptor : public ZoneObject {
750 FrameStateDescriptor(Zone* zone, const FrameStateCallInfo& state_info,
751 size_t parameters_count, size_t locals_count,
753 FrameStateDescriptor* outer_state = NULL);
755 FrameStateType type() const { return type_; }
756 BailoutId bailout_id() const { return bailout_id_; }
757 OutputFrameStateCombine state_combine() const { return frame_state_combine_; }
758 size_t parameters_count() const { return parameters_count_; }
759 size_t locals_count() const { return locals_count_; }
760 size_t stack_count() const { return stack_count_; }
761 FrameStateDescriptor* outer_state() const { return outer_state_; }
762 MaybeHandle<JSFunction> jsfunction() const { return jsfunction_; }
763 bool HasContext() const { return type_ == JS_FRAME; }
765 size_t GetSize(OutputFrameStateCombine combine =
766 OutputFrameStateCombine::Ignore()) const;
767 size_t GetTotalSize() const;
768 size_t GetFrameCount() const;
769 size_t GetJSFrameCount() const;
771 MachineType GetType(size_t index) const;
772 void SetType(size_t index, MachineType type);
775 FrameStateType type_;
776 BailoutId bailout_id_;
777 OutputFrameStateCombine frame_state_combine_;
778 size_t parameters_count_;
779 size_t locals_count_;
781 ZoneVector<MachineType> types_;
782 FrameStateDescriptor* outer_state_;
783 MaybeHandle<JSFunction> jsfunction_;
786 std::ostream& operator<<(std::ostream& os, const Constant& constant);
789 class PhiInstruction FINAL : public ZoneObject {
791 typedef ZoneVector<InstructionOperand> Inputs;
793 PhiInstruction(Zone* zone, int virtual_register, size_t input_count);
795 void SetInput(size_t offset, int virtual_register);
797 int virtual_register() const { return virtual_register_; }
798 const IntVector& operands() const { return operands_; }
800 const InstructionOperand& output() const { return output_; }
801 InstructionOperand& output() { return output_; }
802 const Inputs& inputs() const { return inputs_; }
803 Inputs& inputs() { return inputs_; }
806 // TODO(dcarney): some of these fields are only for verification, move them to
808 const int virtual_register_;
809 InstructionOperand output_;
815 // Analogue of BasicBlock for Instructions instead of Nodes.
816 class InstructionBlock FINAL : public ZoneObject {
818 InstructionBlock(Zone* zone, BasicBlock::Id id,
819 BasicBlock::RpoNumber rpo_number,
820 BasicBlock::RpoNumber loop_header,
821 BasicBlock::RpoNumber loop_end, bool deferred);
823 // Instruction indexes (used by the register allocator).
824 int first_instruction_index() const {
825 DCHECK(code_start_ >= 0);
826 DCHECK(code_end_ > 0);
827 DCHECK(code_end_ >= code_start_);
830 int last_instruction_index() const {
831 DCHECK(code_start_ >= 0);
832 DCHECK(code_end_ > 0);
833 DCHECK(code_end_ >= code_start_);
834 return code_end_ - 1;
837 int32_t code_start() const { return code_start_; }
838 void set_code_start(int32_t start) { code_start_ = start; }
840 int32_t code_end() const { return code_end_; }
841 void set_code_end(int32_t end) { code_end_ = end; }
843 bool IsDeferred() const { return deferred_; }
845 BasicBlock::Id id() const { return id_; }
846 BasicBlock::RpoNumber ao_number() const { return ao_number_; }
847 BasicBlock::RpoNumber rpo_number() const { return rpo_number_; }
848 BasicBlock::RpoNumber loop_header() const { return loop_header_; }
849 BasicBlock::RpoNumber loop_end() const {
850 DCHECK(IsLoopHeader());
853 inline bool IsLoopHeader() const { return loop_end_.IsValid(); }
855 typedef ZoneVector<BasicBlock::RpoNumber> Predecessors;
856 Predecessors& predecessors() { return predecessors_; }
857 const Predecessors& predecessors() const { return predecessors_; }
858 size_t PredecessorCount() const { return predecessors_.size(); }
859 size_t PredecessorIndexOf(BasicBlock::RpoNumber rpo_number) const;
861 typedef ZoneVector<BasicBlock::RpoNumber> Successors;
862 Successors& successors() { return successors_; }
863 const Successors& successors() const { return successors_; }
864 size_t SuccessorCount() const { return successors_.size(); }
866 typedef ZoneVector<PhiInstruction*> PhiInstructions;
867 const PhiInstructions& phis() const { return phis_; }
868 void AddPhi(PhiInstruction* phi) { phis_.push_back(phi); }
870 void set_ao_number(BasicBlock::RpoNumber ao_number) {
871 ao_number_ = ao_number;
875 Successors successors_;
876 Predecessors predecessors_;
877 PhiInstructions phis_;
878 const BasicBlock::Id id_;
879 BasicBlock::RpoNumber ao_number_; // Assembly order number.
880 const BasicBlock::RpoNumber rpo_number_;
881 const BasicBlock::RpoNumber loop_header_;
882 const BasicBlock::RpoNumber loop_end_;
883 int32_t code_start_; // start index of arch-specific code.
884 int32_t code_end_; // end index of arch-specific code.
885 const bool deferred_; // Block contains deferred code.
888 typedef ZoneDeque<Constant> ConstantDeque;
889 typedef std::map<int, Constant, std::less<int>,
890 zone_allocator<std::pair<int, Constant> > > ConstantMap;
892 typedef ZoneDeque<Instruction*> InstructionDeque;
893 typedef ZoneDeque<PointerMap*> PointerMapDeque;
894 typedef ZoneVector<FrameStateDescriptor*> DeoptimizationVector;
895 typedef ZoneVector<InstructionBlock*> InstructionBlocks;
897 struct PrintableInstructionSequence;
900 // Represents architecture-specific generated code before, during, and after
901 // register allocation.
902 // TODO(titzer): s/IsDouble/IsFloat64/
903 class InstructionSequence FINAL : public ZoneObject {
905 static InstructionBlocks* InstructionBlocksFor(Zone* zone,
906 const Schedule* schedule);
907 // Puts the deferred blocks last.
908 static void ComputeAssemblyOrder(InstructionBlocks* blocks);
910 InstructionSequence(Isolate* isolate, Zone* zone,
911 InstructionBlocks* instruction_blocks);
913 int NextVirtualRegister();
914 int VirtualRegisterCount() const { return next_virtual_register_; }
916 const InstructionBlocks& instruction_blocks() const {
917 return *instruction_blocks_;
920 int InstructionBlockCount() const {
921 return static_cast<int>(instruction_blocks_->size());
924 InstructionBlock* InstructionBlockAt(BasicBlock::RpoNumber rpo_number) {
925 return instruction_blocks_->at(rpo_number.ToSize());
928 int LastLoopInstructionIndex(const InstructionBlock* block) {
929 return instruction_blocks_->at(block->loop_end().ToSize() - 1)
930 ->last_instruction_index();
933 const InstructionBlock* InstructionBlockAt(
934 BasicBlock::RpoNumber rpo_number) const {
935 return instruction_blocks_->at(rpo_number.ToSize());
938 const InstructionBlock* GetInstructionBlock(int instruction_index) const;
940 bool IsReference(int virtual_register) const;
941 bool IsDouble(int virtual_register) const;
943 void MarkAsReference(int virtual_register);
944 void MarkAsDouble(int virtual_register);
946 void AddGapMove(int index, InstructionOperand* from, InstructionOperand* to);
948 GapInstruction* GetBlockStart(BasicBlock::RpoNumber rpo) const;
950 typedef InstructionDeque::const_iterator const_iterator;
951 const_iterator begin() const { return instructions_.begin(); }
952 const_iterator end() const { return instructions_.end(); }
953 const InstructionDeque& instructions() const { return instructions_; }
955 GapInstruction* GapAt(int index) const {
956 return GapInstruction::cast(InstructionAt(index));
958 bool IsGapAt(int index) const { return InstructionAt(index)->IsGapMoves(); }
959 Instruction* InstructionAt(int index) const {
961 DCHECK(index < static_cast<int>(instructions_.size()));
962 return instructions_[index];
965 Isolate* isolate() const { return isolate_; }
966 const PointerMapDeque* pointer_maps() const { return &pointer_maps_; }
967 Zone* zone() const { return zone_; }
969 // Used by the instruction selector while adding instructions.
970 int AddInstruction(Instruction* instr);
971 void StartBlock(BasicBlock::RpoNumber rpo);
972 void EndBlock(BasicBlock::RpoNumber rpo);
974 int AddConstant(int virtual_register, Constant constant) {
975 // TODO(titzer): allow RPO numbers as constants?
976 DCHECK(constant.type() != Constant::kRpoNumber);
977 DCHECK(virtual_register >= 0 && virtual_register < next_virtual_register_);
978 DCHECK(constants_.find(virtual_register) == constants_.end());
979 constants_.insert(std::make_pair(virtual_register, constant));
980 return virtual_register;
982 Constant GetConstant(int virtual_register) const {
983 ConstantMap::const_iterator it = constants_.find(virtual_register);
984 DCHECK(it != constants_.end());
985 DCHECK_EQ(virtual_register, it->first);
989 typedef ZoneVector<Constant> Immediates;
990 Immediates& immediates() { return immediates_; }
992 int AddImmediate(Constant constant) {
993 int index = static_cast<int>(immediates_.size());
994 immediates_.push_back(constant);
997 Constant GetImmediate(int index) const {
999 DCHECK(index < static_cast<int>(immediates_.size()));
1000 return immediates_[index];
1005 static StateId FromInt(int id) { return StateId(id); }
1006 int ToInt() const { return id_; }
1009 explicit StateId(int id) : id_(id) {}
1013 StateId AddFrameStateDescriptor(FrameStateDescriptor* descriptor);
1014 FrameStateDescriptor* GetFrameStateDescriptor(StateId deoptimization_id);
1015 int GetFrameStateDescriptorCount();
1017 BasicBlock::RpoNumber InputRpo(Instruction* instr, size_t index) {
1018 InstructionOperand* operand = instr->InputAt(index);
1019 Constant constant = operand->IsImmediate() ? GetImmediate(operand->index())
1020 : GetConstant(operand->index());
1021 return constant.ToRpoNumber();
1025 friend std::ostream& operator<<(std::ostream& os,
1026 const PrintableInstructionSequence& code);
1028 typedef std::set<int, std::less<int>, ZoneIntAllocator> VirtualRegisterSet;
1032 InstructionBlocks* const instruction_blocks_;
1033 IntVector block_starts_;
1034 ConstantMap constants_;
1035 Immediates immediates_;
1036 InstructionDeque instructions_;
1037 int next_virtual_register_;
1038 PointerMapDeque pointer_maps_;
1039 VirtualRegisterSet doubles_;
1040 VirtualRegisterSet references_;
1041 DeoptimizationVector deoptimization_entries_;
1043 DISALLOW_COPY_AND_ASSIGN(InstructionSequence);
1047 struct PrintableInstructionSequence {
1048 const RegisterConfiguration* register_configuration_;
1049 const InstructionSequence* sequence_;
1053 std::ostream& operator<<(std::ostream& os,
1054 const PrintableInstructionSequence& code);
1056 } // namespace compiler
1057 } // namespace internal
1060 #endif // V8_COMPILER_INSTRUCTION_H_