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 intptr_t pos = block->end_pos() - 1; | 389 // block. |
| 390 | 390 intptr_t pos = block->end_pos() - 2; |
| 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(); |
|
Vyacheslav Egorov (Google)
2012/07/16 12:42:55
I suggest you just don't give goto a position in N
| |
| 395 if (goto_instr != NULL) { | |
| 396 --pos; // The end of the previous instruction. | |
| 397 current = current->previous(); | |
| 398 // If we have a parallel move here then the successor block must be a | |
| 399 // join with phis. The phi inputs contribute uses to the predecessor | |
| 400 // blocks (and the phi outputs are definitions in the successor block). | |
| 395 ParallelMoveInstr* parallel_move = current->AsParallelMove(); | 401 ParallelMoveInstr* parallel_move = current->AsParallelMove(); |
| 396 JoinEntryInstr* join = current->next()->AsJoinEntry(); | 402 if (parallel_move != NULL) { |
| 397 ASSERT(join != NULL); | 403 JoinEntryInstr* join = goto_instr->successor(); |
| 404 ASSERT(join != NULL); | |
| 398 | 405 |
| 399 // Find index of the current block in predecessors of join. | 406 // Search for the index of the current block in the predecessors of |
| 400 intptr_t pred_idx = -1; | 407 // the join. TODO(kmillikin): record the predecessor index in the |
| 401 for (intptr_t j = 0; j < join->PredecessorCount(); j++) { | 408 // goto when building the predecessor list to avoid this search. |
| 402 BlockEntryInstr* pred = join->PredecessorAt(j); | 409 intptr_t pred_idx = 0; |
| 403 if (pred == block) { | 410 for (; pred_idx < join->PredecessorCount(); pred_idx++) { |
| 404 pred_idx = j; | 411 if (join->PredecessorAt(pred_idx) == block) break; |
| 405 break; | |
| 406 } | 412 } |
| 407 } | 413 ASSERT(pred_idx < join->PredecessorCount()); |
| 408 ASSERT(pred_idx != -1); | |
| 409 | 414 |
| 410 // For every phi we have a reserved phi resolution move and we need | 415 // Record the corresponding phi input use for each phi. |
| 411 // to either initialize its source with constant or to register a use, so | 416 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); |
| 412 // that register allocator will populate source slot with location of | 417 for (intptr_t move_idx = 0; move_idx < phis->length(); move_idx++) { |
| 413 // the appropriate SSA value. | 418 PhiInstr* phi = (*phis)[move_idx]; |
| 414 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); | 419 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 | 420 |
| 420 Value* val = phi->InputAt(pred_idx); | 421 Value* val = phi->InputAt(pred_idx); |
| 421 | 422 MoveOperands move = parallel_move->moves()[move_idx]; |
| 422 MoveOperands move = parallel_move->moves()[move_idx]; | 423 if (val->IsUse()) { |
| 423 if (val->IsUse()) { | 424 const intptr_t virtual_register = |
| 424 const intptr_t use = val->AsUse()->definition()->ssa_temp_index(); | 425 val->AsUse()->definition()->ssa_temp_index(); |
| 425 Location* slot = move.src_slot(); | 426 Location* slot = move.src_slot(); |
| 426 *slot = Location::RequiresRegister(); | 427 *slot = Location::RequiresRegister(); |
| 427 GetLiveRange(use)->head()->AddUse(NULL, pos, slot); | 428 GetLiveRange(virtual_register)->head()->AddUse(NULL, pos, slot); |
| 428 } else { | 429 } else { |
| 429 ASSERT(val->IsConstant()); | 430 ASSERT(val->IsConstant()); |
| 430 move.set_src(Location::Constant(val->AsConstant()->value())); | 431 move.set_src(Location::Constant(val->AsConstant()->value())); |
| 432 } | |
| 431 } | 433 } |
| 432 | 434 |
| 433 move_idx++; | 435 // Skip to the instruction before the parallel move. |
| 436 pos -= 3; // The beginning of the previous instruction. | |
|
Vyacheslav Egorov (Google)
2012/07/16 12:42:55
I don't get where -3 comes from. we now have -6 in
Kevin Millikin (Google)
2012/07/16 13:47:48
I was counting both the goto and the parallel move
| |
| 437 current = current->previous(); | |
| 434 } | 438 } |
| 435 | |
| 436 current = current->previous(); | |
| 437 } | 439 } |
| 438 | 440 |
| 439 // Now process all instructions in reverse order. | 441 // Now process all instructions in reverse order. |
| 440 // Advance position to the start of the last instruction in the block. | |
| 441 pos -= 1; | |
| 442 while (current != block) { | 442 while (current != block) { |
| 443 LocationSummary* locs = current->locs(); | 443 LocationSummary* locs = current->locs(); |
| 444 | 444 |
| 445 const bool output_same_as_first_input = | 445 const bool output_same_as_first_input = |
| 446 locs->out().IsUnallocated() && | 446 locs->out().IsUnallocated() && |
| 447 locs->out().policy() == Location::kSameAsFirstInput; | 447 locs->out().policy() == Location::kSameAsFirstInput; |
| 448 | 448 |
| 449 // TODO(vegorov): number of inputs should match number of input locations. | 449 // TODO(vegorov): number of inputs should match number of input locations. |
| 450 // TODO(vegorov): generic support for writable registers? | 450 // TODO(vegorov): generic support for writable registers? |
| 451 for (intptr_t j = 0; j < current->InputCount(); j++) { | 451 for (intptr_t j = 0; j < current->InputCount(); j++) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 513 } | 513 } |
| 514 | 514 |
| 515 Definition* def = current->AsDefinition(); | 515 Definition* def = current->AsDefinition(); |
| 516 if ((def != NULL) && (def->ssa_temp_index() >= 0)) { | 516 if ((def != NULL) && (def->ssa_temp_index() >= 0)) { |
| 517 Define(output_same_as_first_input ? current : NULL, | 517 Define(output_same_as_first_input ? current : NULL, |
| 518 pos, | 518 pos, |
| 519 def->ssa_temp_index(), | 519 def->ssa_temp_index(), |
| 520 locs->out_slot()); | 520 locs->out_slot()); |
| 521 } | 521 } |
| 522 | 522 |
| 523 pos -= 2; | |
| 523 current = current->previous(); | 524 current = current->previous(); |
| 524 pos -= 2; | |
| 525 } | 525 } |
| 526 | 526 |
| 527 // If this block is a join we need to add destinations of phi | 527 // 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 | 528 // resolution moves to phi's live range so that register allocator will |
| 529 // fill them with moves. | 529 // fill them with moves. |
| 530 if (block->IsJoinEntry() && block->AsJoinEntry()->phis() != NULL) { | 530 if (block->IsJoinEntry() && block->AsJoinEntry()->phis() != NULL) { |
| 531 ZoneGrowableArray<PhiInstr*>* phis = block->AsJoinEntry()->phis(); | 531 ZoneGrowableArray<PhiInstr*>* phis = block->AsJoinEntry()->phis(); |
| 532 | 532 |
| 533 intptr_t move_idx = 0; | 533 intptr_t move_idx = 0; |
| 534 for (intptr_t j = 0; j < phis->length(); j++) { | 534 for (intptr_t j = 0; j < phis->length(); j++) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 581 current = current->next(); | 581 current = current->next(); |
| 582 pos += 2; | 582 pos += 2; |
| 583 } | 583 } |
| 584 block->set_end_pos(pos); | 584 block->set_end_pos(pos); |
| 585 | 585 |
| 586 // For join entry predecessors create phi resolution moves if | 586 // For join entry predecessors create phi resolution moves if |
| 587 // necessary. They will be populated by the register allocator. | 587 // necessary. They will be populated by the register allocator. |
| 588 if (block->IsJoinEntry() && (block->AsJoinEntry()->phi_count() > 0)) { | 588 if (block->IsJoinEntry() && (block->AsJoinEntry()->phi_count() > 0)) { |
| 589 const intptr_t phi_count = block->AsJoinEntry()->phi_count(); | 589 const intptr_t phi_count = block->AsJoinEntry()->phi_count(); |
| 590 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 | |
| 594 ParallelMoveInstr* move = new ParallelMoveInstr(); | 591 ParallelMoveInstr* move = new ParallelMoveInstr(); |
| 595 move->set_next(block); | 592 // 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++) { | 593 for (intptr_t j = 0; j < phi_count; j++) { |
| 602 move->AddMove(Location::NoLocation(), Location::NoLocation()); | 594 move->AddMove(Location::NoLocation(), Location::NoLocation()); |
| 603 } | 595 } |
| 596 | |
| 597 // Insert the move between the last two instructions of the | |
| 598 // predecessor block (all such blocks have at least two instructions: | |
| 599 // the block entry and goto instructions.) | |
| 600 BlockEntryInstr* pred = block->PredecessorAt(i); | |
| 601 Instruction* next = pred->last_instruction(); | |
| 602 Instruction* previous = next->previous(); | |
| 603 ASSERT(next->IsGoto()); | |
| 604 ASSERT(!previous->IsParallelMove()); // Why?? | |
|
Vyacheslav Egorov (Google)
2012/07/16 12:42:55
ParallelMove should be created only once. (verific
Kevin Millikin (Google)
2012/07/16 13:47:48
It seems like an indirect way to assert that. It
| |
| 605 previous->set_next(move); | |
| 606 move->set_previous(previous); | |
| 607 move->set_next(next); | |
| 608 next->set_previous(move); | |
| 604 } | 609 } |
| 605 } | 610 } |
| 606 } | 611 } |
| 607 } | 612 } |
| 608 | 613 |
| 609 | 614 |
| 610 intptr_t UseInterval::Intersect(UseInterval* other) { | 615 intptr_t UseInterval::Intersect(UseInterval* other) { |
| 611 if (this->start() <= other->start()) { | 616 if (this->start() <= other->start()) { |
| 612 if (other->start() < this->end()) return other->start(); | 617 if (other->start() < this->end()) return other->start(); |
| 613 } else if (this->start() < other->end()) { | 618 } else if (this->start() < other->end()) { |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 927 | 932 |
| 928 if (FLAG_trace_ssa_allocator) { | 933 if (FLAG_trace_ssa_allocator) { |
| 929 OS::Print("-- ir after allocation -------------------------\n"); | 934 OS::Print("-- ir after allocation -------------------------\n"); |
| 930 FlowGraphPrinter printer(Function::Handle(), block_order_, true); | 935 FlowGraphPrinter printer(Function::Handle(), block_order_, true); |
| 931 printer.PrintBlocks(); | 936 printer.PrintBlocks(); |
| 932 } | 937 } |
| 933 } | 938 } |
| 934 | 939 |
| 935 | 940 |
| 936 } // namespace dart | 941 } // namespace dart |
| OLD | NEW |