blob: f83cdebede03e33e2e6badfdb0ebf147db91360e [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/compiler/common-operator.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006#include "src/compiler/graph.h"
7#include "src/compiler/instruction.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008
9namespace v8 {
10namespace internal {
11namespace compiler {
12
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013std::ostream& operator<<(std::ostream& os,
14 const PrintableInstructionOperand& printable) {
15 const InstructionOperand& op = *printable.op_;
16 const RegisterConfiguration* conf = printable.register_configuration_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017 switch (op.kind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018 case InstructionOperand::UNALLOCATED: {
19 const UnallocatedOperand* unalloc = UnallocatedOperand::cast(&op);
20 os << "v" << unalloc->virtual_register();
21 if (unalloc->basic_policy() == UnallocatedOperand::FIXED_SLOT) {
22 return os << "(=" << unalloc->fixed_slot_index() << "S)";
23 }
24 switch (unalloc->extended_policy()) {
25 case UnallocatedOperand::NONE:
26 return os;
27 case UnallocatedOperand::FIXED_REGISTER:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040028 return os << "(=" << conf->general_register_name(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029 unalloc->fixed_register_index()) << ")";
30 case UnallocatedOperand::FIXED_DOUBLE_REGISTER:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040031 return os << "(=" << conf->double_register_name(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032 unalloc->fixed_register_index()) << ")";
33 case UnallocatedOperand::MUST_HAVE_REGISTER:
34 return os << "(R)";
35 case UnallocatedOperand::SAME_AS_FIRST_INPUT:
36 return os << "(1)";
37 case UnallocatedOperand::ANY:
38 return os << "(-)";
39 }
40 }
41 case InstructionOperand::CONSTANT:
42 return os << "[constant:" << op.index() << "]";
43 case InstructionOperand::IMMEDIATE:
44 return os << "[immediate:" << op.index() << "]";
45 case InstructionOperand::STACK_SLOT:
46 return os << "[stack:" << op.index() << "]";
47 case InstructionOperand::DOUBLE_STACK_SLOT:
48 return os << "[double_stack:" << op.index() << "]";
49 case InstructionOperand::REGISTER:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040050 return os << "[" << conf->general_register_name(op.index()) << "|R]";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 case InstructionOperand::DOUBLE_REGISTER:
Emily Bernierd0a1eb72015-03-24 16:35:39 -040052 return os << "[" << conf->double_register_name(op.index()) << "|R]";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053 }
54 UNREACHABLE();
55 return os;
56}
57
58
59template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
60SubKindOperand<kOperandKind, kNumCachedOperands>*
61 SubKindOperand<kOperandKind, kNumCachedOperands>::cache = NULL;
62
63
64template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
65void SubKindOperand<kOperandKind, kNumCachedOperands>::SetUpCache() {
66 if (cache) return;
67 cache = new SubKindOperand[kNumCachedOperands];
68 for (int i = 0; i < kNumCachedOperands; i++) {
69 cache[i].ConvertTo(kOperandKind, i);
70 }
71}
72
73
74template <InstructionOperand::Kind kOperandKind, int kNumCachedOperands>
75void SubKindOperand<kOperandKind, kNumCachedOperands>::TearDownCache() {
76 delete[] cache;
77 cache = NULL;
78}
79
80
81void InstructionOperand::SetUpCaches() {
82#define INSTRUCTION_OPERAND_SETUP(name, type, number) \
83 name##Operand::SetUpCache();
84 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_SETUP)
85#undef INSTRUCTION_OPERAND_SETUP
86}
87
88
89void InstructionOperand::TearDownCaches() {
90#define INSTRUCTION_OPERAND_TEARDOWN(name, type, number) \
91 name##Operand::TearDownCache();
92 INSTRUCTION_OPERAND_LIST(INSTRUCTION_OPERAND_TEARDOWN)
93#undef INSTRUCTION_OPERAND_TEARDOWN
94}
95
96
Emily Bernierd0a1eb72015-03-24 16:35:39 -040097std::ostream& operator<<(std::ostream& os,
98 const PrintableMoveOperands& printable) {
99 const MoveOperands& mo = *printable.move_operands_;
100 PrintableInstructionOperand printable_op = {printable.register_configuration_,
101 mo.destination()};
102
103 os << printable_op;
104 if (!mo.source()->Equals(mo.destination())) {
105 printable_op.op_ = mo.source();
106 os << " = " << printable_op;
107 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000108 return os << ";";
109}
110
111
112bool ParallelMove::IsRedundant() const {
113 for (int i = 0; i < move_operands_.length(); ++i) {
114 if (!move_operands_[i].IsRedundant()) return false;
115 }
116 return true;
117}
118
119
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400120bool GapInstruction::IsRedundant() const {
121 for (int i = GapInstruction::FIRST_INNER_POSITION;
122 i <= GapInstruction::LAST_INNER_POSITION; i++) {
123 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant())
124 return false;
125 }
126 return true;
127}
128
129
130std::ostream& operator<<(std::ostream& os,
131 const PrintableParallelMove& printable) {
132 const ParallelMove& pm = *printable.parallel_move_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000133 bool first = true;
134 for (ZoneList<MoveOperands>::iterator move = pm.move_operands()->begin();
135 move != pm.move_operands()->end(); ++move) {
136 if (move->IsEliminated()) continue;
137 if (!first) os << " ";
138 first = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400139 PrintableMoveOperands pmo = {printable.register_configuration_, move};
140 os << pmo;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 }
142 return os;
143}
144
145
146void PointerMap::RecordPointer(InstructionOperand* op, Zone* zone) {
147 // Do not record arguments as pointers.
148 if (op->IsStackSlot() && op->index() < 0) return;
149 DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
150 pointer_operands_.Add(op, zone);
151}
152
153
154void PointerMap::RemovePointer(InstructionOperand* op) {
155 // Do not record arguments as pointers.
156 if (op->IsStackSlot() && op->index() < 0) return;
157 DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
158 for (int i = 0; i < pointer_operands_.length(); ++i) {
159 if (pointer_operands_[i]->Equals(op)) {
160 pointer_operands_.Remove(i);
161 --i;
162 }
163 }
164}
165
166
167void PointerMap::RecordUntagged(InstructionOperand* op, Zone* zone) {
168 // Do not record arguments as pointers.
169 if (op->IsStackSlot() && op->index() < 0) return;
170 DCHECK(!op->IsDoubleRegister() && !op->IsDoubleStackSlot());
171 untagged_operands_.Add(op, zone);
172}
173
174
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400175std::ostream& operator<<(std::ostream& os, const PointerMap& pm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176 os << "{";
177 for (ZoneList<InstructionOperand*>::iterator op =
178 pm.pointer_operands_.begin();
179 op != pm.pointer_operands_.end(); ++op) {
180 if (op != pm.pointer_operands_.begin()) os << ";";
181 os << *op;
182 }
183 return os << "}";
184}
185
186
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400187std::ostream& operator<<(std::ostream& os, const ArchOpcode& ao) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 switch (ao) {
189#define CASE(Name) \
190 case k##Name: \
191 return os << #Name;
192 ARCH_OPCODE_LIST(CASE)
193#undef CASE
194 }
195 UNREACHABLE();
196 return os;
197}
198
199
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400200std::ostream& operator<<(std::ostream& os, const AddressingMode& am) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 switch (am) {
202 case kMode_None:
203 return os;
204#define CASE(Name) \
205 case kMode_##Name: \
206 return os << #Name;
207 TARGET_ADDRESSING_MODE_LIST(CASE)
208#undef CASE
209 }
210 UNREACHABLE();
211 return os;
212}
213
214
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400215std::ostream& operator<<(std::ostream& os, const FlagsMode& fm) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216 switch (fm) {
217 case kFlags_none:
218 return os;
219 case kFlags_branch:
220 return os << "branch";
221 case kFlags_set:
222 return os << "set";
223 }
224 UNREACHABLE();
225 return os;
226}
227
228
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400229std::ostream& operator<<(std::ostream& os, const FlagsCondition& fc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000230 switch (fc) {
231 case kEqual:
232 return os << "equal";
233 case kNotEqual:
234 return os << "not equal";
235 case kSignedLessThan:
236 return os << "signed less than";
237 case kSignedGreaterThanOrEqual:
238 return os << "signed greater than or equal";
239 case kSignedLessThanOrEqual:
240 return os << "signed less than or equal";
241 case kSignedGreaterThan:
242 return os << "signed greater than";
243 case kUnsignedLessThan:
244 return os << "unsigned less than";
245 case kUnsignedGreaterThanOrEqual:
246 return os << "unsigned greater than or equal";
247 case kUnsignedLessThanOrEqual:
248 return os << "unsigned less than or equal";
249 case kUnsignedGreaterThan:
250 return os << "unsigned greater than";
251 case kUnorderedEqual:
252 return os << "unordered equal";
253 case kUnorderedNotEqual:
254 return os << "unordered not equal";
255 case kUnorderedLessThan:
256 return os << "unordered less than";
257 case kUnorderedGreaterThanOrEqual:
258 return os << "unordered greater than or equal";
259 case kUnorderedLessThanOrEqual:
260 return os << "unordered less than or equal";
261 case kUnorderedGreaterThan:
262 return os << "unordered greater than";
263 case kOverflow:
264 return os << "overflow";
265 case kNotOverflow:
266 return os << "not overflow";
267 }
268 UNREACHABLE();
269 return os;
270}
271
272
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400273std::ostream& operator<<(std::ostream& os,
274 const PrintableInstruction& printable) {
275 const Instruction& instr = *printable.instr_;
276 PrintableInstructionOperand printable_op = {printable.register_configuration_,
277 NULL};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000278 if (instr.OutputCount() > 1) os << "(";
279 for (size_t i = 0; i < instr.OutputCount(); i++) {
280 if (i > 0) os << ", ";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281 printable_op.op_ = instr.OutputAt(i);
282 os << printable_op;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000283 }
284
285 if (instr.OutputCount() > 1) os << ") = ";
286 if (instr.OutputCount() == 1) os << " = ";
287
288 if (instr.IsGapMoves()) {
289 const GapInstruction* gap = GapInstruction::cast(&instr);
290 os << (instr.IsBlockStart() ? " block-start" : "gap ");
291 for (int i = GapInstruction::FIRST_INNER_POSITION;
292 i <= GapInstruction::LAST_INNER_POSITION; i++) {
293 os << "(";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 if (gap->parallel_moves_[i] != NULL) {
295 PrintableParallelMove ppm = {printable.register_configuration_,
296 gap->parallel_moves_[i]};
297 os << ppm;
298 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000299 os << ") ";
300 }
301 } else if (instr.IsSourcePosition()) {
302 const SourcePositionInstruction* pos =
303 SourcePositionInstruction::cast(&instr);
304 os << "position (" << pos->source_position().raw() << ")";
305 } else {
306 os << ArchOpcodeField::decode(instr.opcode());
307 AddressingMode am = AddressingModeField::decode(instr.opcode());
308 if (am != kMode_None) {
309 os << " : " << AddressingModeField::decode(instr.opcode());
310 }
311 FlagsMode fm = FlagsModeField::decode(instr.opcode());
312 if (fm != kFlags_none) {
313 os << " && " << fm << " if "
314 << FlagsConditionField::decode(instr.opcode());
315 }
316 }
317 if (instr.InputCount() > 0) {
318 for (size_t i = 0; i < instr.InputCount(); i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400319 printable_op.op_ = instr.InputAt(i);
320 os << " " << printable_op;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 }
322 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400323 return os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324}
325
326
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400327std::ostream& operator<<(std::ostream& os, const Constant& constant) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000328 switch (constant.type()) {
329 case Constant::kInt32:
330 return os << constant.ToInt32();
331 case Constant::kInt64:
332 return os << constant.ToInt64() << "l";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400333 case Constant::kFloat32:
334 return os << constant.ToFloat32() << "f";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 case Constant::kFloat64:
336 return os << constant.ToFloat64();
337 case Constant::kExternalReference:
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338 return os << static_cast<const void*>(
339 constant.ToExternalReference().address());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340 case Constant::kHeapObject:
341 return os << Brief(*constant.ToHeapObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400342 case Constant::kRpoNumber:
343 return os << "RPO" << constant.ToRpoNumber().ToInt();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344 }
345 UNREACHABLE();
346 return os;
347}
348
349
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400350InstructionBlock::InstructionBlock(Zone* zone, BasicBlock::Id id,
351 BasicBlock::RpoNumber rpo_number,
352 BasicBlock::RpoNumber loop_header,
353 BasicBlock::RpoNumber loop_end,
354 bool deferred)
355 : successors_(zone),
356 predecessors_(zone),
357 phis_(zone),
358 id_(id),
359 ao_number_(rpo_number),
360 rpo_number_(rpo_number),
361 loop_header_(loop_header),
362 loop_end_(loop_end),
363 code_start_(-1),
364 code_end_(-1),
365 deferred_(deferred) {}
366
367
368size_t InstructionBlock::PredecessorIndexOf(
369 BasicBlock::RpoNumber rpo_number) const {
370 size_t j = 0;
371 for (InstructionBlock::Predecessors::const_iterator i = predecessors_.begin();
372 i != predecessors_.end(); ++i, ++j) {
373 if (*i == rpo_number) break;
374 }
375 return j;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376}
377
378
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400379static BasicBlock::RpoNumber GetRpo(BasicBlock* block) {
380 if (block == NULL) return BasicBlock::RpoNumber::Invalid();
381 return block->GetRpoNumber();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382}
383
384
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400385static BasicBlock::RpoNumber GetLoopEndRpo(const BasicBlock* block) {
386 if (!block->IsLoopHeader()) return BasicBlock::RpoNumber::Invalid();
387 return block->loop_end()->GetRpoNumber();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000388}
389
390
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400391static InstructionBlock* InstructionBlockFor(Zone* zone,
392 const BasicBlock* block) {
393 InstructionBlock* instr_block = new (zone) InstructionBlock(
394 zone, block->id(), block->GetRpoNumber(), GetRpo(block->loop_header()),
395 GetLoopEndRpo(block), block->deferred());
396 // Map successors and precessors
397 instr_block->successors().reserve(block->SuccessorCount());
398 for (auto it = block->successors_begin(); it != block->successors_end();
399 ++it) {
400 instr_block->successors().push_back((*it)->GetRpoNumber());
401 }
402 instr_block->predecessors().reserve(block->PredecessorCount());
403 for (auto it = block->predecessors_begin(); it != block->predecessors_end();
404 ++it) {
405 instr_block->predecessors().push_back((*it)->GetRpoNumber());
406 }
407 return instr_block;
408}
409
410
411InstructionBlocks* InstructionSequence::InstructionBlocksFor(
412 Zone* zone, const Schedule* schedule) {
413 InstructionBlocks* blocks = zone->NewArray<InstructionBlocks>(1);
414 new (blocks) InstructionBlocks(
415 static_cast<int>(schedule->rpo_order()->size()), NULL, zone);
416 size_t rpo_number = 0;
417 for (BasicBlockVector::const_iterator it = schedule->rpo_order()->begin();
418 it != schedule->rpo_order()->end(); ++it, ++rpo_number) {
419 DCHECK_EQ(NULL, (*blocks)[rpo_number]);
420 DCHECK((*it)->GetRpoNumber().ToSize() == rpo_number);
421 (*blocks)[rpo_number] = InstructionBlockFor(zone, *it);
422 }
423 ComputeAssemblyOrder(blocks);
424 return blocks;
425}
426
427
428void InstructionSequence::ComputeAssemblyOrder(InstructionBlocks* blocks) {
429 int ao = 0;
430 for (auto const block : *blocks) {
431 if (!block->IsDeferred()) {
432 block->set_ao_number(BasicBlock::RpoNumber::FromInt(ao++));
433 }
434 }
435 for (auto const block : *blocks) {
436 if (block->IsDeferred()) {
437 block->set_ao_number(BasicBlock::RpoNumber::FromInt(ao++));
438 }
439 }
440}
441
442
443InstructionSequence::InstructionSequence(Zone* instruction_zone,
444 InstructionBlocks* instruction_blocks)
445 : zone_(instruction_zone),
446 instruction_blocks_(instruction_blocks),
447 block_starts_(zone()),
448 constants_(ConstantMap::key_compare(),
449 ConstantMap::allocator_type(zone())),
450 immediates_(zone()),
451 instructions_(zone()),
452 next_virtual_register_(0),
453 pointer_maps_(zone()),
454 doubles_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
455 references_(std::less<int>(), VirtualRegisterSet::allocator_type(zone())),
456 deoptimization_entries_(zone()) {
457 block_starts_.reserve(instruction_blocks_->size());
458}
459
460
461BlockStartInstruction* InstructionSequence::GetBlockStart(
462 BasicBlock::RpoNumber rpo) const {
463 const InstructionBlock* block = InstructionBlockAt(rpo);
464 return BlockStartInstruction::cast(InstructionAt(block->code_start()));
465}
466
467
468void InstructionSequence::StartBlock(BasicBlock::RpoNumber rpo) {
469 DCHECK(block_starts_.size() == rpo.ToSize());
470 InstructionBlock* block = InstructionBlockAt(rpo);
471 int code_start = static_cast<int>(instructions_.size());
472 block->set_code_start(code_start);
473 block_starts_.push_back(code_start);
474 BlockStartInstruction* block_start = BlockStartInstruction::New(zone());
475 AddInstruction(block_start);
476}
477
478
479void InstructionSequence::EndBlock(BasicBlock::RpoNumber rpo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000480 int end = static_cast<int>(instructions_.size());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400481 InstructionBlock* block = InstructionBlockAt(rpo);
482 DCHECK(block->code_start() >= 0 && block->code_start() < end);
483 block->set_code_end(end);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000484}
485
486
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400487int InstructionSequence::AddInstruction(Instruction* instr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000488 // TODO(titzer): the order of these gaps is a holdover from Lithium.
489 GapInstruction* gap = GapInstruction::New(zone());
490 if (instr->IsControl()) instructions_.push_back(gap);
491 int index = static_cast<int>(instructions_.size());
492 instructions_.push_back(instr);
493 if (!instr->IsControl()) instructions_.push_back(gap);
494 if (instr->NeedsPointerMap()) {
495 DCHECK(instr->pointer_map() == NULL);
496 PointerMap* pointer_map = new (zone()) PointerMap(zone());
497 pointer_map->set_instruction_position(index);
498 instr->set_pointer_map(pointer_map);
499 pointer_maps_.push_back(pointer_map);
500 }
501 return index;
502}
503
504
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400505const InstructionBlock* InstructionSequence::GetInstructionBlock(
506 int instruction_index) const {
507 DCHECK(instruction_blocks_->size() == block_starts_.size());
508 auto begin = block_starts_.begin();
509 auto end = std::lower_bound(begin, block_starts_.end(), instruction_index,
510 std::less_equal<int>());
511 size_t index = std::distance(begin, end) - 1;
512 auto block = instruction_blocks_->at(index);
513 DCHECK(block->code_start() <= instruction_index &&
514 instruction_index < block->code_end());
515 return block;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000516}
517
518
519bool InstructionSequence::IsReference(int virtual_register) const {
520 return references_.find(virtual_register) != references_.end();
521}
522
523
524bool InstructionSequence::IsDouble(int virtual_register) const {
525 return doubles_.find(virtual_register) != doubles_.end();
526}
527
528
529void InstructionSequence::MarkAsReference(int virtual_register) {
530 references_.insert(virtual_register);
531}
532
533
534void InstructionSequence::MarkAsDouble(int virtual_register) {
535 doubles_.insert(virtual_register);
536}
537
538
539void InstructionSequence::AddGapMove(int index, InstructionOperand* from,
540 InstructionOperand* to) {
541 GapAt(index)->GetOrCreateParallelMove(GapInstruction::START, zone())->AddMove(
542 from, to, zone());
543}
544
545
546InstructionSequence::StateId InstructionSequence::AddFrameStateDescriptor(
547 FrameStateDescriptor* descriptor) {
548 int deoptimization_id = static_cast<int>(deoptimization_entries_.size());
549 deoptimization_entries_.push_back(descriptor);
550 return StateId::FromInt(deoptimization_id);
551}
552
553FrameStateDescriptor* InstructionSequence::GetFrameStateDescriptor(
554 InstructionSequence::StateId state_id) {
555 return deoptimization_entries_[state_id.ToInt()];
556}
557
558
559int InstructionSequence::GetFrameStateDescriptorCount() {
560 return static_cast<int>(deoptimization_entries_.size());
561}
562
563
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400564FrameStateDescriptor::FrameStateDescriptor(
565 Zone* zone, const FrameStateCallInfo& state_info, size_t parameters_count,
566 size_t locals_count, size_t stack_count, FrameStateDescriptor* outer_state)
567 : type_(state_info.type()),
568 bailout_id_(state_info.bailout_id()),
569 frame_state_combine_(state_info.state_combine()),
570 parameters_count_(parameters_count),
571 locals_count_(locals_count),
572 stack_count_(stack_count),
573 types_(zone),
574 outer_state_(outer_state),
575 jsfunction_(state_info.jsfunction()) {
576 types_.resize(GetSize(), kMachNone);
577}
578
579size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const {
580 size_t size = parameters_count() + locals_count() + stack_count() +
581 (HasContext() ? 1 : 0);
582 switch (combine.kind()) {
583 case OutputFrameStateCombine::kPushOutput:
584 size += combine.GetPushCount();
585 break;
586 case OutputFrameStateCombine::kPokeAt:
587 break;
588 }
589 return size;
590}
591
592
593size_t FrameStateDescriptor::GetTotalSize() const {
594 size_t total_size = 0;
595 for (const FrameStateDescriptor* iter = this; iter != NULL;
596 iter = iter->outer_state_) {
597 total_size += iter->GetSize();
598 }
599 return total_size;
600}
601
602
603size_t FrameStateDescriptor::GetFrameCount() const {
604 size_t count = 0;
605 for (const FrameStateDescriptor* iter = this; iter != NULL;
606 iter = iter->outer_state_) {
607 ++count;
608 }
609 return count;
610}
611
612
613size_t FrameStateDescriptor::GetJSFrameCount() const {
614 size_t count = 0;
615 for (const FrameStateDescriptor* iter = this; iter != NULL;
616 iter = iter->outer_state_) {
617 if (iter->type_ == JS_FRAME) {
618 ++count;
619 }
620 }
621 return count;
622}
623
624
625MachineType FrameStateDescriptor::GetType(size_t index) const {
626 return types_[index];
627}
628
629
630void FrameStateDescriptor::SetType(size_t index, MachineType type) {
631 DCHECK(index < GetSize());
632 types_[index] = type;
633}
634
635
636std::ostream& operator<<(std::ostream& os,
637 const PrintableInstructionSequence& printable) {
638 const InstructionSequence& code = *printable.sequence_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639 for (size_t i = 0; i < code.immediates_.size(); ++i) {
640 Constant constant = code.immediates_[i];
641 os << "IMM#" << i << ": " << constant << "\n";
642 }
643 int i = 0;
644 for (ConstantMap::const_iterator it = code.constants_.begin();
645 it != code.constants_.end(); ++i, ++it) {
646 os << "CST#" << i << ": v" << it->first << " = " << it->second << "\n";
647 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400648 for (int i = 0; i < code.InstructionBlockCount(); i++) {
649 BasicBlock::RpoNumber rpo = BasicBlock::RpoNumber::FromInt(i);
650 const InstructionBlock* block = code.InstructionBlockAt(rpo);
651 CHECK(block->rpo_number() == rpo);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400653 os << "RPO#" << block->rpo_number();
654 os << ": AO#" << block->ao_number();
655 os << ": B" << block->id();
656 if (block->IsDeferred()) os << " (deferred)";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000657 if (block->IsLoopHeader()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400658 os << " loop blocks: [" << block->rpo_number() << ", "
659 << block->loop_end() << ")";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000660 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400661 os << " instructions: [" << block->code_start() << ", "
662 << block->code_end() << ")\n predecessors:";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000663
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400664 for (auto pred : block->predecessors()) {
665 const InstructionBlock* pred_block = code.InstructionBlockAt(pred);
666 os << " B" << pred_block->id();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667 }
668 os << "\n";
669
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400670 for (auto phi : block->phis()) {
671 PrintableInstructionOperand printable_op = {
672 printable.register_configuration_, phi->output()};
673 os << " phi: " << printable_op << " =";
674 for (auto input : phi->inputs()) {
675 printable_op.op_ = input;
676 os << " " << printable_op;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 }
678 os << "\n";
679 }
680
681 ScopedVector<char> buf(32);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400682 PrintableInstruction printable_instr;
683 printable_instr.register_configuration_ = printable.register_configuration_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684 for (int j = block->first_instruction_index();
685 j <= block->last_instruction_index(); j++) {
686 // TODO(svenpanne) Add some basic formatting to our streams.
687 SNPrintF(buf, "%5d", j);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400688 printable_instr.instr_ = code.InstructionAt(j);
689 os << " " << buf.start() << ": " << printable_instr << "\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 }
691
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400692 for (auto succ : block->successors()) {
693 const InstructionBlock* succ_block = code.InstructionBlockAt(succ);
694 os << " B" << succ_block->id();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000695 }
696 os << "\n";
697 }
698 return os;
699}
700
701} // namespace compiler
702} // namespace internal
703} // namespace v8