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 #include "src/compiler/common-operator.h"
6 #include "src/compiler/generic-node-inl.h"
7 #include "src/compiler/graph.h"
8 #include "src/compiler/instruction.h"
14 std::ostream& operator<<(std::ostream& os,
15 const PrintableInstructionOperand& printable) {
16 const InstructionOperand& op = *printable.op_;
17 const RegisterConfiguration* conf = printable.register_configuration_;
19 case InstructionOperand::INVALID:
21 case InstructionOperand::UNALLOCATED: {
22 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
23 os << "v" << unalloc->virtual_register();
24 if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
25 return os << "(=" << unalloc->fixed_slot_index() << "S)";
27 switch (unalloc->extended_policy()) {
28 case UnallocatedOperand::NONE:
30 case UnallocatedOperand::FIXED_REGISTER:
31 return os << "(=" << conf->general_register_name(
32 unalloc->fixed_register_index()) << ")";
33 case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
34 return os << "(=" << conf->double_register_name(
35 unalloc->fixed_register_index()) << ")";
36 case UnallocatedOperand::MUST_HAVE_REGISTER:
38 case UnallocatedOperand::SAME_AS_FIRST_INPUT:
40 case UnallocatedOperand::ANY:
44 case InstructionOperand::CONSTANT:
45 return os << "[constant:" << op.index() << "]";
46 case InstructionOperand::IMMEDIATE:
47 return os << "[immediate:" << op.index() << "]";
48 case InstructionOperand::STACK_SLOT:
49 return os << "[stack:" << op.index() << "]";
50 case InstructionOperand::DOUBLE_STACK_SLOT:
51 return os << "[double_stack:" << op.index() << "]";
52 case InstructionOperand::REGISTER:
53 return os << "[" << conf->general_register_name(op.index()) << "|R]";
54 case InstructionOperand::DOUBLE_REGISTER:
55 return os << "[" << conf->double_register_name(op.index()) << "|R]";
62 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
63 SubKindOperand<kOperandKind, kNumCachedOperands>*
64 SubKindOperand<kOperandKind, kNumCachedOperands>::cache = NULL;
67 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
68 void SubKindOperand<kOperandKind, kNumCachedOperands>::SetUpCache() {
70 cache = new SubKindOperand[kNumCachedOperands];
71 for (int i = 0; i < kNumCachedOperands; i++) {
72 cache[i].ConvertTo(kOperandKind, i);
77 template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
78 void SubKindOperand<kOperandKind, kNumCachedOperands>::TearDownCache() {
84 void InstructionOperand::SetUpCaches() {
85 #define INSTRUCTION_OPERAND_SETUP(name, type, number) \
86 name##Operand::SetUpCache();
87 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_SETUP)
88 #undef INSTRUCTION_OPERAND_SETUP
92 void InstructionOperand::TearDownCaches() {
93 #define INSTRUCTION_OPERAND_TEARDOWN(name, type, number) \
94 name##Operand::TearDownCache();
95 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_TEARDOWN)
96 #undef INSTRUCTION_OPERAND_TEARDOWN
100 std::ostream& operator<<(std::ostream& os,
101 const PrintableMoveOperands& printable) {
102 const MoveOperands& mo = *printable.move_operands_;
103 PrintableInstructionOperand printable_op = {printable.register_configuration_,
107 if (!mo.source()->Equals(mo.destination())) {
108 printable_op.op_ = mo.source();
109 os << " = " << printable_op;
115 bool ParallelMove::IsRedundant() const {
116 for (int i = 0; i < move_operands_.length(); ++i) {
117 if (!move_operands_[i].IsRedundant()) return false;
123 std::ostream& operator<<(std::ostream& os,
124 const PrintableParallelMove& printable) {
125 const ParallelMove& pm = *printable.parallel_move_;
127 for (ZoneList<MoveOperands>::iterator move = pm.move_operands()->begin();
128 move != pm.move_operands()->end(); ++move) {
129 if (move->IsEliminated()) continue;
130 if (!first) os << " ";
132 PrintableMoveOperands pmo = {printable.register_configuration_, move};
139 void PointerMap::RecordPointer(InstructionOperand* op, Zone* zone) {
140 // Do not record arguments as pointers.
141 if (op->IsStackSlot() && op->index() < 0) return;
142 DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
143 pointer_operands_.Add(op, zone);
147 void PointerMap::RemovePointer(InstructionOperand* op) {
148 // Do not record arguments as pointers.
149 if (op->IsStackSlot() && op->index() < 0) return;
150 DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
151 for (int i = 0; i < pointer_operands_.length(); ++i) {
152 if (pointer_operands_[i]->Equals(op)) {
153 pointer_operands_.Remove(i);
160 void PointerMap::RecordUntagged(InstructionOperand* op, Zone* zone) {
161 // Do not record arguments as pointers.
162 if (op->IsStackSlot() && op->index() < 0) return;
163 DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
164 untagged_operands_.Add(op, zone);
168 std::ostream& operator<<(std::ostream& os, const PointerMap& pm) {
170 for (ZoneList<InstructionOperand*>::iterator op =
171 pm.pointer_operands_.begin();
172 op != pm.pointer_operands_.end(); ++op) {
173 if (op != pm.pointer_operands_.begin()) os << ";";
180 std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
185 ARCH_OPCODE_LIST(CASE)
193 std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
200 TARGET_ADDRESSING_MODE_LIST(CASE)
208 std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
213 return os << "branch";
222 std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
225 return os << "equal";
227 return os << "not equal";
228 case kSignedLessThan:
229 return os << "signed less than";
230 case kSignedGreaterThanOrEqual:
231 return os << "signed greater than or equal";
232 case kSignedLessThanOrEqual:
233 return os << "signed less than or equal";
234 case kSignedGreaterThan:
235 return os << "signed greater than";
236 case kUnsignedLessThan:
237 return os << "unsigned less than";
238 case kUnsignedGreaterThanOrEqual:
239 return os << "unsigned greater than or equal";
240 case kUnsignedLessThanOrEqual:
241 return os << "unsigned less than or equal";
242 case kUnsignedGreaterThan:
243 return os << "unsigned greater than";
244 case kUnorderedEqual:
245 return os << "unordered equal";
246 case kUnorderedNotEqual:
247 return os << "unordered not equal";
248 case kUnorderedLessThan:
249 return os << "unordered less than";
250 case kUnorderedGreaterThanOrEqual:
251 return os << "unordered greater than or equal";
252 case kUnorderedLessThanOrEqual:
253 return os << "unordered less than or equal";
254 case kUnorderedGreaterThan:
255 return os << "unordered greater than";
257 return os << "overflow";
259 return os << "not overflow";
266 std::ostream& operator<<(std::ostream& os,
267 const PrintableInstruction& printable) {
268 const Instruction& instr = *printable.instr_;
269 PrintableInstructionOperand printable_op = {printable.register_configuration_,
271 if (instr.OutputCount() > 1) os << "(";
272 for (size_t i = 0; i < instr.OutputCount(); i++) {
273 if (i > 0) os << ", ";
274 printable_op.op_ = instr.OutputAt(i);
278 if (instr.OutputCount() > 1) os << ") = ";
279 if (instr.OutputCount() == 1) os << " = ";
281 if (instr.IsGapMoves()) {
282 const GapInstruction* gap = GapInstruction::cast(&instr);
283 os << (instr.IsBlockStart() ? " block-start" : "gap ");
284 for (int i = GapInstruction::FIRST_INNER_POSITION;
285 i <= GapInstruction::LAST_INNER_POSITION; i++) {
287 if (gap->parallel_moves_[i] != NULL) {
288 PrintableParallelMove ppm = {printable.register_configuration_,
289 gap->parallel_moves_[i]};
294 } else if (instr.IsSourcePosition()) {
295 const SourcePositionInstruction* pos =
296 SourcePositionInstruction::cast(&instr);
297 os << "position (" << pos->source_position().raw() << ")";
299 os << ArchOpcodeField::decode(instr.opcode());
300 AddressingMode am = AddressingModeField::decode(instr.opcode());
301 if (am != kMode_None) {
302 os << " : " << AddressingModeField::decode(instr.opcode());
304 FlagsMode fm = FlagsModeField::decode(instr.opcode());
305 if (fm != kFlags_none) {
306 os << " && " << fm << " if "
307 << FlagsConditionField::decode(instr.opcode());
310 if (instr.InputCount() > 0) {
311 for (size_t i = 0; i < instr.InputCount(); i++) {
312 printable_op.op_ = instr.InputAt(i);
313 os << " " << printable_op;
320 std::ostream& operator<<(std::ostream& os, const Constant& constant) {
321 switch (constant.type()) {
322 case Constant::kInt32:
323 return os << constant.ToInt32();
324 case Constant::kInt64:
325 return os << constant.ToInt64() << "l";
326 case Constant::kFloat32:
327 return os << constant.ToFloat32() << "f";
328 case Constant::kFloat64:
329 return os << constant.ToFloat64();
330 case Constant::kExternalReference:
331 return os << static_cast<const void*>(
332 constant.ToExternalReference().address());
333 case Constant::kHeapObject:
334 return os << Brief(*constant.ToHeapObject());
341 static BasicBlock::RpoNumber GetRpo(BasicBlock* block) {
342 if (block == NULL) return BasicBlock::RpoNumber::Invalid();
343 return block->GetRpoNumber();
347 static BasicBlock::RpoNumber GetLoopEndRpo(const BasicBlock* block) {
348 if (!block->IsLoopHeader()) return BasicBlock::RpoNumber::Invalid();
349 return BasicBlock::RpoNumber::FromInt(block->loop_end());
353 InstructionBlock::InstructionBlock(Zone* zone, const BasicBlock* block)
354 : successors_(static_cast<int>(block->SuccessorCount()),
355 BasicBlock::RpoNumber::Invalid(), zone),
356 predecessors_(static_cast<int>(block->PredecessorCount()),
357 BasicBlock::RpoNumber::Invalid(), zone),
360 ao_number_(block->GetAoNumber()),
361 rpo_number_(block->GetRpoNumber()),
362 loop_header_(GetRpo(block->loop_header())),
363 loop_end_(GetLoopEndRpo(block)),
366 deferred_(block->deferred()) {
367 // Map successors and precessors
369 for (BasicBlock::Successors::const_iterator it = block->successors_begin();
370 it != block->successors_end(); ++it, ++index) {
371 successors_[index] = (*it)->GetRpoNumber();
374 for (BasicBlock::Predecessors::const_iterator
375 it = block->predecessors_begin();
376 it != block->predecessors_end(); ++it, ++index) {
377 predecessors_[index] = (*it)->GetRpoNumber();
382 size_t InstructionBlock::PredecessorIndexOf(
383 BasicBlock::RpoNumber rpo_number) const {
385 for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
386 i != predecessors_.end(); ++i, ++j) {
387 if (*i == rpo_number) break;
393 InstructionBlocks* InstructionSequence::InstructionBlocksFor(
394 Zone* zone, const Schedule* schedule) {
395 InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
396 new (blocks) InstructionBlocks(
397 static_cast<int>(schedule->rpo_order()->size()), NULL, zone);
398 size_t rpo_number = 0;
399 for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
400 it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
401 DCHECK_EQ(NULL, (*blocks)[rpo_number]);
402 DCHECK((*it)->GetRpoNumber().ToSize() == rpo_number);
403 (*blocks)[rpo_number] = new (zone) InstructionBlock(zone, *it);
409 InstructionSequence::InstructionSequence(Zone* instruction_zone,
410 InstructionBlocks* instruction_blocks)
411 : zone_(instruction_zone),
412 instruction_blocks_(instruction_blocks),
413 constants_(ConstantMap::key_compare(),
414 ConstantMap::allocator_type(zone())),
416 instructions_(zone()),
417 next_virtual_register_(0),
418 pointer_maps_(zone()),
419 doubles_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
420 references_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
421 deoptimization_entries_(zone()) {}
424 Label* InstructionSequence::GetLabel(BasicBlock::RpoNumber rpo) {
425 return GetBlockStart(rpo)->label();
429 BlockStartInstruction* InstructionSequence::GetBlockStart(
430 BasicBlock::RpoNumber rpo) {
431 InstructionBlock* block = InstructionBlockAt(rpo);
432 BlockStartInstruction* block_start =
433 BlockStartInstruction::cast(InstructionAt(block->code_start()));
434 DCHECK_EQ(rpo.ToInt(), block_start->rpo_number().ToInt());
439 void InstructionSequence::StartBlock(BasicBlock* basic_block) {
440 InstructionBlock* block = InstructionBlockAt(basic_block->GetRpoNumber());
441 block->set_code_start(static_cast<int>(instructions_.size()));
442 BlockStartInstruction* block_start =
443 BlockStartInstruction::New(zone(), basic_block);
444 AddInstruction(block_start);
448 void InstructionSequence::EndBlock(BasicBlock* basic_block) {
449 int end = static_cast<int>(instructions_.size());
450 InstructionBlock* block = InstructionBlockAt(basic_block->GetRpoNumber());
451 DCHECK(block->code_start() >= 0 && block->code_start() < end);
452 block->set_code_end(end);
456 int InstructionSequence::AddInstruction(Instruction* instr) {
457 // TODO(titzer): the order of these gaps is a holdover from Lithium.
458 GapInstruction* gap = GapInstruction::New(zone());
459 if (instr->IsControl()) instructions_.push_back(gap);
460 int index = static_cast<int>(instructions_.size());
461 instructions_.push_back(instr);
462 if (!instr->IsControl()) instructions_.push_back(gap);
463 if (instr->NeedsPointerMap()) {
464 DCHECK(instr->pointer_map() == NULL);
465 PointerMap* pointer_map = new (zone()) PointerMap(zone());
466 pointer_map->set_instruction_position(index);
467 instr->set_pointer_map(pointer_map);
468 pointer_maps_.push_back(pointer_map);
474 const InstructionBlock* InstructionSequence::GetInstructionBlock(
475 int instruction_index) const {
476 // TODO(turbofan): Optimize this.
478 DCHECK_LE(0, instruction_index);
479 Instruction* instruction = InstructionAt(instruction_index--);
480 if (instruction->IsBlockStart()) {
481 return instruction_blocks_->at(
482 BlockStartInstruction::cast(instruction)->rpo_number().ToSize());
488 bool InstructionSequence::IsReference(int virtual_register) const {
489 return references_.find(virtual_register) != references_.end();
493 bool InstructionSequence::IsDouble(int virtual_register) const {
494 return doubles_.find(virtual_register) != doubles_.end();
498 void InstructionSequence::MarkAsReference(int virtual_register) {
499 references_.insert(virtual_register);
503 void InstructionSequence::MarkAsDouble(int virtual_register) {
504 doubles_.insert(virtual_register);
508 void InstructionSequence::AddGapMove(int index, InstructionOperand* from,
509 InstructionOperand* to) {
510 GapAt(index)->GetOrCreateParallelMove(GapInstruction::START, zone())->AddMove(
515 InstructionSequence::StateId InstructionSequence::AddFrameStateDescriptor(
516 FrameStateDescriptor* descriptor) {
517 int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
518 deoptimization_entries_.push_back(descriptor);
519 return StateId::FromInt(deoptimization_id);
522 FrameStateDescriptor* InstructionSequence::GetFrameStateDescriptor(
523 InstructionSequence::StateId state_id) {
524 return deoptimization_entries_[state_id.ToInt()];
528 int InstructionSequence::GetFrameStateDescriptorCount() {
529 return static_cast<int>(deoptimization_entries_.size());
533 FrameStateDescriptor::FrameStateDescriptor(
534 Zone* zone, const FrameStateCallInfo& state_info, size_t parameters_count,
535 size_t locals_count, size_t stack_count, FrameStateDescriptor* outer_state)
536 : type_(state_info.type()),
537 bailout_id_(state_info.bailout_id()),
538 frame_state_combine_(state_info.state_combine()),
539 parameters_count_(parameters_count),
540 locals_count_(locals_count),
541 stack_count_(stack_count),
543 outer_state_(outer_state),
544 jsfunction_(state_info.jsfunction()) {
545 types_.resize(GetSize(), kMachNone);
548 size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
549 size_t size = parameters_count() + locals_count() + stack_count() +
550 (HasContext() ? 1 : 0);
551 switch (combine.kind()) {
552 case OutputFrameStateCombine::kPushOutput:
553 size += combine.GetPushCount();
555 case OutputFrameStateCombine::kPokeAt:
562 size_t FrameStateDescriptor::GetTotalSize() const {
563 size_t total_size = 0;
564 for (const FrameStateDescriptor* iter = this; iter != NULL;
565 iter = iter->outer_state_) {
566 total_size += iter->GetSize();
572 size_t FrameStateDescriptor::GetFrameCount() const {
574 for (const FrameStateDescriptor* iter = this; iter != NULL;
575 iter = iter->outer_state_) {
582 size_t FrameStateDescriptor::GetJSFrameCount() const {
584 for (const FrameStateDescriptor* iter = this; iter != NULL;
585 iter = iter->outer_state_) {
586 if (iter->type_ == JS_FRAME) {
594 MachineType FrameStateDescriptor::GetType(size_t index) const {
595 return types_[index];
599 void FrameStateDescriptor::SetType(size_t index, MachineType type) {
600 DCHECK(index < GetSize());
601 types_[index] = type;
605 std::ostream& operator<<(std::ostream& os,
606 const PrintableInstructionSequence& printable) {
607 const InstructionSequence& code = *printable.sequence_;
608 for (size_t i = 0; i < code.immediates_.size(); ++i) {
609 Constant constant = code.immediates_[i];
610 os << "IMM#" << i << ": " << constant << "\n";
613 for (ConstantMap::const_iterator it = code.constants_.begin();
614 it != code.constants_.end(); ++i, ++it) {
615 os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
617 for (int i = 0; i < code.InstructionBlockCount(); i++) {
618 BasicBlock::RpoNumber rpo = BasicBlock::RpoNumber::FromInt(i);
619 const InstructionBlock* block = code.InstructionBlockAt(rpo);
620 CHECK(block->rpo_number() == rpo);
622 os << "RPO#" << block->rpo_number();
623 os << ": AO#" << block->ao_number();
624 os << ": B" << block->id();
625 if (block->IsDeferred()) os << " (deferred)";
626 if (block->IsLoopHeader()) {
627 os << " loop blocks: [" << block->rpo_number() << ", "
628 << block->loop_end() << ")";
630 os << " instructions: [" << block->code_start() << ", "
631 << block->code_end() << ")\n predecessors:";
633 for (auto pred : block->predecessors()) {
634 const InstructionBlock* pred_block = code.InstructionBlockAt(pred);
635 os << " B" << pred_block->id();
639 for (auto phi : block->phis()) {
640 os << " phi: v" << phi->virtual_register() << " =";
641 for (auto op_vreg : phi->operands()) {
642 os << " v" << op_vreg;
647 ScopedVector<char> buf(32);
648 PrintableInstruction printable_instr;
649 printable_instr.register_configuration_ = printable.register_configuration_;
650 for (int j = block->first_instruction_index();
651 j <= block->last_instruction_index(); j++) {
652 // TODO(svenpanne) Add some basic formatting to our streams.
653 SNPrintF(buf, "%5d", j);
654 printable_instr.instr_ = code.InstructionAt(j);
655 os << " " << buf.start() << ": " << printable_instr << "\n";
658 for (auto succ : block->successors()) {
659 const InstructionBlock* succ_block = code.InstructionBlockAt(succ);
660 os << " B" << succ_block->id();
667 } // namespace compiler
668 } // namespace internal