Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Side by Side Diff: runtime/vm/flow_graph_allocator.cc

Issue 10805008: Revert "Revert "Introduce Goto instructions to the flow graph."" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/flow_graph_builder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/flow_graph_builder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698