| 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 beginning of the last instruction in the | 388 // Position corresponding to the end of the last instruction in the block. |
| 389 // block. | |
| 390 intptr_t pos = block->end_pos() - 1; | 389 intptr_t pos = block->end_pos() - 1; |
| 390 |
| 391 Instruction* current = block->last_instruction(); | 391 Instruction* current = block->last_instruction(); |
| 392 | 392 |
| 393 // Goto instructions do not contribute liveness information. | 393 // If last instruction is a parallel move we need to perform phi resolution. |
| 394 GotoInstr* goto_instr = current->AsGoto(); | 394 if (current->IsParallelMove()) { |
| 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. | |
| 405 ParallelMoveInstr* parallel_move = current->AsParallelMove(); | 395 ParallelMoveInstr* parallel_move = current->AsParallelMove(); |
| 406 if (parallel_move != NULL) { | 396 JoinEntryInstr* join = current->next()->AsJoinEntry(); |
| 407 JoinEntryInstr* join = goto_instr->successor(); | 397 ASSERT(join != NULL); |
| 408 ASSERT(join != NULL); | |
| 409 | 398 |
| 410 // Search for the index of the current block in the predecessors of | 399 // Find index of the current block in predecessors of join. |
| 411 // the join. | 400 intptr_t pred_idx = -1; |
| 412 // TODO(kmillikin): record the predecessor index in the goto when | 401 for (intptr_t j = 0; j < join->PredecessorCount(); j++) { |
| 413 // building the predecessor list to avoid this search. | 402 BlockEntryInstr* pred = join->PredecessorAt(j); |
| 414 intptr_t pred_idx = 0; | 403 if (pred == block) { |
| 415 for (; pred_idx < join->PredecessorCount(); pred_idx++) { | 404 pred_idx = j; |
| 416 if (join->PredecessorAt(pred_idx) == block) break; | 405 break; |
| 417 } | 406 } |
| 418 ASSERT(pred_idx < join->PredecessorCount()); | 407 } |
| 408 ASSERT(pred_idx != -1); |
| 419 | 409 |
| 420 // Record the corresponding phi input use for each phi. | 410 // For every phi we have a reserved phi resolution move and we need |
| 421 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 411 // to either initialize its source with constant or to register a use, so |
| 422 for (intptr_t move_idx = 0; move_idx < phis->length(); move_idx++) { | 412 // that register allocator will populate source slot with location of |
| 423 PhiInstr* phi = (*phis)[move_idx]; | 413 // the appropriate SSA value. |
| 424 if (phi == NULL) continue; | 414 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| 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; |
| 425 | 419 |
| 426 Value* val = phi->InputAt(pred_idx); | 420 Value* val = phi->InputAt(pred_idx); |
| 427 MoveOperands move = parallel_move->moves()[move_idx]; | 421 |
| 428 if (val->IsUse()) { | 422 MoveOperands move = parallel_move->moves()[move_idx]; |
| 429 const intptr_t virtual_register = | 423 if (val->IsUse()) { |
| 430 val->AsUse()->definition()->ssa_temp_index(); | 424 const intptr_t use = val->AsUse()->definition()->ssa_temp_index(); |
| 431 Location* slot = move.src_slot(); | 425 Location* slot = move.src_slot(); |
| 432 *slot = Location::RequiresRegister(); | 426 *slot = Location::RequiresRegister(); |
| 433 GetLiveRange(virtual_register)->head()->AddUse(NULL, pos, slot); | 427 GetLiveRange(use)->head()->AddUse(NULL, pos, slot); |
| 434 } else { | 428 } else { |
| 435 ASSERT(val->IsConstant()); | 429 ASSERT(val->IsConstant()); |
| 436 move.set_src(Location::Constant(val->AsConstant()->value())); | 430 move.set_src(Location::Constant(val->AsConstant()->value())); |
| 437 } | |
| 438 } | 431 } |
| 439 | 432 |
| 440 // Begin backward iteration with the instruction before the parallel | 433 move_idx++; |
| 441 // move. | |
| 442 current = current->previous(); | |
| 443 } | 434 } |
| 435 |
| 436 current = current->previous(); |
| 444 } | 437 } |
| 445 | 438 |
| 446 // Now process all instructions in reverse order. | 439 // Now process all instructions in reverse order. |
| 447 --pos; // 'pos' is now the start position for the current instruction. | 440 // Advance position to the start of the last instruction in the block. |
| 441 pos -= 1; |
| 448 while (current != block) { | 442 while (current != block) { |
| 449 LocationSummary* locs = current->locs(); | 443 LocationSummary* locs = current->locs(); |
| 450 | 444 |
| 451 const bool output_same_as_first_input = | 445 const bool output_same_as_first_input = |
| 452 locs->out().IsUnallocated() && | 446 locs->out().IsUnallocated() && |
| 453 locs->out().policy() == Location::kSameAsFirstInput; | 447 locs->out().policy() == Location::kSameAsFirstInput; |
| 454 | 448 |
| 455 // TODO(vegorov): number of inputs should match number of input locations. | 449 // TODO(vegorov): number of inputs should match number of input locations. |
| 456 // TODO(vegorov): generic support for writable registers? | 450 // TODO(vegorov): generic support for writable registers? |
| 457 for (intptr_t j = 0; j < current->InputCount(); j++) { | 451 for (intptr_t j = 0; j < current->InputCount(); j++) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 561 // All phi resolution moves are connected. Phi's live range is complete. | 555 // All phi resolution moves are connected. Phi's live range is complete. |
| 562 AddToUnallocated(interval); | 556 AddToUnallocated(interval); |
| 563 | 557 |
| 564 move_idx++; | 558 move_idx++; |
| 565 } | 559 } |
| 566 } | 560 } |
| 567 } | 561 } |
| 568 } | 562 } |
| 569 | 563 |
| 570 | 564 |
| 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. | |
| 576 void FlowGraphAllocator::NumberInstructions() { | 565 void FlowGraphAllocator::NumberInstructions() { |
| 577 intptr_t pos = 0; | 566 intptr_t pos = 0; |
| 578 | 567 |
| 579 // The basic block order is reverse postorder. | |
| 580 const intptr_t block_count = postorder_.length(); | 568 const intptr_t block_count = postorder_.length(); |
| 581 for (intptr_t i = block_count - 1; i >= 0; i--) { | 569 for (intptr_t i = block_count - 1; i >= 0; i--) { |
| 582 BlockEntryInstr* block = postorder_[i]; | 570 BlockEntryInstr* block = postorder_[i]; |
| 571 |
| 583 block->set_start_pos(pos); | 572 block->set_start_pos(pos); |
| 584 block->set_lifetime_position(pos); | |
| 585 pos += 2; | 573 pos += 2; |
| 586 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { | 574 Instruction* current = block->next(); |
| 587 Instruction* current = it.Current(); | 575 |
| 588 // Do not assign numbers to parallel moves or goto instructions. | 576 Instruction* last = block->last_instruction(); |
| 589 if (!current->IsParallelMove() && !current->IsGoto()) { | 577 if (!last->IsParallelMove()) last = last->next(); |
| 590 current->set_lifetime_position(pos); | 578 |
| 591 pos += 2; | 579 while (current != last) { |
| 592 } | 580 current->set_lifetime_position(pos); |
| 581 current = current->next(); |
| 582 pos += 2; |
| 593 } | 583 } |
| 594 block->set_end_pos(pos); | 584 block->set_end_pos(pos); |
| 595 | 585 |
| 596 // For join entry predecessors create phi resolution moves if | 586 // For join entry predecessors create phi resolution moves if |
| 597 // necessary. They will be populated by the register allocator. | 587 // necessary. They will be populated by the register allocator. |
| 598 JoinEntryInstr* join = block->AsJoinEntry(); | 588 if (block->IsJoinEntry() && (block->AsJoinEntry()->phi_count() > 0)) { |
| 599 if ((join != NULL) && (join->phi_count() > 0)) { | 589 const intptr_t phi_count = block->AsJoinEntry()->phi_count(); |
| 600 const intptr_t phi_count = join->phi_count(); | |
| 601 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { | 590 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { |
| 591 BlockEntryInstr* pred = block->PredecessorAt(i); |
| 592 ASSERT(!pred->last_instruction()->IsParallelMove()); |
| 593 |
| 602 ParallelMoveInstr* move = new ParallelMoveInstr(); | 594 ParallelMoveInstr* move = new ParallelMoveInstr(); |
| 603 // Populate the ParallelMove with empty moves. | 595 move->set_next(block); |
| 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. |
| 604 for (intptr_t j = 0; j < phi_count; j++) { | 601 for (intptr_t j = 0; j < phi_count; j++) { |
| 605 move->AddMove(Location::NoLocation(), Location::NoLocation()); | 602 move->AddMove(Location::NoLocation(), Location::NoLocation()); |
| 606 } | 603 } |
| 607 | |
| 608 // Insert the move between the last two instructions of the | |
| 609 // predecessor block (all such blocks have at least two instructions: | |
| 610 // the block entry and goto instructions.) | |
| 611 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 612 Instruction* next = pred->last_instruction(); | |
| 613 Instruction* previous = next->previous(); | |
| 614 ASSERT(next->IsGoto()); | |
| 615 ASSERT(!previous->IsParallelMove()); | |
| 616 previous->set_next(move); | |
| 617 move->set_previous(previous); | |
| 618 move->set_next(next); | |
| 619 next->set_previous(move); | |
| 620 } | 604 } |
| 621 } | 605 } |
| 622 } | 606 } |
| 623 } | 607 } |
| 624 | 608 |
| 625 | 609 |
| 626 intptr_t UseInterval::Intersect(UseInterval* other) { | 610 intptr_t UseInterval::Intersect(UseInterval* other) { |
| 627 if (this->start() <= other->start()) { | 611 if (this->start() <= other->start()) { |
| 628 if (other->start() < this->end()) return other->start(); | 612 if (other->start() < this->end()) return other->start(); |
| 629 } else if (this->start() < other->end()) { | 613 } else if (this->start() < other->end()) { |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 943 | 927 |
| 944 if (FLAG_trace_ssa_allocator) { | 928 if (FLAG_trace_ssa_allocator) { |
| 945 OS::Print("-- ir after allocation -------------------------\n"); | 929 OS::Print("-- ir after allocation -------------------------\n"); |
| 946 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 930 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 947 printer.PrintBlocks(); | 931 printer.PrintBlocks(); |
| 948 } | 932 } |
| 949 } | 933 } |
| 950 | 934 |
| 951 | 935 |
| 952 } // namespace dart | 936 } // namespace dart |
| OLD | NEW |