Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_allocator.h" | 5 #include "vm/flow_graph_allocator.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/il_printer.h" | 9 #include "vm/il_printer.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 BlockEntryInstr* block = postorder_[i]; | 378 BlockEntryInstr* block = postorder_[i]; |
| 379 | 379 |
| 380 // For every SSA value that is live out of this block create an interval | 380 // For every SSA value that is live out of this block create an interval |
| 381 // that covers the hole block. It will be shortened if we encounter a | 381 // that covers the hole block. It will be shortened if we encounter a |
| 382 // definition of this value in this block. | 382 // definition of this value in this block. |
| 383 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { | 383 for (BitVector::Iterator it(live_out_[i]); !it.Done(); it.Advance()) { |
| 384 LiveRange* range = GetLiveRange(it.Current()); | 384 LiveRange* range = GetLiveRange(it.Current()); |
| 385 range->AddUseInterval(block->start_pos(), block->end_pos()); | 385 range->AddUseInterval(block->start_pos(), block->end_pos()); |
| 386 } | 386 } |
| 387 | 387 |
| 388 // Position corresponding to the end of the last instruction in the block. | 388 // Position corresponding to the beginning of the last instruction in the |
| 389 // block. | |
| 389 intptr_t pos = block->end_pos() - 1; | 390 intptr_t pos = block->end_pos() - 1; |
| 390 | |
| 391 Instruction* current = block->last_instruction(); | 391 Instruction* current = block->last_instruction(); |
| 392 | 392 |
| 393 // If last instruction is a parallel move we need to perform phi resolution. | 393 // Goto instructions do not contribute liveness information. |
| 394 if (current->IsParallelMove()) { | 394 GotoInstr* goto_instr = current->AsGoto(); |
| 395 if (goto_instr != NULL) { | |
| 396 current = current->previous(); | |
| 397 // If we have a parallel move here then the successor block must be a | |
|
srdjan
2012/07/16 16:50:45
must start with a join with phis
| |
| 398 // join with phis. The phi inputs contribute uses to each predecessor | |
| 399 // block (and the phi outputs contribute definitions in the successor | |
| 400 // block). | |
| 401 // | |
| 402 // We record those uses at the end of the instruction preceding the | |
| 403 // parallel move. This position is 'pos', because we do not assign | |
| 404 // instruction numbers to parallel moves. | |
| 395 ParallelMoveInstr* parallel_move = current->AsParallelMove(); | 405 ParallelMoveInstr* parallel_move = current->AsParallelMove(); |
| 396 JoinEntryInstr* join = current->next()->AsJoinEntry(); | 406 if (parallel_move != NULL) { |
| 397 ASSERT(join != NULL); | 407 JoinEntryInstr* join = goto_instr->successor(); |
| 408 ASSERT(join != NULL); | |
| 398 | 409 |
| 399 // Find index of the current block in predecessors of join. | 410 // Search for the index of the current block in the predecessors of |
| 400 intptr_t pred_idx = -1; | 411 // the join. |
| 401 for (intptr_t j = 0; j < join->PredecessorCount(); j++) { | 412 // TODO(kmillikin): record the predecessor index in the goto when |
| 402 BlockEntryInstr* pred = join->PredecessorAt(j); | 413 // building the predecessor list to avoid this search. |
| 403 if (pred == block) { | 414 intptr_t pred_idx = 0; |
| 404 pred_idx = j; | 415 for (; pred_idx < join->PredecessorCount(); pred_idx++) { |
| 405 break; | 416 if (join->PredecessorAt(pred_idx) == block) break; |
| 406 } | 417 } |
| 407 } | 418 ASSERT(pred_idx < join->PredecessorCount()); |
| 408 ASSERT(pred_idx != -1); | |
| 409 | 419 |
| 410 // For every phi we have a reserved phi resolution move and we need | 420 // Record the corresponding phi input use for each phi. |
| 411 // to either initialize its source with constant or to register a use, so | 421 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| 412 // that register allocator will populate source slot with location of | 422 for (intptr_t move_idx = 0; move_idx < phis->length(); move_idx++) { |
| 413 // the appropriate SSA value. | 423 PhiInstr* phi = (*phis)[move_idx]; |
| 414 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 424 if (phi == NULL) continue; |
| 415 intptr_t move_idx = 0; | |
| 416 for (intptr_t j = 0; j < phis->length(); j++) { | |
| 417 PhiInstr* phi = (*phis)[j]; | |
| 418 if (phi == NULL) continue; | |
| 419 | 425 |
| 420 Value* val = phi->InputAt(pred_idx); | 426 Value* val = phi->InputAt(pred_idx); |
| 421 | 427 MoveOperands move = parallel_move->moves()[move_idx]; |
| 422 MoveOperands move = parallel_move->moves()[move_idx]; | 428 if (val->IsUse()) { |
| 423 if (val->IsUse()) { | 429 const intptr_t virtual_register = |
| 424 const intptr_t use = val->AsUse()->definition()->ssa_temp_index(); | 430 val->AsUse()->definition()->ssa_temp_index(); |
| 425 Location* slot = move.src_slot(); | 431 Location* slot = move.src_slot(); |
| 426 *slot = Location::RequiresRegister(); | 432 *slot = Location::RequiresRegister(); |
| 427 GetLiveRange(use)->head()->AddUse(NULL, pos, slot); | 433 GetLiveRange(virtual_register)->head()->AddUse(NULL, pos, slot); |
| 428 } else { | 434 } else { |
| 429 ASSERT(val->IsConstant()); | 435 ASSERT(val->IsConstant()); |
| 430 move.set_src(Location::Constant(val->AsConstant()->value())); | 436 move.set_src(Location::Constant(val->AsConstant()->value())); |
| 437 } | |
| 431 } | 438 } |
| 432 | 439 |
| 433 move_idx++; | 440 // Begin backward iteration with the instruction before the parallel |
| 441 // move. | |
| 442 current = current->previous(); | |
|
srdjan
2012/07/16 16:50:45
According to the comment this should this be 'curr
Kevin Millikin (Google)
2012/07/18 09:47:11
Yes. It's hard to see on the codereview tool, but
| |
| 434 } | 443 } |
| 435 | |
| 436 current = current->previous(); | |
| 437 } | 444 } |
| 438 | 445 |
| 439 // Now process all instructions in reverse order. | 446 // Now process all instructions in reverse order. |
| 440 // Advance position to the start of the last instruction in the block. | 447 --pos; // 'pos' is now the start position for the current instruction. |
| 441 pos -= 1; | |
| 442 while (current != block) { | 448 while (current != block) { |
| 443 LocationSummary* locs = current->locs(); | 449 LocationSummary* locs = current->locs(); |
| 444 | 450 |
| 445 const bool output_same_as_first_input = | 451 const bool output_same_as_first_input = |
| 446 locs->out().IsUnallocated() && | 452 locs->out().IsUnallocated() && |
| 447 locs->out().policy() == Location::kSameAsFirstInput; | 453 locs->out().policy() == Location::kSameAsFirstInput; |
| 448 | 454 |
| 449 // TODO(vegorov): number of inputs should match number of input locations. | 455 // TODO(vegorov): number of inputs should match number of input locations. |
| 450 // TODO(vegorov): generic support for writable registers? | 456 // TODO(vegorov): generic support for writable registers? |
| 451 for (intptr_t j = 0; j < current->InputCount(); j++) { | 457 for (intptr_t j = 0; j < current->InputCount(); j++) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 555 // All phi resolution moves are connected. Phi's live range is complete. | 561 // All phi resolution moves are connected. Phi's live range is complete. |
| 556 AddToUnallocated(interval); | 562 AddToUnallocated(interval); |
| 557 | 563 |
| 558 move_idx++; | 564 move_idx++; |
| 559 } | 565 } |
| 560 } | 566 } |
| 561 } | 567 } |
| 562 } | 568 } |
| 563 | 569 |
| 564 | 570 |
| 571 // Linearize the control flow graph. The chosen order will be used by the | |
| 572 // linear-scan register allocator. Number most instructions with a pair of | |
| 573 // numbers representing lifetime positions. Introduce explicit parallel | |
| 574 // move instructions in the predecessors of join nodes. The moves are used | |
| 575 // for phi resolution. | |
|
Vyacheslav Egorov (Google)
2012/07/16 14:16:41
there is a comment in the header file. you can cop
| |
| 565 void FlowGraphAllocator::NumberInstructions() { | 576 void FlowGraphAllocator::NumberInstructions() { |
| 566 intptr_t pos = 0; | 577 intptr_t pos = 0; |
| 567 | 578 |
| 579 // The basic block order is reverse postorder. | |
| 568 const intptr_t block_count = postorder_.length(); | 580 const intptr_t block_count = postorder_.length(); |
| 569 for (intptr_t i = block_count - 1; i >= 0; i--) { | 581 for (intptr_t i = block_count - 1; i >= 0; i--) { |
| 570 BlockEntryInstr* block = postorder_[i]; | 582 BlockEntryInstr* block = postorder_[i]; |
| 571 | |
| 572 block->set_start_pos(pos); | 583 block->set_start_pos(pos); |
| 584 block->set_lifetime_position(pos); | |
| 573 pos += 2; | 585 pos += 2; |
| 574 Instruction* current = block->next(); | 586 // We do not assign an instruction number to the block entry. |
|
Kevin Millikin (Google)
2012/07/16 13:49:18
Ooops, this comment described the situation before
| |
| 575 | 587 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 576 Instruction* last = block->last_instruction(); | 588 Instruction* current = it.Current(); |
| 577 if (!last->IsParallelMove()) last = last->next(); | 589 // Do not assign numbers to parallel moves or goto instructions. |
| 578 | 590 if (!current->IsParallelMove() && !current->IsGoto()) { |
| 579 while (current != last) { | 591 current->set_lifetime_position(pos); |
| 580 current->set_lifetime_position(pos); | 592 pos += 2; |
| 581 current = current->next(); | 593 } |
| 582 pos += 2; | |
| 583 } | 594 } |
| 584 block->set_end_pos(pos); | 595 block->set_end_pos(pos); |
| 585 | 596 |
| 586 // For join entry predecessors create phi resolution moves if | 597 // For join entry predecessors create phi resolution moves if |
| 587 // necessary. They will be populated by the register allocator. | 598 // necessary. They will be populated by the register allocator. |
| 588 if (block->IsJoinEntry() && (block->AsJoinEntry()->phi_count() > 0)) { | 599 JoinEntryInstr* join = block->AsJoinEntry(); |
| 589 const intptr_t phi_count = block->AsJoinEntry()->phi_count(); | 600 if ((join != NULL) && (join->phi_count() > 0)) { |
| 601 const intptr_t phi_count = join->phi_count(); | |
| 590 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 602 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 591 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 592 ASSERT(!pred->last_instruction()->IsParallelMove()); | |
| 593 | |
| 594 ParallelMoveInstr* move = new ParallelMoveInstr(); | 603 ParallelMoveInstr* move = new ParallelMoveInstr(); |
| 595 move->set_next(block); | 604 // Populate the ParallelMove with empty moves. |
| 596 move->set_previous(pred->last_instruction()); | |
| 597 pred->last_instruction()->set_next(move); | |
| 598 pred->set_last_instruction(move); | |
| 599 | |
| 600 // Populate ParallelMove with empty moves. | |
| 601 for (intptr_t j = 0; j < phi_count; j++) { | 605 for (intptr_t j = 0; j < phi_count; j++) { |
| 602 move->AddMove(Location::NoLocation(), Location::NoLocation()); | 606 move->AddMove(Location::NoLocation(), Location::NoLocation()); |
| 603 } | 607 } |
| 608 | |
| 609 // Insert the move between the last two instructions of the | |
| 610 // predecessor block (all such blocks have at least two instructions: | |
| 611 // the block entry and goto instructions.) | |
| 612 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 613 Instruction* next = pred->last_instruction(); | |
| 614 Instruction* previous = next->previous(); | |
| 615 ASSERT(next->IsGoto()); | |
| 616 ASSERT(!previous->IsParallelMove()); | |
| 617 previous->set_next(move); | |
| 618 move->set_previous(previous); | |
| 619 move->set_next(next); | |
| 620 next->set_previous(move); | |
| 604 } | 621 } |
| 605 } | 622 } |
| 606 } | 623 } |
| 607 } | 624 } |
| 608 | 625 |
| 609 | 626 |
| 610 intptr_t UseInterval::Intersect(UseInterval* other) { | 627 intptr_t UseInterval::Intersect(UseInterval* other) { |
| 611 if (this->start() <= other->start()) { | 628 if (this->start() <= other->start()) { |
| 612 if (other->start() < this->end()) return other->start(); | 629 if (other->start() < this->end()) return other->start(); |
| 613 } else if (this->start() < other->end()) { | 630 } else if (this->start() < other->end()) { |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 927 | 944 |
| 928 if (FLAG_trace_ssa_allocator) { | 945 if (FLAG_trace_ssa_allocator) { |
| 929 OS::Print("-- ir after allocation -------------------------\n"); | 946 OS::Print("-- ir after allocation -------------------------\n"); |
| 930 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 947 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 931 printer.PrintBlocks(); | 948 printer.PrintBlocks(); |
| 932 } | 949 } |
| 933 } | 950 } |
| 934 | 951 |
| 935 | 952 |
| 936 } // namespace dart | 953 } // namespace dart |
| OLD | NEW |