| 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) { |
| 15 ASSERT(deopt_id != Isolate::kNoDeoptId); |
| 16 |
| 17 // Intrinsified functions do not have edge counts, so give all edges equal |
| 18 // weights. |
| 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 TargetEntryInstr* target = successor->AsTargetEntry(); |
| 48 if (target != NULL) { |
| 49 intptr_t count = ComputeEdgeCount(unoptimized_code, target->deopt_id()); |
| 50 if ((count >= 0) && (entry_count != 0)) { |
| 51 double weight = |
| 52 static_cast<double>(count) / static_cast<double>(entry_count); |
| 53 target->set_edge_weight(weight); |
| 54 } |
| 55 } else { |
| 56 GotoInstr* jump = instruction->AsGoto(); |
| 57 if (jump != NULL) { |
| 58 intptr_t count = ComputeEdgeCount(unoptimized_code, jump->deopt_id()); |
| 59 if ((count >= 0) && (entry_count != 0)) { |
| 60 double weight = |
| 61 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 |