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

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

Issue 10831070: Allow deoptimization from states with spilled values. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: address Srdjan's comments Created 8 years, 4 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 | « runtime/vm/flow_graph_allocator.h ('k') | runtime/vm/flow_graph_compiler_ia32.cc » ('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 25 matching lines...) Expand all
36 static intptr_t MinPosition(intptr_t a, intptr_t b) { 36 static intptr_t MinPosition(intptr_t a, intptr_t b) {
37 return (a < b) ? a : b; 37 return (a < b) ? a : b;
38 } 38 }
39 39
40 40
41 static bool IsParallelMovePosition(intptr_t pos) { 41 static bool IsParallelMovePosition(intptr_t pos) {
42 return (pos & 1) == 0; 42 return (pos & 1) == 0;
43 } 43 }
44 44
45 45
46 static bool IsInstructionPosition(intptr_t pos) { 46 static bool IsInstructionStartPosition(intptr_t pos) {
47 return (pos & 1) == 0;
48 }
49
50
51 static bool IsInstructionEndPosition(intptr_t pos) {
47 return (pos & 1) == 1; 52 return (pos & 1) == 1;
48 } 53 }
49 54
50 55
51 static intptr_t ToParallelMove(intptr_t pos) { 56 static intptr_t ToInstructionStart(intptr_t pos) {
52 return (pos & ~1); 57 return (pos & ~1);
53 } 58 }
54 59
60
55 FlowGraphAllocator::FlowGraphAllocator( 61 FlowGraphAllocator::FlowGraphAllocator(
56 const GrowableArray<BlockEntryInstr*>& block_order, 62 const GrowableArray<BlockEntryInstr*>& block_order,
57 FlowGraphBuilder* builder) 63 FlowGraphBuilder* builder)
58 : builder_(builder), 64 : builder_(builder),
59 block_order_(block_order), 65 block_order_(block_order),
60 postorder_(builder->postorder_block_entries()), 66 postorder_(builder->postorder_block_entries()),
61 live_out_(block_order.length()), 67 live_out_(block_order.length()),
62 kill_(block_order.length()), 68 kill_(block_order.length()),
63 live_in_(block_order.length()), 69 live_in_(block_order.length()),
64 vreg_count_(builder->current_ssa_temp_index()), 70 vreg_count_(builder->current_ssa_temp_index()),
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 322
317 323
318 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) { 324 LiveRange* FlowGraphAllocator::GetLiveRange(intptr_t vreg) {
319 if (live_ranges_[vreg] == NULL) { 325 if (live_ranges_[vreg] == NULL) {
320 live_ranges_[vreg] = new LiveRange(vreg); 326 live_ranges_[vreg] = new LiveRange(vreg);
321 } 327 }
322 return live_ranges_[vreg]; 328 return live_ranges_[vreg];
323 } 329 }
324 330
325 331
326 void FlowGraphAllocator::BlockLocation(Location loc, 332 void FlowGraphAllocator::BlockLocation(Location loc, intptr_t pos) {
327 intptr_t from,
328 intptr_t to) {
329 ASSERT(loc.IsRegister()); 333 ASSERT(loc.IsRegister());
330 const Register reg = loc.reg(); 334 const Register reg = loc.reg();
331 if (blocked_cpu_regs_[reg]) return; 335 if (blocked_cpu_regs_[reg]) return;
332 if (cpu_regs_[reg].length() == 0) { 336 if (cpu_regs_[reg].length() == 0) {
333 cpu_regs_[reg].Add(new LiveRange(kNoVirtualRegister)); 337 cpu_regs_[reg].Add(new LiveRange(kNoVirtualRegister));
334 } 338 }
335 cpu_regs_[reg][0]->AddUseInterval(from, to); 339 cpu_regs_[reg][0]->AddUseInterval(pos, pos + 2);
336 } 340 }
337 341
338 342
339 void LiveRange::Print() { 343 void LiveRange::Print() {
340 OS::Print(" live range v%d [%d, %d)\n", vreg(), Start(), End()); 344 OS::Print(" live range v%d [%d, %d)\n", vreg(), Start(), End());
341 UsePosition* use_pos = uses_; 345 UsePosition* use_pos = uses_;
342 for (UseInterval* interval = first_use_interval_; 346 for (UseInterval* interval = first_use_interval_;
343 interval != NULL; 347 interval != NULL;
344 interval = interval->next()) { 348 interval = interval->next()) {
345 OS::Print(" use interval [%d, %d)\n", 349 OS::Print(" use interval [%d, %d)\n",
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 } 442 }
439 ConvertAllUses(range); 443 ConvertAllUses(range);
440 } 444 }
441 } 445 }
442 } 446 }
443 447
444 // 448 //
445 // When describing shape of live ranges in comments below we are going to use 449 // When describing shape of live ranges in comments below we are going to use
446 // the following notation: 450 // the following notation:
447 // 451 //
448 // B block entry 452 // B block entry
449 // g goto instruction 453 // g g' start and end of goto instruction
450 // m parallel move 454 // i i' start and end of any other instruction
451 // i any other instruction 455 // j j' start and end of any other instruction
452 // 456
453 // - body of a use interval 457 // - body of a use interval
454 // [ start of a use interval 458 // [ start of a use interval
455 // ) end of a use interval 459 // ) end of a use interval
456 // * use 460 // * use
457 // 461 //
458 // For example diagram 462 // For example diagram
459 // 463 //
460 // m i 464 // i i'
461 // value --*-) 465 // value --*--)
462 // 466 //
463 // can be read as: use interval for value starts somewhere before parallel move 467 // can be read as: use interval for value starts somewhere before instruction
464 // and extends until currently processed instruction, there is a use of value 468 // and extends until currently processed instruction, there is a use of value
465 // at a position of the parallel move. 469 // at the start of the instruction.
466 // 470 //
467 471
468 Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves( 472 Instruction* FlowGraphAllocator::ConnectOutgoingPhiMoves(
469 BlockEntryInstr* block) { 473 BlockEntryInstr* block) {
470 Instruction* last = block->last_instruction(); 474 Instruction* last = block->last_instruction();
471 475
472 GotoInstr* goto_instr = last->AsGoto(); 476 GotoInstr* goto_instr = last->AsGoto();
473 if (goto_instr == NULL) return last; 477 if (goto_instr == NULL) return last;
474 478
475 // If we have a parallel move here then the successor block must be a 479 // If we have a parallel move here then the successor block must be a
476 // join with phis. The phi inputs contribute uses to each predecessor 480 // join with phis. The phi inputs contribute uses to each predecessor
477 // block (and the phi outputs contribute definitions in the successor 481 // block (and the phi outputs contribute definitions in the successor
478 // block). 482 // block).
479 ParallelMoveInstr* parallel_move = goto_instr->previous()->AsParallelMove(); 483 ParallelMoveInstr* parallel_move = goto_instr->previous()->AsParallelMove();
480 if (parallel_move == NULL) return goto_instr->previous(); 484 if (parallel_move == NULL) return goto_instr->previous();
481 485
482 // All uses are recorded at the position of parallel move preceding goto. 486 // All uses are recorded at the position of parallel move preceding goto.
483 const intptr_t pos = goto_instr->lifetime_position() - 1; 487 const intptr_t pos = goto_instr->lifetime_position();
484 ASSERT((pos >= 0) && IsParallelMovePosition(pos)); 488 ASSERT(parallel_move->lifetime_position() == pos);
485 489
486 JoinEntryInstr* join = goto_instr->successor(); 490 JoinEntryInstr* join = goto_instr->successor();
487 ASSERT(join != NULL); 491 ASSERT(join != NULL);
488 492
489 // Search for the index of the current block in the predecessors of 493 // Search for the index of the current block in the predecessors of
490 // the join. 494 // the join.
491 const intptr_t pred_idx = join->IndexOfPredecessor(block); 495 const intptr_t pred_idx = join->IndexOfPredecessor(block);
492 496
493 // Record the corresponding phi input use for each phi. 497 // Record the corresponding phi input use for each phi.
494 ZoneGrowableArray<PhiInstr*>* phis = join->phis(); 498 ZoneGrowableArray<PhiInstr*>* phis = join->phis();
495 intptr_t move_idx = 0; 499 intptr_t move_idx = 0;
496 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) { 500 for (intptr_t phi_idx = 0; phi_idx < phis->length(); phi_idx++) {
497 PhiInstr* phi = (*phis)[phi_idx]; 501 PhiInstr* phi = (*phis)[phi_idx];
498 if (phi == NULL) continue; 502 if (phi == NULL) continue;
499 503
500 Value* val = phi->InputAt(pred_idx); 504 Value* val = phi->InputAt(pred_idx);
501 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx); 505 MoveOperands* move = parallel_move->MoveOperandsAt(move_idx);
502 if (val->IsUse()) { 506 if (val->IsUse()) {
503 // Expected shape of live ranges: 507 // Expected shape of live ranges:
504 // 508 //
505 // m g 509 // g g'
506 // value --* 510 // value --*
507 // 511 //
508 512
509 LiveRange* range = GetLiveRange( 513 LiveRange* range = GetLiveRange(
510 val->AsUse()->definition()->ssa_temp_index()); 514 val->AsUse()->definition()->ssa_temp_index());
511 515
512 range->AddUseInterval(block->start_pos(), pos); 516 range->AddUseInterval(block->start_pos(), pos);
513 range->AddUse(pos, move->src_slot()); 517 range->AddUse(pos, move->src_slot());
514 518
515 move->set_src(Location::PrefersRegister()); 519 move->set_src(Location::PrefersRegister());
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 } 578 }
575 } 579 }
576 } 580 }
577 581
578 582
579 // Create and update live ranges corresponding to instruction's inputs, 583 // Create and update live ranges corresponding to instruction's inputs,
580 // temporaries and output. 584 // temporaries and output.
581 void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block, 585 void FlowGraphAllocator::ProcessOneInstruction(BlockEntryInstr* block,
582 Instruction* current) { 586 Instruction* current) {
583 const intptr_t pos = current->lifetime_position(); 587 const intptr_t pos = current->lifetime_position();
584 ASSERT(IsInstructionPosition(pos)); 588 ASSERT(IsInstructionStartPosition(pos));
585 589
586 LocationSummary* locs = current->locs(); 590 LocationSummary* locs = current->locs();
587 591
588 // TODO(vegorov): number of inputs must match number of input locations. 592 // TODO(vegorov): number of inputs must match number of input locations.
589 if (locs->input_count() != current->InputCount()) { 593 if (locs->input_count() != current->InputCount()) {
590 builder_->Bailout("ssa allocator: number of input locations mismatch"); 594 builder_->Bailout("ssa allocator: number of input locations mismatch");
591 } 595 }
592 596
593 // Normalize same-as-first-input output if input is specified as 597 // Normalize same-as-first-input output if input is specified as
594 // fixed register. 598 // fixed register.
595 if (locs->out().IsUnallocated() && 599 if (locs->out().IsUnallocated() &&
596 (locs->out().policy() == Location::kSameAsFirstInput) && 600 (locs->out().policy() == Location::kSameAsFirstInput) &&
597 (locs->in(0).IsRegister())) { 601 (locs->in(0).IsRegister())) {
598 locs->set_out(locs->in(0)); 602 locs->set_out(locs->in(0));
599 } 603 }
600 604
601 const bool output_same_as_first_input = 605 const bool output_same_as_first_input =
602 locs->out().IsUnallocated() && 606 locs->out().IsUnallocated() &&
603 (locs->out().policy() == Location::kSameAsFirstInput); 607 (locs->out().policy() == Location::kSameAsFirstInput);
604 608
605 // Add uses from the deoptimization environment. 609 // Add uses from the deoptimization environment.
606 if (current->env() != NULL) { 610 if (current->env() != NULL) {
607 // Any value mentioned in the deoptimization environment should survive 611 // Any value mentioned in the deoptimization environment should survive
608 // until the end of instruction but it does not need to be in the register. 612 // until the end of instruction but it does not need to be in the register.
609 // Expected shape of live range: 613 // Expected shape of live range:
610 // 614 //
611 // m i m 615 // i i'
612 // value -----*--) 616 // value -----*
613 // 617 //
614 618
615 Environment* env = current->env(); 619 Environment* env = current->env();
616 const GrowableArray<Value*>& values = env->values(); 620 const GrowableArray<Value*>& values = env->values();
617 621
618 for (intptr_t j = 0; j < values.length(); j++) { 622 for (intptr_t j = 0; j < values.length(); j++) {
619 Value* val = values[j]; 623 Value* val = values[j];
620 if (val->IsUse()) { 624 if (val->IsUse()) {
621 env->AddLocation(Location::Any()); 625 env->AddLocation(Location::Any());
622 const intptr_t vreg = val->AsUse()->definition()->ssa_temp_index(); 626 const intptr_t vreg = val->AsUse()->definition()->ssa_temp_index();
623 627
624 LiveRange* range = GetLiveRange(vreg); 628 LiveRange* range = GetLiveRange(vreg);
625 range->AddUseInterval(block->start_pos(), pos + 1); 629 range->AddUseInterval(block->start_pos(), pos + 1);
626 range->AddUse(pos, env->LocationSlotAt(j)); 630 range->AddUse(pos + 1, env->LocationSlotAt(j));
627 } else { 631 } else {
628 ASSERT(val->IsConstant()); 632 ASSERT(val->IsConstant());
629 env->AddLocation(Location::NoLocation()); 633 env->AddLocation(Location::NoLocation());
630 } 634 }
631 } 635 }
632 } 636 }
633 637
634 // Process inputs. 638 // Process inputs.
635 // Skip the first input if output is specified with kSameAsFirstInput policy, 639 // Skip the first input if output is specified with kSameAsFirstInput policy,
636 // they will be processed together at the very end. 640 // they will be processed together at the very end.
637 for (intptr_t j = output_same_as_first_input ? 1 : 0; 641 for (intptr_t j = output_same_as_first_input ? 1 : 0;
638 j < current->InputCount(); 642 j < current->InputCount();
639 j++) { 643 j++) {
640 Value* input = current->InputAt(j); 644 Value* input = current->InputAt(j);
641 ASSERT(input->IsUse()); // Can not be a constant currently. 645 ASSERT(input->IsUse()); // Can not be a constant currently.
642 const intptr_t vreg = input->AsUse()->definition()->ssa_temp_index(); 646 const intptr_t vreg = input->AsUse()->definition()->ssa_temp_index();
643 LiveRange* range = GetLiveRange(vreg); 647 LiveRange* range = GetLiveRange(vreg);
644 648
645 Location* in_ref = locs->in_slot(j); 649 Location* in_ref = locs->in_slot(j);
646 650
647 if (in_ref->IsRegister()) { 651 if (in_ref->IsRegister()) {
648 // Input is expected in a fixed register. Expected shape of 652 // Input is expected in a fixed register. Expected shape of
649 // live ranges: 653 // live ranges:
650 // 654 //
651 // m i m 655 // i i'
652 // value --* 656 // value --*
653 // register [-----) 657 // register [--)
654 // 658 //
655 MoveOperands* move = 659 MoveOperands* move =
656 AddMoveAt(pos - 1, *in_ref, Location::PrefersRegister()); 660 AddMoveAt(pos, *in_ref, Location::PrefersRegister());
657 BlockLocation(*in_ref, pos - 1, pos + 1); 661 BlockLocation(*in_ref, pos);
658 range->AddUseInterval(block->start_pos(), pos - 1); 662 range->AddUseInterval(block->start_pos(), pos);
659 range->AddUse(pos - 1, move->src_slot()); 663 range->AddUse(pos, move->src_slot());
660 } else { 664 } else {
661 // Normal unallocated input. Expected shape of 665 // Normal unallocated input. Expected shape of
662 // live ranges: 666 // live ranges:
663 // 667 //
664 // m i m 668 // i i'
665 // value -----*--) 669 // value -----*
666 // 670 //
667 ASSERT(in_ref->IsUnallocated()); 671 ASSERT(in_ref->IsUnallocated());
668 range->AddUseInterval(block->start_pos(), pos + 1); 672 range->AddUseInterval(block->start_pos(), pos + 1);
669 range->AddUse(pos, in_ref); 673 range->AddUse(pos + 1, in_ref);
670 } 674 }
671 } 675 }
672 676
673 // Process temps. 677 // Process temps.
674 for (intptr_t j = 0; j < locs->temp_count(); j++) { 678 for (intptr_t j = 0; j < locs->temp_count(); j++) {
675 // Expected shape of live range: 679 // Expected shape of live range:
676 // 680 //
677 // m i m 681 // i i'
678 // [--) 682 // [-----)
679 // 683 //
680 684
681 Location temp = locs->temp(j); 685 Location temp = locs->temp(j);
682 if (temp.IsRegister()) { 686 if (temp.IsRegister()) {
683 BlockLocation(temp, pos, pos + 1); 687 BlockLocation(temp, pos);
684 } else if (temp.IsUnallocated()) { 688 } else if (temp.IsUnallocated()) {
685 LiveRange* range = new LiveRange(kTempVirtualRegister); 689 LiveRange* range = new LiveRange(kTempVirtualRegister);
686 range->AddUseInterval(pos, pos + 1); 690 range->AddUseInterval(pos, pos + 1);
687 range->AddUse(pos, locs->temp_slot(j)); 691 range->AddUse(pos, locs->temp_slot(j));
688 AddToUnallocated(range); 692 AddToUnallocated(range);
689 } else { 693 } else {
690 UNREACHABLE(); 694 UNREACHABLE();
691 } 695 }
692 } 696 }
693 697
694 // Block all allocatable registers for calls. 698 // Block all allocatable registers for calls.
695 if (locs->is_call()) { 699 if (locs->is_call()) {
696 // Expected shape of live range: 700 // Expected shape of live range:
697 // 701 //
698 // m i m 702 // i i'
699 // [--) 703 // [-----)
700 // 704 //
701 705
702 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) { 706 for (intptr_t reg = 0; reg < kNumberOfCpuRegisters; reg++) {
703 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)), 707 BlockLocation(Location::RegisterLocation(static_cast<Register>(reg)),
704 pos, 708 pos);
705 pos + 1);
706 } 709 }
707 710
708 #ifdef DEBUG 711 #ifdef DEBUG
709 // Verify that temps, inputs and output were specified as fixed 712 // Verify that temps, inputs and output were specified as fixed
710 // locations. Every register is blocked now so attempt to 713 // locations. Every register is blocked now so attempt to
711 // allocate will not succeed. 714 // allocate will not succeed.
712 for (intptr_t j = 0; j < locs->temp_count(); j++) { 715 for (intptr_t j = 0; j < locs->temp_count(); j++) {
713 ASSERT(!locs->temp(j).IsUnallocated()); 716 ASSERT(!locs->temp(j).IsUnallocated());
714 } 717 }
715 718
(...skipping 20 matching lines...) Expand all
736 // such definitions. 739 // such definitions.
737 LiveRange* range = (def->ssa_temp_index() >= 0) ? 740 LiveRange* range = (def->ssa_temp_index() >= 0) ?
738 GetLiveRange(def->ssa_temp_index()) : 741 GetLiveRange(def->ssa_temp_index()) :
739 new LiveRange(kTempVirtualRegister); 742 new LiveRange(kTempVirtualRegister);
740 Location* out = locs->out_slot(); 743 Location* out = locs->out_slot();
741 744
742 // Process output and finalize its liverange. 745 // Process output and finalize its liverange.
743 if (out->IsRegister()) { 746 if (out->IsRegister()) {
744 // Fixed output location. Expected shape of live range: 747 // Fixed output location. Expected shape of live range:
745 // 748 //
746 // m i m 749 // i i' j j'
747 // register [--) 750 // register [-----)
748 // output [------- 751 // output [-------
749 // 752 //
750 BlockLocation(*out, pos, pos + 1); 753 BlockLocation(*out, pos);
751 754
752 if (range->vreg() == kTempVirtualRegister) return; 755 if (range->vreg() == kTempVirtualRegister) return;
753 756
754 // We need to emit move connecting fixed register with another location 757 // We need to emit move connecting fixed register with another location
755 // that will be allocated for this output's live range. 758 // that will be allocated for this output's live range.
756 // Special case: fixed output followed by a fixed input last use. 759 // Special case: fixed output followed by a fixed input last use.
757 UsePosition* use = range->first_use(); 760 UsePosition* use = range->first_use();
758 if (use->pos() == (pos + 1)) { 761 if (use->pos() == (pos + 2)) {
759 // We have a use position on the parallel move.
760 ASSERT(use->location_slot()->IsUnallocated()); 762 ASSERT(use->location_slot()->IsUnallocated());
761 *(use->location_slot()) = *out; 763 *(use->location_slot()) = *out;
762 764
763 // Remove first use. It was allocated. 765 // Remove first use. It was allocated.
764 range->set_first_use(range->first_use()->next()); 766 range->set_first_use(range->first_use()->next());
765 } 767 }
766 768
767 // Shorten live range to the point of definition, this might make the range 769 // Shorten live range to the point of definition, this might make the range
768 // empty (if the only use immediately follows). If range is not empty add 770 // empty (if the only use immediately follows). If range is not empty add
769 // move from a fixed register to an unallocated location. 771 // move from a fixed register to an unallocated location.
770 range->DefineAt(pos + 1); 772 range->DefineAt(pos + 2);
771 if (range->Start() == range->End()) return; 773 if (range->Start() == range->End()) return;
772 774
773 MoveOperands* move = AddMoveAt(pos + 1, Location::PrefersRegister(), *out); 775 MoveOperands* move = AddMoveAt(pos + 2, Location::PrefersRegister(), *out);
774 range->AddUse(pos + 1, move->dest_slot()); 776 range->AddUse(pos + 2, move->dest_slot());
775 } else if (output_same_as_first_input) { 777 } else if (output_same_as_first_input) {
776 // Output register will contain a value of the first input at instruction's 778 // Output register will contain a value of the first input at instruction's
777 // start. Expected shape of live ranges: 779 // start. Expected shape of live ranges:
778 // 780 //
779 // m i m 781 // i i'
780 // input #0 --* 782 // input #0 --*
781 // output [--*---- 783 // output [----
782 // 784 //
783 ASSERT(locs->in_slot(0)->Equals(Location::RequiresRegister())); 785 ASSERT(locs->in_slot(0)->Equals(Location::RequiresRegister()));
784 786
785 // Create move that will copy value between input and output. 787 // Create move that will copy value between input and output.
786 locs->set_out(Location::RequiresRegister()); 788 locs->set_out(Location::RequiresRegister());
787 MoveOperands* move = AddMoveAt(pos - 1, 789 MoveOperands* move = AddMoveAt(pos,
788 Location::RequiresRegister(), 790 Location::RequiresRegister(),
789 Location::PrefersRegister()); 791 Location::PrefersRegister());
790 792
791 // Add uses to the live range of the input. 793 // Add uses to the live range of the input.
792 Value* input = current->InputAt(0); 794 Value* input = current->InputAt(0);
793 ASSERT(input->IsUse()); // Can not be a constant currently. 795 ASSERT(input->IsUse()); // Can not be a constant currently.
794 LiveRange* input_range = GetLiveRange( 796 LiveRange* input_range = GetLiveRange(
795 input->AsUse()->definition()->ssa_temp_index()); 797 input->AsUse()->definition()->ssa_temp_index());
796 input_range->AddUseInterval(block->start_pos(), pos - 1); 798 input_range->AddUseInterval(block->start_pos(), pos);
797 input_range->AddUse(pos - 1, move->src_slot()); 799 input_range->AddUse(pos, move->src_slot());
798 800
799 // Shorten output live range to the point of definition and add both input 801 // Shorten output live range to the point of definition and add both input
800 // and output uses slots to be filled by allocator. 802 // and output uses slots to be filled by allocator.
801 range->DefineAt(pos - 1); 803 range->DefineAt(pos);
802 range->AddUse(pos - 1, out); 804 range->AddUse(pos, out);
803 range->AddUse(pos - 1, move->dest_slot()); 805 range->AddUse(pos, move->dest_slot());
804 range->AddUse(pos, locs->in_slot(0)); 806 range->AddUse(pos, locs->in_slot(0));
805 } else { 807 } else {
806 // Normal unallocated location that requires a register. Expected shape of 808 // Normal unallocated location that requires a register. Expected shape of
807 // live range: 809 // live range:
808 // 810 //
809 // m i m 811 // i i'
810 // output [------- 812 // output [-------
811 // 813 //
812 ASSERT(out->IsUnallocated() && 814 ASSERT(out->IsUnallocated() &&
813 (out->policy() == Location::kRequiresRegister)); 815 (out->policy() == Location::kRequiresRegister));
814 816
815 // Shorten live range to the point of definition and add use to be filled by 817 // Shorten live range to the point of definition and add use to be filled by
816 // allocator. 818 // allocator.
817 range->DefineAt(pos); 819 range->DefineAt(pos);
818 range->AddUse(pos, out); 820 range->AddUse(pos, out);
819 } 821 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
857 void FlowGraphAllocator::NumberInstructions() { 859 void FlowGraphAllocator::NumberInstructions() {
858 intptr_t pos = 0; 860 intptr_t pos = 0;
859 861
860 // The basic block order is reverse postorder. 862 // The basic block order is reverse postorder.
861 const intptr_t block_count = postorder_.length(); 863 const intptr_t block_count = postorder_.length();
862 for (intptr_t i = block_count - 1; i >= 0; i--) { 864 for (intptr_t i = block_count - 1; i >= 0; i--) {
863 BlockEntryInstr* block = postorder_[i]; 865 BlockEntryInstr* block = postorder_[i];
864 866
865 instructions_.Add(block); 867 instructions_.Add(block);
866 block->set_start_pos(pos); 868 block->set_start_pos(pos);
867 block->set_lifetime_position(pos + 1); 869 block->set_lifetime_position(pos);
868 pos += 2; 870 pos += 2;
869 871
870 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) { 872 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
871 Instruction* current = it.Current(); 873 Instruction* current = it.Current();
872 // Do not assign numbers to parallel move instructions. 874 // Do not assign numbers to parallel move instructions.
873 if (!current->IsParallelMove()) { 875 if (!current->IsParallelMove()) {
874 instructions_.Add(current); 876 instructions_.Add(current);
875 current->set_lifetime_position(pos + 1); 877 current->set_lifetime_position(pos);
876 pos += 2; 878 pos += 2;
877 } 879 }
878 } 880 }
879 block->set_end_pos(pos); 881 block->set_end_pos(pos);
880 } 882 }
881 883
882 // Create parallel moves in join predecessors. This must be done after 884 // Create parallel moves in join predecessors. This must be done after
883 // all instructions are numbered. 885 // all instructions are numbered.
884 for (intptr_t i = block_count - 1; i >= 0; i--) { 886 for (intptr_t i = block_count - 1; i >= 0; i--) {
885 BlockEntryInstr* block = postorder_[i]; 887 BlockEntryInstr* block = postorder_[i];
886 888
887 // For join entry predecessors create phi resolution moves if 889 // For join entry predecessors create phi resolution moves if
888 // necessary. They will be populated by the register allocator. 890 // necessary. They will be populated by the register allocator.
889 JoinEntryInstr* join = block->AsJoinEntry(); 891 JoinEntryInstr* join = block->AsJoinEntry();
890 if ((join != NULL) && (join->phi_count() > 0)) { 892 if ((join != NULL) && (join->phi_count() > 0)) {
891 const intptr_t phi_count = join->phi_count(); 893 const intptr_t phi_count = join->phi_count();
892 for (intptr_t i = 0; i < block->PredecessorCount(); i++) { 894 for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
893 // Insert the move between the last two instructions of the 895 // Insert the move between the last two instructions of the
894 // predecessor block (all such blocks have at least two instructions: 896 // predecessor block (all such blocks have at least two instructions:
895 // the block entry and goto instructions.) 897 // the block entry and goto instructions.)
896 Instruction* last = block->PredecessorAt(i)->last_instruction(); 898 Instruction* last = block->PredecessorAt(i)->last_instruction();
899 ASSERT(last->IsGoto());
900
897 ParallelMoveInstr* move = 901 ParallelMoveInstr* move =
898 CreateParallelMoveBefore(last, last->lifetime_position() - 1); 902 CreateParallelMoveBefore(last, last->lifetime_position());
899 903
900 // Populate the ParallelMove with empty moves. 904 // Populate the ParallelMove with empty moves.
901 for (intptr_t j = 0; j < phi_count; j++) { 905 for (intptr_t j = 0; j < phi_count; j++) {
902 move->AddMove(Location::NoLocation(), Location::NoLocation()); 906 move->AddMove(Location::NoLocation(), Location::NoLocation());
903 } 907 }
908
909 // Replace Goto instruction with the corresponding move in
910 // the array of instructions. This is done to ensure that
911 // this parallel move will be treated as a normal instruction
912 // by AddMoveAt for the purpose of live ranges connections (i.e.
913 // a separate move will be inserted by AddMoveAt)
914 // This move can't be reused by AddMoveAt to insert
915 // moves at Goto position because such range connecting moves might
916 // come into a conflict with phi connecting moves due to implicit
917 // interference: phi-value's liferange starts only at successor block
918 // but the move is actually performed at the predecessor.
919 ASSERT(instructions_[last->lifetime_position() / 2] == last);
920 instructions_[last->lifetime_position() / 2] = move;
904 } 921 }
905 } 922 }
906 } 923 }
907 } 924 }
908 925
909 926
910 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const { 927 Instruction* FlowGraphAllocator::InstructionAt(intptr_t pos) const {
911 return instructions_[pos / 2]; 928 return instructions_[pos / 2];
912 } 929 }
913 930
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1016 1033
1017 LiveRange* LiveRange::MakeTemp(intptr_t pos, Location* location_slot) { 1034 LiveRange* LiveRange::MakeTemp(intptr_t pos, Location* location_slot) {
1018 UNREACHABLE(); 1035 UNREACHABLE();
1019 return NULL; 1036 return NULL;
1020 } 1037 }
1021 1038
1022 1039
1023 LiveRange* LiveRange::SplitAt(intptr_t split_pos) { 1040 LiveRange* LiveRange::SplitAt(intptr_t split_pos) {
1024 if (Start() == split_pos) return this; 1041 if (Start() == split_pos) return this;
1025 1042
1026 // Ranges can only be connected by parallel moves.
1027 split_pos = ToParallelMove(split_pos);
1028
1029 UseInterval* interval = finger_.first_pending_use_interval(); 1043 UseInterval* interval = finger_.first_pending_use_interval();
1030 ASSERT(interval->start() < split_pos); 1044 ASSERT(interval->start() < split_pos);
1031 1045
1032 // Corner case. We need to start over to find previous interval. 1046 // Corner case. We need to start over to find previous interval.
1033 if (interval->start() == split_pos) interval = first_use_interval_; 1047 if (interval->start() == split_pos) interval = first_use_interval_;
1034 1048
1035 UseInterval* last_before_split = NULL; 1049 UseInterval* last_before_split = NULL;
1036 while (interval->end() <= split_pos) { 1050 while (interval->end() <= split_pos) {
1037 last_before_split = interval; 1051 last_before_split = interval;
1038 interval = interval->next(); 1052 interval = interval->next();
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1094 return next_sibling_; 1108 return next_sibling_;
1095 } 1109 }
1096 1110
1097 1111
1098 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range, 1112 LiveRange* FlowGraphAllocator::SplitBetween(LiveRange* range,
1099 intptr_t from, 1113 intptr_t from,
1100 intptr_t to) { 1114 intptr_t to) {
1101 // TODO(vegorov): select optimal split position based on loop structure. 1115 // TODO(vegorov): select optimal split position based on loop structure.
1102 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n", 1116 TRACE_ALLOC(("split %d [%d, %d) between [%d, %d)\n",
1103 range->vreg(), range->Start(), range->End(), from, to)); 1117 range->vreg(), range->Start(), range->End(), from, to));
1118
1119 // Prefer spliting at instruction starts if possible.
1120 if (from < ToInstructionStart(to)) {
1121 to = ToInstructionStart(to);
1122 }
1123
1104 return range->SplitAt(to); 1124 return range->SplitAt(to);
1105 } 1125 }
1106 1126
1107 1127
1108 void FlowGraphAllocator::SpillBetween(LiveRange* range, 1128 void FlowGraphAllocator::SpillBetween(LiveRange* range,
1109 intptr_t from, 1129 intptr_t from,
1110 intptr_t to) { 1130 intptr_t to) {
1111 ASSERT(from < to); 1131 ASSERT(from < to);
1112 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n", 1132 TRACE_ALLOC(("spill %d [%d, %d) between [%d, %d)\n",
1113 range->vreg(), range->Start(), range->End(), from, to)); 1133 range->vreg(), range->Start(), range->End(), from, to));
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
1212 FirstIntersectionWithAllocated(static_cast<Register>(reg), unallocated); 1232 FirstIntersectionWithAllocated(static_cast<Register>(reg), unallocated);
1213 1233
1214 if (intersection > free_until) { 1234 if (intersection > free_until) {
1215 candidate = static_cast<Register>(reg); 1235 candidate = static_cast<Register>(reg);
1216 free_until = intersection; 1236 free_until = intersection;
1217 if (free_until == kMaxPosition) break; 1237 if (free_until == kMaxPosition) break;
1218 } 1238 }
1219 } 1239 }
1220 } 1240 }
1221 1241
1222 if (free_until != kMaxPosition) free_until = ToParallelMove(free_until);
1223
1224 // All registers are blocked by active ranges. 1242 // All registers are blocked by active ranges.
1225 if (free_until <= unallocated->Start()) return false; 1243 if (free_until <= unallocated->Start()) return false;
1226 1244
1227 TRACE_ALLOC(("assigning free register %s to %d\n", 1245 TRACE_ALLOC(("assigning free register %s to %d\n",
1228 Location::RegisterLocation(candidate).Name(), 1246 Location::RegisterLocation(candidate).Name(),
1229 unallocated->vreg())); 1247 unallocated->vreg()));
1230 1248
1231 if (free_until != kMaxPosition) { 1249 if (free_until != kMaxPosition) {
1232 // There was an intersection. Split unallocated. 1250 // There was an intersection. Split unallocated.
1233 TRACE_ALLOC((" splitting at %d\n", free_until)); 1251 TRACE_ALLOC((" splitting at %d\n", free_until));
(...skipping 25 matching lines...) Expand all
1259 if (UpdateFreeUntil(static_cast<Register>(reg), 1277 if (UpdateFreeUntil(static_cast<Register>(reg),
1260 unallocated, 1278 unallocated,
1261 &free_until, 1279 &free_until,
1262 &blocked_at)) { 1280 &blocked_at)) {
1263 candidate = static_cast<Register>(reg); 1281 candidate = static_cast<Register>(reg);
1264 } 1282 }
1265 } 1283 }
1266 1284
1267 if (free_until < register_use->pos()) { 1285 if (free_until < register_use->pos()) {
1268 // Can't acquire free register. Spill until we really need one. 1286 // Can't acquire free register. Spill until we really need one.
1269 ASSERT(unallocated->Start() < ToParallelMove(register_use->pos())); 1287 ASSERT(unallocated->Start() < ToInstructionStart(register_use->pos()));
1270 SpillBetween(unallocated, unallocated->Start(), register_use->pos()); 1288 SpillBetween(unallocated, unallocated->Start(), register_use->pos());
1271 return; 1289 return;
1272 } 1290 }
1273 1291
1274 if (blocked_at < unallocated->End()) { 1292 if (blocked_at < unallocated->End()) {
1275 LiveRange* tail = SplitBetween(unallocated, 1293 LiveRange* tail = SplitBetween(unallocated,
1276 unallocated->Start(), 1294 unallocated->Start(),
1277 blocked_at); 1295 blocked_at);
1278 AddToUnallocated(tail); 1296 AddToUnallocated(tail);
1279 } 1297 }
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
1398 SpillBetween(allocated, spill_position, restore_position); 1416 SpillBetween(allocated, spill_position, restore_position);
1399 } 1417 }
1400 1418
1401 return true; 1419 return true;
1402 } 1420 }
1403 1421
1404 1422
1405 MoveOperands* FlowGraphAllocator::AddMoveAt(intptr_t pos, 1423 MoveOperands* FlowGraphAllocator::AddMoveAt(intptr_t pos,
1406 Location to, 1424 Location to,
1407 Location from) { 1425 Location from) {
1408 ASSERT(IsParallelMovePosition(pos));
1409 Instruction* instr = InstructionAt(pos); 1426 Instruction* instr = InstructionAt(pos);
1410 ASSERT(!instr->IsBlockEntry()); 1427 ASSERT(!instr->IsBlockEntry());
1411 return CreateParallelMoveBefore(instr, pos)->AddMove(to, from); 1428
1429 ParallelMoveInstr* parallel_move = NULL;
1430 if (IsInstructionStartPosition(pos)) {
1431 parallel_move = CreateParallelMoveBefore(instr, pos);
1432 } else {
1433 parallel_move = CreateParallelMoveAfter(instr, pos);
1434 }
1435
1436 return parallel_move->AddMove(to, from);
1412 } 1437 }
1413 1438
1414 1439
1415 void FlowGraphAllocator::ConvertUseTo(UsePosition* use, Location loc) { 1440 void FlowGraphAllocator::ConvertUseTo(UsePosition* use, Location loc) {
1416 ASSERT(use->location_slot() != NULL); 1441 ASSERT(use->location_slot() != NULL);
1417 Location* slot = use->location_slot(); 1442 Location* slot = use->location_slot();
1418 ASSERT(slot->IsUnallocated()); 1443 ASSERT(slot->IsUnallocated());
1419 ASSERT((slot->policy() == Location::kRequiresRegister) || 1444 ASSERT((slot->policy() == Location::kRequiresRegister) ||
1420 (slot->policy() == Location::kPrefersRegister) || 1445 (slot->policy() == Location::kPrefersRegister) ||
1421 (slot->policy() == Location::kAny)); 1446 (slot->policy() == Location::kAny));
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
1538 TRACE_ALLOC(("Connect source_block=%d, target_block=%d\n", 1563 TRACE_ALLOC(("Connect source_block=%d, target_block=%d\n",
1539 source_block->block_id(), 1564 source_block->block_id(),
1540 target_block->block_id())); 1565 target_block->block_id()));
1541 if (range->next_sibling() == NULL) { 1566 if (range->next_sibling() == NULL) {
1542 // Nothing to connect. The whole range was allocated to the same location. 1567 // Nothing to connect. The whole range was allocated to the same location.
1543 TRACE_ALLOC(("range %d has no siblings\n", range->vreg())); 1568 TRACE_ALLOC(("range %d has no siblings\n", range->vreg()));
1544 return; 1569 return;
1545 } 1570 }
1546 1571
1547 const intptr_t source_pos = source_block->end_pos() - 1; 1572 const intptr_t source_pos = source_block->end_pos() - 1;
1548 ASSERT(IsInstructionPosition(source_pos)); 1573 ASSERT(IsInstructionEndPosition(source_pos));
1549 1574
1550 const intptr_t target_pos = target_block->start_pos(); 1575 const intptr_t target_pos = target_block->start_pos();
1551 1576
1552 Location target; 1577 Location target;
1553 Location source; 1578 Location source;
1554 1579
1555 #ifdef DEBUG 1580 #ifdef DEBUG
1556 LiveRange* source_cover = NULL; 1581 LiveRange* source_cover = NULL;
1557 LiveRange* target_cover = NULL; 1582 LiveRange* target_cover = NULL;
1558 #endif 1583 #endif
(...skipping 19 matching lines...) Expand all
1578 1603
1579 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n", 1604 TRACE_ALLOC(("connecting [%d, %d) [%s] to [%d, %d) [%s]\n",
1580 source_cover->Start(), source_cover->End(), source.Name(), 1605 source_cover->Start(), source_cover->End(), source.Name(),
1581 target_cover->Start(), target_cover->End(), target.Name())); 1606 target_cover->Start(), target_cover->End(), target.Name()));
1582 1607
1583 // Siblings were allocated to the same register. 1608 // Siblings were allocated to the same register.
1584 if (source.Equals(target)) return; 1609 if (source.Equals(target)) return;
1585 1610
1586 Instruction* last = source_block->last_instruction(); 1611 Instruction* last = source_block->last_instruction();
1587 if (last->SuccessorCount() == 1) { 1612 if (last->SuccessorCount() == 1) {
1588 CreateParallelMoveBefore(last, last->lifetime_position() - 1)-> 1613 CreateParallelMoveBefore(last, last->lifetime_position())->
1589 AddMove(target, source); 1614 AddMove(target, source);
1590 } else { 1615 } else {
1591 CreateParallelMoveAfter(target_block, target_block->start_pos())-> 1616 CreateParallelMoveAfter(target_block, target_block->start_pos())->
1592 AddMove(target, source); 1617 AddMove(target, source);
1593 } 1618 }
1594 } 1619 }
1595 1620
1596 1621
1597 void FlowGraphAllocator::ResolveControlFlow() { 1622 void FlowGraphAllocator::ResolveControlFlow() {
1598 // Resolve linear control flow between touching split siblings 1623 // Resolve linear control flow between touching split siblings
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1651 1676
1652 if (FLAG_trace_ssa_allocator) { 1677 if (FLAG_trace_ssa_allocator) {
1653 OS::Print("-- ir after allocation -------------------------\n"); 1678 OS::Print("-- ir after allocation -------------------------\n");
1654 FlowGraphPrinter printer(Function::Handle(), block_order_, true); 1679 FlowGraphPrinter printer(Function::Handle(), block_order_, true);
1655 printer.PrintBlocks(); 1680 printer.PrintBlocks();
1656 } 1681 }
1657 } 1682 }
1658 1683
1659 1684
1660 } // namespace dart 1685 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_allocator.h ('k') | runtime/vm/flow_graph_compiler_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698