| 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 |
| 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 intptr_t move_idx = 0; |
| 413 // the appropriate SSA value. | 423 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { |
| 414 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 424 PhiInstr* phi = (*phis)[phi_idx]; |
| 415 intptr_t move_idx = 0; | 425 if (phi == NULL) continue; |
| 416 for (intptr_t j = 0; j < phis->length(); j++) { | |
| 417 PhiInstr* phi = (*phis)[j]; | |
| 418 if (phi == NULL) continue; | |
| 419 | 426 |
| 420 Value* val = phi->InputAt(pred_idx); | 427 Value* val = phi->InputAt(pred_idx); |
| 421 | 428 MoveOperands move = parallel_move->moves()[move_idx]; |
| 422 MoveOperands move = parallel_move->moves()[move_idx]; | 429 if (val->IsUse()) { |
| 423 if (val->IsUse()) { | 430 const intptr_t virtual_register = |
| 424 const intptr_t use = val->AsUse()->definition()->ssa_temp_index(); | 431 val->AsUse()->definition()->ssa_temp_index(); |
| 425 Location* slot = move.src_slot(); | 432 Location* slot = move.src_slot(); |
| 426 *slot = Location::RequiresRegister(); | 433 *slot = Location::RequiresRegister(); |
| 427 GetLiveRange(use)->head()->AddUse(NULL, pos, slot); | 434 GetLiveRange(virtual_register)->head()->AddUse(NULL, pos, slot); |
| 428 } else { | 435 } else { |
| 429 ASSERT(val->IsConstant()); | 436 ASSERT(val->IsConstant()); |
| 430 move.set_src(Location::Constant(val->AsConstant()->value())); | 437 move.set_src(Location::Constant(val->AsConstant()->value())); |
| 438 } |
| 439 move_idx++; |
| 431 } | 440 } |
| 432 | 441 |
| 433 move_idx++; | 442 // Begin backward iteration with the instruction before the parallel |
| 443 // move. |
| 444 current = current->previous(); |
| 434 } | 445 } |
| 435 | |
| 436 current = current->previous(); | |
| 437 } | 446 } |
| 438 | 447 |
| 439 // Now process all instructions in reverse order. | 448 // Now process all instructions in reverse order. |
| 440 // Advance position to the start of the last instruction in the block. | 449 --pos; // 'pos' is now the start position for the current instruction. |
| 441 pos -= 1; | |
| 442 while (current != block) { | 450 while (current != block) { |
| 443 LocationSummary* locs = current->locs(); | 451 LocationSummary* locs = current->locs(); |
| 444 | 452 |
| 445 const bool output_same_as_first_input = | 453 const bool output_same_as_first_input = |
| 446 locs->out().IsUnallocated() && | 454 locs->out().IsUnallocated() && |
| 447 locs->out().policy() == Location::kSameAsFirstInput; | 455 locs->out().policy() == Location::kSameAsFirstInput; |
| 448 | 456 |
| 449 // TODO(vegorov): number of inputs should match number of input locations. | 457 // TODO(vegorov): number of inputs should match number of input locations. |
| 450 // TODO(vegorov): generic support for writable registers? | 458 // TODO(vegorov): generic support for writable registers? |
| 451 for (intptr_t j = 0; j < current->InputCount(); j++) { | 459 for (intptr_t j = 0; j < current->InputCount(); j++) { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 locs->out_slot()); | 528 locs->out_slot()); |
| 521 } | 529 } |
| 522 | 530 |
| 523 current = current->previous(); | 531 current = current->previous(); |
| 524 pos -= 2; | 532 pos -= 2; |
| 525 } | 533 } |
| 526 | 534 |
| 527 // If this block is a join we need to add destinations of phi | 535 // If this block is a join we need to add destinations of phi |
| 528 // resolution moves to phi's live range so that register allocator will | 536 // resolution moves to phi's live range so that register allocator will |
| 529 // fill them with moves. | 537 // fill them with moves. |
| 530 if (block->IsJoinEntry() && block->AsJoinEntry()->phis() != NULL) { | 538 JoinEntryInstr* join = block->AsJoinEntry(); |
| 531 ZoneGrowableArray<PhiInstr*>* phis = block->AsJoinEntry()->phis(); | 539 if (join != NULL) { |
| 540 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| 541 if (phis != NULL) { |
| 542 intptr_t move_idx = 0; |
| 543 for (intptr_t j = 0; j < phis->length(); j++) { |
| 544 PhiInstr* phi = (*phis)[j]; |
| 545 if (phi == NULL) continue; |
| 532 | 546 |
| 533 intptr_t move_idx = 0; | 547 const intptr_t virtual_register = phi->ssa_temp_index(); |
| 534 for (intptr_t j = 0; j < phis->length(); j++) { | 548 ASSERT(virtual_register != -1); |
| 535 PhiInstr* phi = (*phis)[j]; | |
| 536 if (phi == NULL) continue; | |
| 537 | 549 |
| 538 const intptr_t def = phi->ssa_temp_index(); | 550 LiveRange* range = GetLiveRange(virtual_register); |
| 539 ASSERT(def != -1); | 551 range->DefineAt(NULL, pos, NULL); |
| 552 UseInterval* interval = GetLiveRange(virtual_register)->head(); |
| 540 | 553 |
| 541 LiveRange* range = GetLiveRange(def); | 554 for (intptr_t k = 0; k < phi->InputCount(); k++) { |
| 542 range->DefineAt(NULL, pos, NULL); | 555 BlockEntryInstr* pred = block->PredecessorAt(k); |
| 543 UseInterval* interval = GetLiveRange(def)->head(); | 556 ASSERT(pred->last_instruction()->IsGoto()); |
| 557 Instruction* move_instr = pred->last_instruction()->previous(); |
| 558 ASSERT(move_instr->IsParallelMove()); |
| 544 | 559 |
| 545 for (intptr_t k = 0; k < phi->InputCount(); k++) { | 560 Location* slot = |
| 546 BlockEntryInstr* pred = block->PredecessorAt(k); | 561 move_instr->AsParallelMove()->moves()[move_idx].dest_slot(); |
| 547 ASSERT(pred->last_instruction()->IsParallelMove()); | 562 *slot = Location::RequiresRegister(); |
| 563 interval->AddUse(NULL, pos, slot); |
| 564 } |
| 548 | 565 |
| 549 Location* slot = pred->last_instruction()->AsParallelMove()-> | 566 // All phi resolution moves are connected. Phi's live range is |
| 550 moves()[move_idx].dest_slot(); | 567 // complete. |
| 551 *slot = Location::RequiresRegister(); | 568 AddToUnallocated(interval); |
| 552 interval->AddUse(NULL, pos, slot); | 569 |
| 570 move_idx++; |
| 553 } | 571 } |
| 554 | |
| 555 // All phi resolution moves are connected. Phi's live range is complete. | |
| 556 AddToUnallocated(interval); | |
| 557 | |
| 558 move_idx++; | |
| 559 } | 572 } |
| 560 } | 573 } |
| 561 } | 574 } |
| 562 } | 575 } |
| 563 | 576 |
| 564 | 577 |
| 578 // Linearize the control flow graph. The chosen order will be used by the |
| 579 // linear-scan register allocator. Number most instructions with a pair of |
| 580 // numbers representing lifetime positions. Introduce explicit parallel |
| 581 // move instructions in the predecessors of join nodes. The moves are used |
| 582 // for phi resolution. |
| 565 void FlowGraphAllocator::NumberInstructions() { | 583 void FlowGraphAllocator::NumberInstructions() { |
| 566 intptr_t pos = 0; | 584 intptr_t pos = 0; |
| 567 | 585 |
| 586 // The basic block order is reverse postorder. |
| 568 const intptr_t block_count = postorder_.length(); | 587 const intptr_t block_count = postorder_.length(); |
| 569 for (intptr_t i = block_count - 1; i >= 0; i--) { | 588 for (intptr_t i = block_count - 1; i >= 0; i--) { |
| 570 BlockEntryInstr* block = postorder_[i]; | 589 BlockEntryInstr* block = postorder_[i]; |
| 571 | |
| 572 block->set_start_pos(pos); | 590 block->set_start_pos(pos); |
| 591 block->set_lifetime_position(pos); |
| 573 pos += 2; | 592 pos += 2; |
| 574 Instruction* current = block->next(); | 593 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 575 | 594 Instruction* current = it.Current(); |
| 576 Instruction* last = block->last_instruction(); | 595 // Do not assign numbers to parallel moves or goto instructions. |
| 577 if (!last->IsParallelMove()) last = last->next(); | 596 if (!current->IsParallelMove() && !current->IsGoto()) { |
| 578 | 597 current->set_lifetime_position(pos); |
| 579 while (current != last) { | 598 pos += 2; |
| 580 current->set_lifetime_position(pos); | 599 } |
| 581 current = current->next(); | |
| 582 pos += 2; | |
| 583 } | 600 } |
| 584 block->set_end_pos(pos); | 601 block->set_end_pos(pos); |
| 585 | 602 |
| 586 // For join entry predecessors create phi resolution moves if | 603 // For join entry predecessors create phi resolution moves if |
| 587 // necessary. They will be populated by the register allocator. | 604 // necessary. They will be populated by the register allocator. |
| 588 if (block->IsJoinEntry() && (block->AsJoinEntry()->phi_count() > 0)) { | 605 JoinEntryInstr* join = block->AsJoinEntry(); |
| 589 const intptr_t phi_count = block->AsJoinEntry()->phi_count(); | 606 if ((join != NULL) && (join->phi_count() > 0)) { |
| 607 const intptr_t phi_count = join->phi_count(); |
| 590 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 608 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(); | 609 ParallelMoveInstr* move = new ParallelMoveInstr(); |
| 595 move->set_next(block); | 610 // 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++) { | 611 for (intptr_t j = 0; j < phi_count; j++) { |
| 602 move->AddMove(Location::NoLocation(), Location::NoLocation()); | 612 move->AddMove(Location::NoLocation(), Location::NoLocation()); |
| 603 } | 613 } |
| 614 |
| 615 // Insert the move between the last two instructions of the |
| 616 // predecessor block (all such blocks have at least two instructions: |
| 617 // the block entry and goto instructions.) |
| 618 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 619 Instruction* next = pred->last_instruction(); |
| 620 Instruction* previous = next->previous(); |
| 621 ASSERT(next->IsGoto()); |
| 622 ASSERT(!previous->IsParallelMove()); |
| 623 previous->set_next(move); |
| 624 move->set_previous(previous); |
| 625 move->set_next(next); |
| 626 next->set_previous(move); |
| 604 } | 627 } |
| 605 } | 628 } |
| 606 } | 629 } |
| 607 } | 630 } |
| 608 | 631 |
| 609 | 632 |
| 610 intptr_t UseInterval::Intersect(UseInterval* other) { | 633 intptr_t UseInterval::Intersect(UseInterval* other) { |
| 611 if (this->start() <= other->start()) { | 634 if (this->start() <= other->start()) { |
| 612 if (other->start() < this->end()) return other->start(); | 635 if (other->start() < this->end()) return other->start(); |
| 613 } else if (this->start() < other->end()) { | 636 } else if (this->start() < other->end()) { |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 | 950 |
| 928 if (FLAG_trace_ssa_allocator) { | 951 if (FLAG_trace_ssa_allocator) { |
| 929 OS::Print("-- ir after allocation -------------------------\n"); | 952 OS::Print("-- ir after allocation -------------------------\n"); |
| 930 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 953 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 931 printer.PrintBlocks(); | 954 printer.PrintBlocks(); |
| 932 } | 955 } |
| 933 } | 956 } |
| 934 | 957 |
| 935 | 958 |
| 936 } // namespace dart | 959 } // namespace dart |
| OLD | NEW |