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_builder.h" | 5 #include "vm/flow_graph_builder.h" |
| 6 | 6 |
| 7 #include "vm/flags.h" | 7 #include "vm/flags.h" |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 #include "vm/os.h" | 9 #include "vm/os.h" |
| 10 #include "vm/parser.h" | 10 #include "vm/parser.h" |
| 11 | 11 |
| 12 namespace dart { | 12 namespace dart { |
| 13 | 13 |
| 14 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from graph builder."); | 14 DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from graph builder."); |
| 15 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 15 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
| 16 DECLARE_FLAG(bool, enable_type_checks); | 16 DECLARE_FLAG(bool, enable_type_checks); |
| 17 | 17 |
| 18 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { | 18 void EffectGraphVisitor::Append(const EffectGraphVisitor& other_fragment) { |
| 19 ASSERT(is_open()); | 19 ASSERT(is_open()); |
| 20 if (other_fragment.is_empty()) return; | 20 if (other_fragment.is_empty()) return; |
| 21 if (is_empty()) { | 21 if (is_empty()) { |
| 22 entry_ = other_fragment.entry(); | 22 entry_ = other_fragment.entry(); |
| 23 exit_ = other_fragment.exit(); | 23 exit_ = other_fragment.exit(); |
| 24 } else { | 24 } else { |
| 25 exit()->set_successor(other_fragment.entry()); | 25 exit()->SetSuccessor(other_fragment.entry()); |
| 26 exit_ = other_fragment.exit(); | 26 exit_ = other_fragment.exit(); |
| 27 } | 27 } |
| 28 } | 28 } |
| 29 | 29 |
| 30 | 30 |
| 31 void EffectGraphVisitor::AddInstruction(Instruction* instruction) { | 31 void EffectGraphVisitor::AddInstruction(Instruction* instruction) { |
| 32 ASSERT(is_open()); | 32 ASSERT(is_open()); |
| 33 if (is_empty()) { | 33 if (is_empty()) { |
| 34 entry_ = exit_ = instruction; | 34 entry_ = exit_ = instruction; |
| 35 } else { | 35 } else { |
| 36 exit()->set_successor(instruction); | 36 exit()->SetSuccessor(instruction); |
| 37 exit_ = instruction; | 37 exit_ = instruction; |
| 38 } | 38 } |
| 39 } | 39 } |
| 40 | 40 |
| 41 | 41 |
| 42 void EffectGraphVisitor::Join(const TestGraphVisitor& test_fragment, | 42 void EffectGraphVisitor::Join(const TestGraphVisitor& test_fragment, |
| 43 const EffectGraphVisitor& true_fragment, | 43 const EffectGraphVisitor& true_fragment, |
| 44 const EffectGraphVisitor& false_fragment) { | 44 const EffectGraphVisitor& false_fragment) { |
| 45 // We have: a test graph fragment with zero, one, or two available exits; | 45 // We have: a test graph fragment with zero, one, or two available exits; |
| 46 // and a pair of effect graph fragments with zero or one available exits. | 46 // and a pair of effect graph fragments with zero or one available exits. |
| 47 // We want to append the branch and (if necessary) a join node to this | 47 // We want to append the branch and (if necessary) a join node to this |
| 48 // graph fragment. | 48 // graph fragment. |
| 49 ASSERT(is_open()); | 49 ASSERT(is_open()); |
| 50 | 50 |
| 51 // 1. Connect the test to this graph. | 51 // 1. Connect the test to this graph. |
| 52 Append(test_fragment); | 52 Append(test_fragment); |
| 53 | 53 |
| 54 // 2. Connect the true and false bodies to the test if they are reachable, | 54 // 2. Connect the true and false bodies to the test if they are reachable, |
| 55 // and if so record their exits (if any). | 55 // and if so record their exits (if any). |
| 56 if (test_fragment.can_be_true()) { | 56 if (test_fragment.can_be_true()) { |
| 57 Instruction* true_exit = NULL; | 57 Instruction* true_exit = NULL; |
| 58 Instruction* false_exit = NULL; | 58 Instruction* false_exit = NULL; |
| 59 TargetEntryInstr* true_entry = new TargetEntryInstr(); | 59 TargetEntryInstr* true_entry = new TargetEntryInstr(); |
| 60 *test_fragment.true_successor_address() = true_entry; | 60 *test_fragment.true_successor_address() = true_entry; |
| 61 true_entry->set_successor(true_fragment.entry()); | 61 true_entry->SetSuccessor(true_fragment.entry()); |
| 62 true_exit = true_fragment.is_empty() ? true_entry : true_fragment.exit(); | 62 true_exit = true_fragment.is_empty() ? true_entry : true_fragment.exit(); |
| 63 | 63 |
| 64 TargetEntryInstr* false_entry = new TargetEntryInstr(); | 64 TargetEntryInstr* false_entry = new TargetEntryInstr(); |
| 65 *test_fragment.false_successor_address() = false_entry; | 65 *test_fragment.false_successor_address() = false_entry; |
| 66 false_entry->set_successor(false_fragment.entry()); | 66 false_entry->SetSuccessor(false_fragment.entry()); |
| 67 false_exit = | 67 false_exit = |
| 68 false_fragment.is_empty() ? false_entry : false_fragment.exit(); | 68 false_fragment.is_empty() ? false_entry : false_fragment.exit(); |
| 69 | 69 |
| 70 exit_ = new JoinEntryInstr(); | 70 exit_ = new JoinEntryInstr(); |
| 71 true_exit->set_successor(exit_); | 71 true_exit->SetSuccessor(exit_); |
| 72 false_exit->set_successor(exit_); | 72 false_exit->SetSuccessor(exit_); |
| 73 } | 73 } |
| 74 } | 74 } |
| 75 | 75 |
| 76 | 76 |
| 77 void EffectGraphVisitor::TieLoop(const TestGraphVisitor& test_fragment, | 77 void EffectGraphVisitor::TieLoop(const TestGraphVisitor& test_fragment, |
| 78 const EffectGraphVisitor& body_fragment) { | 78 const EffectGraphVisitor& body_fragment) { |
| 79 // We have: a test graph fragment with zero, one, or two available exits; | 79 // We have: a test graph fragment with zero, one, or two available exits; |
| 80 // and an effect graph fragment with zero or one available exits. We want | 80 // and an effect graph fragment with zero or one available exits. We want |
| 81 // to append the 'while loop' consisting of the test graph fragment as | 81 // to append the 'while loop' consisting of the test graph fragment as |
| 82 // condition and the effect graph fragment as body. | 82 // condition and the effect graph fragment as body. |
| 83 ASSERT(is_open()); | 83 ASSERT(is_open()); |
| 84 | 84 |
| 85 // 1. Connect the body to the test if it is reachable, and if so record | 85 // 1. Connect the body to the test if it is reachable, and if so record |
| 86 // its exit (if any). | 86 // its exit (if any). |
| 87 Instruction* body_exit = NULL; | 87 Instruction* body_exit = NULL; |
| 88 if (test_fragment.can_be_true()) { | 88 if (test_fragment.can_be_true()) { |
| 89 TargetEntryInstr* body_entry = new TargetEntryInstr(); | 89 TargetEntryInstr* body_entry = new TargetEntryInstr(); |
| 90 *test_fragment.true_successor_address() = body_entry; | 90 *test_fragment.true_successor_address() = body_entry; |
| 91 body_entry->set_successor(body_fragment.entry()); | 91 body_entry->SetSuccessor(body_fragment.entry()); |
| 92 body_exit = body_fragment.is_empty() ? body_entry : body_fragment.exit(); | 92 body_exit = body_fragment.is_empty() ? body_entry : body_fragment.exit(); |
| 93 } | 93 } |
| 94 | 94 |
| 95 // 2. Connect the test to this graph, including the body if reachable and | 95 // 2. Connect the test to this graph, including the body if reachable and |
| 96 // using a fresh join node if the body is reachable and has an open exit. | 96 // using a fresh join node if the body is reachable and has an open exit. |
| 97 if (body_exit == NULL) { | 97 if (body_exit == NULL) { |
| 98 Append(test_fragment); | 98 Append(test_fragment); |
| 99 } else { | 99 } else { |
| 100 JoinEntryInstr* join = new JoinEntryInstr(); | 100 JoinEntryInstr* join = new JoinEntryInstr(); |
| 101 AddInstruction(join); | 101 AddInstruction(join); |
| 102 join->set_successor(test_fragment.entry()); | 102 join->SetSuccessor(test_fragment.entry()); |
| 103 body_exit->set_successor(join); | 103 body_exit->SetSuccessor(join); |
| 104 } | 104 } |
| 105 | 105 |
| 106 // 3. Set the exit to the graph to be empty or a fresh target node | 106 // 3. Set the exit to the graph to be empty or a fresh target node |
| 107 // depending on whether the false branch of the test is reachable. | 107 // depending on whether the false branch of the test is reachable. |
| 108 if (test_fragment.can_be_false()) { | 108 if (test_fragment.can_be_false()) { |
| 109 exit_ = *test_fragment.false_successor_address() = new TargetEntryInstr(); | 109 exit_ = *test_fragment.false_successor_address() = new TargetEntryInstr(); |
| 110 } else { | 110 } else { |
| 111 exit_ = NULL; | 111 exit_ = NULL; |
| 112 } | 112 } |
| 113 } | 113 } |
| (...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 864 } | 864 } |
| 865 } | 865 } |
| 866 | 866 |
| 867 | 867 |
| 868 void FlowGraphBuilder::PrintGraph() const { | 868 void FlowGraphBuilder::PrintGraph() const { |
| 869 if (!FLAG_print_flow_graph || HasBailedOut()) return; | 869 if (!FLAG_print_flow_graph || HasBailedOut()) return; |
| 870 | 870 |
| 871 OS::Print("==== %s\n", | 871 OS::Print("==== %s\n", |
| 872 parsed_function().function().ToFullyQualifiedCString()); | 872 parsed_function().function().ToFullyQualifiedCString()); |
| 873 | 873 |
| 874 for (intptr_t i = postorder_.length() - 1; i >= 0; --i) { | 874 for (intptr_t i = postorder_block_entries_.length() - 1; i >= 0; --i) { |
| 875 OS::Print("%8d: ", postorder_.length() - i); | 875 // Print the block entry. |
| 876 postorder_[i]->Print(i, postorder_); | 876 Instruction* current = postorder_block_entries_[i]->Print(); |
| 877 // And all the successors until an exit, branch, or a block entry. | |
| 878 while (current != NULL && !current->IsBlockEntry()) { | |
|
srdjan
2012/02/22 17:41:10
More parenthesis, please
Kevin Millikin (Google)
2012/02/23 09:08:04
Thanks for the reminder.
| |
| 879 OS::Print("\n"); | |
| 880 current = current->Print(); | |
| 881 } | |
| 882 if (current != NULL && current->IsBlockEntry()) { | |
| 883 OS::Print(" goto %d", current->GetBlockNumber()); | |
| 884 } | |
| 877 OS::Print("\n"); | 885 OS::Print("\n"); |
| 878 } | 886 } |
| 879 OS::Print("\n"); | |
| 880 } | 887 } |
| 881 | 888 |
| 882 | 889 |
| 883 void FlowGraphBuilder::BuildGraph() { | 890 void FlowGraphBuilder::BuildGraph() { |
| 884 EffectGraphVisitor for_effect(this, 0); | 891 EffectGraphVisitor for_effect(this, 0); |
| 892 for_effect.AddInstruction(new TargetEntryInstr()); | |
| 885 parsed_function().node_sequence()->Visit(&for_effect); | 893 parsed_function().node_sequence()->Visit(&for_effect); |
| 886 TraceBailout(); | 894 TraceBailout(); |
| 887 if (!HasBailedOut() && (for_effect.entry() != NULL)) { | 895 if (!HasBailedOut() && (for_effect.entry() != NULL)) { |
| 888 for_effect.entry()->Postorder(&postorder_); | 896 // Accumulate basic block entries via postorder traversal. |
| 897 for_effect.entry()->Postorder(&postorder_block_entries_); | |
| 898 // Number the blocks in reverse postorder starting with 0. | |
| 899 intptr_t index = postorder_block_entries_.length() - 1; | |
|
srdjan
2012/02/22 17:41:10
AS a for loop maybe?
intptr_t number = 0;
for (in
Kevin Millikin (Google)
2012/02/23 09:08:04
Done.
| |
| 900 intptr_t number = 0; | |
| 901 while (index >= 0) { | |
| 902 postorder_block_entries_[index--]->SetBlockNumber(number++); | |
| 903 } | |
| 889 } | 904 } |
| 890 PrintGraph(); | 905 PrintGraph(); |
| 891 } | 906 } |
| 892 | 907 |
| 893 } // namespace dart | 908 } // namespace dart |
| OLD | NEW |