Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 #include "vm/block_scheduler.h" | |
| 6 | |
| 7 #include "vm/allocation.h" | |
| 8 #include "vm/flow_graph.h" | |
| 9 | |
| 10 namespace dart { | |
| 11 | |
| 12 // Compute the edge count at the deopt id of a TargetEntry or Goto. | |
| 13 static intptr_t ComputeEdgeCount(const Code& unoptimized_code, | |
| 14 intptr_t deopt_id) { | |
|
srdjan
2013/08/14 00:28:24
This seems like quite slow way to extract edge cou
| |
| 15 ASSERT(deopt_id != Isolate::kNoDeoptId); | |
| 16 | |
| 17 // Intrinsified functions do not have edge counts, so give all edges equal | |
| 18 // weights. | |
|
srdjan
2013/08/14 00:28:24
Some intrinsified functions should have edge count
| |
| 19 if (unoptimized_code.pointer_offsets_length() == 0) return 1; | |
| 20 | |
| 21 uword pc = unoptimized_code.GetPcForDeoptId(deopt_id, PcDescriptors::kDeopt); | |
| 22 Array& array = Array::Handle(); | |
| 23 // Pointer offsets are sorted in decreasing order. Find the first one | |
| 24 // after the deopt id's pc. | |
| 25 // TODO(kmillikin): Use a more reliable way to find the counter. | |
| 26 for (intptr_t j = unoptimized_code.pointer_offsets_length() - 1; | |
| 27 j >= 0; | |
| 28 --j) { | |
| 29 uword addr = | |
| 30 unoptimized_code.GetPointerOffsetAt(j) + unoptimized_code.EntryPoint(); | |
| 31 if (addr > pc) { | |
| 32 array ^= *reinterpret_cast<RawObject**>(addr); | |
| 33 break; | |
| 34 } | |
| 35 } | |
| 36 ASSERT(!array.IsNull()); | |
| 37 return Smi::Value(Smi::RawCast(array.At(0))); | |
| 38 } | |
| 39 | |
| 40 | |
| 41 // There is an edge from instruction->successor. Set its weight (edge count | |
| 42 // per function entry). | |
| 43 static void SetEdgeWeight(Instruction* instruction, | |
| 44 BlockEntryInstr* successor, | |
| 45 const Code& unoptimized_code, | |
| 46 intptr_t entry_count) { | |
| 47 intptr_t count = -1; | |
| 48 double weight = 0.0; | |
|
Florian Schneider
2013/08/12 11:30:09
style-nit: I would not hoist these two declaration
Kevin Millikin (Google)
2013/08/13 11:14:57
OK, done.
srdjan
2013/08/14 00:28:24
Could you please upload your changes.
| |
| 49 TargetEntryInstr* target = successor->AsTargetEntry(); | |
| 50 if (target != NULL) { | |
| 51 count = ComputeEdgeCount(unoptimized_code, target->deopt_id()); | |
| 52 if ((count >= 0) && (entry_count != 0)) { | |
| 53 weight = static_cast<double>(count) / static_cast<double>(entry_count); | |
| 54 target->set_edge_weight(weight); | |
| 55 } | |
| 56 } else { | |
| 57 GotoInstr* jump = instruction->AsGoto(); | |
| 58 if (jump != NULL) { | |
| 59 count = ComputeEdgeCount(unoptimized_code, jump->deopt_id()); | |
| 60 if ((count >= 0) && (entry_count != 0)) { | |
| 61 weight = static_cast<double>(count) / static_cast<double>(entry_count); | |
| 62 jump->set_edge_weight(weight); | |
| 63 } | |
| 64 } | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 | |
| 69 void BlockScheduler::AssignEdgeWeights() const { | |
| 70 const Code& unoptimized_code = Code::Handle( | |
| 71 flow_graph()->parsed_function().function().unoptimized_code()); | |
| 72 | |
| 73 intptr_t entry_count = | |
| 74 ComputeEdgeCount(unoptimized_code, | |
| 75 flow_graph()->graph_entry()->normal_entry()->deopt_id()); | |
| 76 flow_graph()->graph_entry()->set_entry_count(entry_count); | |
| 77 | |
| 78 for (BlockIterator it = flow_graph()->reverse_postorder_iterator(); | |
| 79 !it.Done(); | |
| 80 it.Advance()) { | |
| 81 BlockEntryInstr* block = it.Current(); | |
| 82 Instruction* last = block->last_instruction(); | |
| 83 for (intptr_t i = 0; i < last->SuccessorCount(); ++i) { | |
| 84 BlockEntryInstr* succ = last->SuccessorAt(i); | |
| 85 SetEdgeWeight(last, succ, unoptimized_code, entry_count); | |
| 86 } | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 | |
| 91 // A weighted control-flow graph edge. | |
| 92 struct Edge { | |
| 93 Edge(BlockEntryInstr* source, BlockEntryInstr* target, double weight) | |
| 94 : source(source), target(target), weight(weight) { } | |
| 95 | |
| 96 static int LowestWeightFirst(const Edge* a, const Edge* b); | |
| 97 | |
| 98 BlockEntryInstr* source; | |
| 99 BlockEntryInstr* target; | |
| 100 double weight; | |
| 101 }; | |
| 102 | |
| 103 | |
| 104 // A linked list node in a chain of blocks. | |
| 105 struct Link : public ZoneAllocated { | |
| 106 Link(BlockEntryInstr* block, Link* next) : block(block), next(next) { } | |
| 107 | |
| 108 BlockEntryInstr* block; | |
| 109 Link* next; | |
| 110 }; | |
| 111 | |
| 112 | |
| 113 // A chain of blocks with first and last pointers for fast concatenation and | |
| 114 // a length to support adding a shorter chain's links to a longer chain. | |
| 115 struct Chain : public ZoneAllocated { | |
| 116 explicit Chain(BlockEntryInstr* block) | |
| 117 : first(new Link(block, NULL)), last(first), length(1) { } | |
| 118 | |
| 119 Link* first; | |
| 120 Link* last; | |
| 121 intptr_t length; | |
| 122 }; | |
| 123 | |
| 124 | |
| 125 int Edge::LowestWeightFirst(const Edge* a, const Edge* b) { | |
| 126 return (a->weight < b->weight) ? -1 : (a->weight > b->weight); | |
| 127 } | |
| 128 | |
| 129 | |
| 130 // Combine two chains by adding the shorter chain's links to the longer | |
| 131 // chain. | |
| 132 static void Union(GrowableArray<Chain*>* chains, | |
| 133 Chain* source_chain, | |
| 134 Chain* target_chain) { | |
| 135 if (source_chain->length < target_chain->length) { | |
| 136 for (Link* link = source_chain->first; link != NULL; link = link->next) { | |
| 137 (*chains)[link->block->postorder_number()] = target_chain; | |
| 138 } | |
| 139 // Link the chains. | |
| 140 source_chain->last->next = target_chain->first; | |
| 141 // Update the state of the longer chain. | |
| 142 target_chain->first = source_chain->first; | |
| 143 target_chain->length += source_chain->length; | |
| 144 } else { | |
| 145 for (Link* link = target_chain->first; link != NULL; link = link->next) { | |
| 146 (*chains)[link->block->postorder_number()] = source_chain; | |
| 147 } | |
| 148 source_chain->last->next = target_chain->first; | |
| 149 source_chain->last = target_chain->last; | |
| 150 source_chain->length += target_chain->length; | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 | |
| 155 void BlockScheduler::ReorderBlocks() const { | |
| 156 // Add every block to a chain of length 1 and compute a list of edges | |
| 157 // sorted by weight. | |
| 158 intptr_t block_count = flow_graph()->preorder().length(); | |
| 159 GrowableArray<Edge> edges(2 * block_count); | |
| 160 | |
| 161 // A map from a block's postorder number to the chain it is in. Used to | |
| 162 // implement a simple (ordered) union-find data structure. Chains are | |
| 163 // stored by pointer so that they are aliased (mutating one mutates all | |
| 164 // shared ones). Find(n) is simply chains[n]. | |
| 165 GrowableArray<Chain*> chains(block_count); | |
| 166 | |
| 167 for (BlockIterator it = flow_graph()->postorder_iterator(); | |
| 168 !it.Done(); | |
| 169 it.Advance()) { | |
| 170 BlockEntryInstr* block = it.Current(); | |
| 171 chains.Add(new Chain(block)); | |
| 172 | |
| 173 Instruction* last = block->last_instruction(); | |
| 174 for (intptr_t i = 0; i < last->SuccessorCount(); ++i) { | |
| 175 BlockEntryInstr* succ = last->SuccessorAt(i); | |
| 176 double weight = 0.0; | |
| 177 if (succ->IsTargetEntry()) { | |
| 178 weight = succ->AsTargetEntry()->edge_weight(); | |
| 179 } else if (last->IsGoto()) { | |
| 180 weight = last->AsGoto()->edge_weight(); | |
| 181 } | |
| 182 edges.Add(Edge(block, succ, weight)); | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 // Handle each edge in turn. The edges are sorted by increasing weight. | |
| 187 edges.Sort(Edge::LowestWeightFirst); | |
| 188 while (!edges.is_empty()) { | |
| 189 Edge edge = edges.RemoveLast(); | |
| 190 Chain* source_chain = chains[edge.source->postorder_number()]; | |
| 191 Chain* target_chain = chains[edge.target->postorder_number()]; | |
| 192 | |
| 193 // If the source and target are already in the same chain or if the | |
| 194 // edge's source or target is not exposed at the appropriate end of a | |
| 195 // chain skip this edge. | |
| 196 if ((source_chain == target_chain) || | |
| 197 (edge.source != source_chain->last->block) || | |
| 198 (edge.target != target_chain->first->block)) { | |
| 199 continue; | |
| 200 } | |
| 201 | |
| 202 Union(&chains, source_chain, target_chain); | |
| 203 } | |
| 204 | |
| 205 // Build a new block order. Emit each chain when its first block occurs | |
| 206 // in the original reverse postorder ordering (which gives a topological | |
| 207 // sort of the blocks). | |
| 208 for (intptr_t i = block_count - 1; i >= 0; --i) { | |
| 209 if (chains[i]->first->block == flow_graph()->postorder()[i]) { | |
| 210 for (Link* link = chains[i]->first; link != NULL; link = link->next) { | |
| 211 flow_graph()->codegen_block_order(true)->Add(link->block); | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 } | |
| 216 | |
| 217 } // namespace dart | |
| OLD | NEW |