| 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.h" | 5 #include "vm/flow_graph.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
| 9 #include "vm/intermediate_language.h" | 9 #include "vm/intermediate_language.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 | 545 |
| 546 // 2a. Handle uses: | 546 // 2a. Handle uses: |
| 547 // Update expression stack environment for each use. | 547 // Update expression stack environment for each use. |
| 548 // For each use of a LoadLocal or StoreLocal: Replace it with the value | 548 // For each use of a LoadLocal or StoreLocal: Replace it with the value |
| 549 // from the environment. | 549 // from the environment. |
| 550 for (intptr_t i = current->InputCount() - 1; i >= 0; --i) { | 550 for (intptr_t i = current->InputCount() - 1; i >= 0; --i) { |
| 551 Value* v = current->InputAt(i); | 551 Value* v = current->InputAt(i); |
| 552 // Update expression stack. | 552 // Update expression stack. |
| 553 ASSERT(env->length() > variable_count()); | 553 ASSERT(env->length() > variable_count()); |
| 554 | 554 |
| 555 Definition* reaching_defn = env->Last(); | 555 Definition* input_defn = env->Last(); |
| 556 env->RemoveLast(); | 556 env->RemoveLast(); |
| 557 | 557 |
| 558 Definition* input_defn = v->definition(); | 558 BindInstr* as_bind = v->definition()->AsBind(); |
| 559 if (input_defn->IsLoadLocal() || input_defn->IsStoreLocal()) { | 559 if ((as_bind != NULL) && |
| 560 (as_bind->computation()->IsLoadLocal() || |
| 561 as_bind->computation()->IsStoreLocal())) { |
| 560 // Remove the load/store from the graph. | 562 // Remove the load/store from the graph. |
| 561 input_defn->RemoveFromGraph(); | 563 as_bind->RemoveFromGraph(); |
| 562 // Assert we are not referencing nulls in the initial environment. | 564 // Assert we are not referencing nulls in the initial environment. |
| 563 ASSERT(reaching_defn->ssa_temp_index() != -1); | 565 ASSERT(input_defn->ssa_temp_index() != -1); |
| 564 current->SetInputAt(i, new Value(reaching_defn)); | 566 current->SetInputAt(i, new Value(input_defn)); |
| 565 } | 567 } |
| 566 } | 568 } |
| 567 | 569 |
| 568 // Drop pushed arguments for calls. | 570 // Drop pushed arguments for calls. |
| 569 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { | 571 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { |
| 570 env->RemoveLast(); | 572 env->RemoveLast(); |
| 571 } | 573 } |
| 572 | 574 |
| 573 // 2b. Handle LoadLocal and StoreLocal. | 575 // 2b. Handle LoadLocal and StoreLocal. |
| 574 // For each LoadLocal: Remove it from the graph. | 576 // For each LoadLocal: Remove it from the graph. |
| 575 // For each StoreLocal: Remove it from the graph and update the environment. | 577 // For each StoreLocal: Remove it from the graph and update the environment. |
| 576 Definition* definition = current->AsDefinition(); | 578 BindInstr* bind = current->AsBind(); |
| 577 if (definition != NULL) { | 579 if (bind != NULL) { |
| 578 LoadLocalInstr* load = definition->AsLoadLocal(); | 580 LoadLocalComp* load = bind->computation()->AsLoadLocal(); |
| 579 StoreLocalInstr* store = definition->AsStoreLocal(); | 581 StoreLocalComp* store = bind->computation()->AsStoreLocal(); |
| 580 if ((load != NULL) || (store != NULL)) { | 582 if ((load != NULL) || (store != NULL)) { |
| 581 intptr_t index; | 583 intptr_t index; |
| 582 if (store != NULL) { | 584 if (store != NULL) { |
| 583 index = store->local().BitIndexIn(non_copied_parameter_count_); | 585 index = store->local().BitIndexIn(non_copied_parameter_count_); |
| 584 // Update renaming environment. | 586 // Update renaming environment. |
| 585 (*env)[index] = store->value()->definition(); | 587 (*env)[index] = store->value()->definition(); |
| 586 } else { | 588 } else { |
| 587 // The graph construction ensures we do not have an unused LoadLocal | 589 // The graph construction ensures we do not have an unused LoadLocal |
| 588 // computation. | 590 // computation. |
| 589 ASSERT(definition->is_used()); | 591 ASSERT(bind->is_used()); |
| 590 index = load->local().BitIndexIn(non_copied_parameter_count_); | 592 index = load->local().BitIndexIn(non_copied_parameter_count_); |
| 591 | 593 |
| 592 PhiInstr* phi = (*env)[index]->AsPhi(); | 594 PhiInstr* phi = (*env)[index]->AsPhi(); |
| 593 if ((phi != NULL) && !phi->is_alive()) { | 595 if ((phi != NULL) && !phi->is_alive()) { |
| 594 phi->mark_alive(); | 596 phi->mark_alive(); |
| 595 live_phis->Add(phi); | 597 live_phis->Add(phi); |
| 596 } | 598 } |
| 597 } | 599 } |
| 598 // Update expression stack or remove from graph. | 600 // Update expression stack or remove from graph. |
| 599 if (definition->is_used()) { | 601 if (bind->is_used()) { |
| 600 env->Add((*env)[index]); | 602 env->Add((*env)[index]); |
| 601 // We remove load/store instructions when we find their use in 2a. | 603 // We remove load/store instructions when we find their use in 2a. |
| 602 } else { | 604 } else { |
| 603 it.RemoveCurrentFromGraph(); | 605 it.RemoveCurrentFromGraph(); |
| 604 } | 606 } |
| 605 } else { | 607 } else { |
| 606 // Not a load or store. | 608 // Not a load or store. |
| 607 if (definition->is_used()) { | 609 if (bind->is_used()) { |
| 608 // Assign fresh SSA temporary and update expression stack. | 610 // Assign fresh SSA temporary and update expression stack. |
| 609 definition->set_ssa_temp_index(alloc_ssa_temp_index()); | 611 bind->set_ssa_temp_index(alloc_ssa_temp_index()); |
| 610 env->Add(definition); | 612 env->Add(bind); |
| 611 } | 613 } |
| 612 } | 614 } |
| 613 } | 615 } |
| 614 | 616 |
| 615 // 2c. Handle pushed argument. | 617 // 2c. Handle pushed argument. |
| 616 PushArgumentInstr* push = current->AsPushArgument(); | 618 PushArgumentInstr* push = current->AsPushArgument(); |
| 617 if (push != NULL) { | 619 if (push != NULL) { |
| 618 env->Add(push); | 620 env->Add(push); |
| 619 } | 621 } |
| 620 } | 622 } |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 | 694 |
| 693 | 695 |
| 694 // Inline a flow graph at a call site. | 696 // Inline a flow graph at a call site. |
| 695 // | 697 // |
| 696 // Assumes the callee graph was computed with BuildGraphForInlining and | 698 // Assumes the callee graph was computed with BuildGraphForInlining and |
| 697 // transformed to SSA with ComputeSSAForInlining, and that the use lists have | 699 // transformed to SSA with ComputeSSAForInlining, and that the use lists have |
| 698 // been correctly computed. | 700 // been correctly computed. |
| 699 // | 701 // |
| 700 // After inlining the caller graph will correctly have adjusted the pre/post | 702 // After inlining the caller graph will correctly have adjusted the pre/post |
| 701 // orders, the dominator tree and the use lists. | 703 // orders, the dominator tree and the use lists. |
| 702 void FlowGraph::InlineCall(StaticCallInstr* call, FlowGraph* callee_graph) { | 704 void FlowGraph::InlineCall(BindInstr* caller_instr, |
| 705 StaticCallComp* caller_comp, |
| 706 FlowGraph* callee_graph) { |
| 703 ASSERT(callee_graph->exits() != NULL); | 707 ASSERT(callee_graph->exits() != NULL); |
| 704 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); | 708 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); |
| 705 ASSERT(callee_graph->max_virtual_register_number() > | 709 ASSERT(callee_graph->max_virtual_register_number() > |
| 706 max_virtual_register_number()); | 710 max_virtual_register_number()); |
| 707 | 711 |
| 708 // TODO(zerny): Implement support for callee graphs with control flow. | 712 // TODO(zerny): Implement support for callee graphs with control flow. |
| 709 ASSERT(callee_graph->preorder().length() == 2); | 713 ASSERT(callee_graph->preorder().length() == 2); |
| 710 | 714 |
| 711 // Adjust the SSA temp index by the callee graph's index. | 715 // Adjust the SSA temp index by the callee graph's index. |
| 712 current_ssa_temp_index_ = callee_graph->max_virtual_register_number(); | 716 current_ssa_temp_index_ = callee_graph->max_virtual_register_number(); |
| 713 | 717 |
| 714 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); | 718 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); |
| 715 ZoneGrowableArray<ReturnInstr*>* callee_exits = callee_graph->exits(); | 719 ZoneGrowableArray<ReturnInstr*>* callee_exits = callee_graph->exits(); |
| 716 | 720 |
| 717 // 1. Insert the callee graph into the caller graph. | 721 // 1. Insert the callee graph into the caller graph. |
| 718 if (callee_exits->length() == 1) { | 722 if (callee_exits->length() == 1) { |
| 719 ReturnInstr* exit = (*callee_exits)[0]; | 723 ReturnInstr* exit = (*callee_exits)[0]; |
| 720 // TODO(zerny): Support one exit graph containing control flow. | 724 // TODO(zerny): Support one exit graph containing control flow. |
| 721 ASSERT(callee_entry == GetBlockEntry(exit)); | 725 ASSERT(callee_entry == GetBlockEntry(exit)); |
| 722 // For just one exit, replace the uses and remove the call from the graph. | 726 // For just one exit, replace the uses and remove the call from the graph. |
| 723 call->ReplaceUsesWith(exit->value()->definition()); | 727 caller_instr->ReplaceUsesWith(exit->value()->definition()); |
| 724 Link(call->previous(), callee_entry->next()); | 728 Link(caller_instr->previous(), callee_entry->next()); |
| 725 Link(exit->previous(), call->next()); | 729 Link(exit->previous(), caller_instr->next()); |
| 726 } else { | 730 } else { |
| 727 // TODO(zerny): Support multiple exits. | 731 // TODO(zerny): Support multiple exits. |
| 728 UNREACHABLE(); | 732 UNREACHABLE(); |
| 729 } | 733 } |
| 730 | 734 |
| 731 // TODO(zerny): Adjust pre/post orders. | 735 // TODO(zerny): Adjust pre/post orders. |
| 732 // TODO(zerny): Update dominator tree. | 736 // TODO(zerny): Update dominator tree. |
| 733 | 737 |
| 734 // Remove original arguments to the call. | 738 // Remove original arguments to the call. |
| 735 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 739 for (intptr_t i = 0; i < caller_comp->ArgumentCount(); ++i) { |
| 736 PushArgumentInstr* push = call->ArgumentAt(i); | 740 PushArgumentInstr* push = caller_comp->ArgumentAt(i); |
| 737 push->ReplaceUsesWith(push->value()->definition()); | 741 push->ReplaceUsesWith(push->value()->definition()); |
| 738 push->RemoveFromGraph(); | 742 push->RemoveFromGraph(); |
| 739 } | 743 } |
| 740 } | 744 } |
| 741 | 745 |
| 742 | 746 |
| 743 } // namespace dart | 747 } // namespace dart |
| OLD | NEW |