| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/loop-analysis.h" | 5 #include "src/compiler/loop-analysis.h" |
| 6 | 6 |
| 7 #include "src/compiler/graph.h" | 7 #include "src/compiler/graph.h" |
| 8 #include "src/compiler/node.h" | 8 #include "src/compiler/node.h" |
| 9 #include "src/compiler/node-marker.h" | 9 #include "src/compiler/node-marker.h" |
| 10 #include "src/compiler/node-properties-inl.h" | 10 #include "src/compiler/node-properties-inl.h" |
| 11 #include "src/zone.h" | 11 #include "src/zone.h" |
| 12 | 12 |
| 13 namespace v8 { | 13 namespace v8 { |
| 14 namespace internal { | 14 namespace internal { |
| 15 namespace compiler { | 15 namespace compiler { |
| 16 | 16 |
| 17 typedef uint32_t LoopMarks; | 17 #define OFFSET(x) ((x)&0x1f) |
| 18 | 18 #define BIT(x) (1u << OFFSET(x)) |
| 19 #define INDEX(x) ((x) >> 5) |
| 19 | 20 |
| 20 // TODO(titzer): don't assume entry edges have a particular index. | 21 // TODO(titzer): don't assume entry edges have a particular index. |
| 21 // TODO(titzer): use a BitMatrix to generalize this algorithm. | |
| 22 static const size_t kMaxLoops = 31; | |
| 23 static const int kAssumedLoopEntryIndex = 0; // assume loops are entered here. | 22 static const int kAssumedLoopEntryIndex = 0; // assume loops are entered here. |
| 24 static const LoopMarks kVisited = 1; // loop #0 is reserved. | |
| 25 | 23 |
| 26 | 24 |
| 27 // Temporary information for each node during marking. | 25 // Temporary information for each node during marking. |
| 28 struct NodeInfo { | 26 struct NodeInfo { |
| 29 Node* node; | 27 Node* node; |
| 30 NodeInfo* next; // link in chaining loop members | 28 NodeInfo* next; // link in chaining loop members |
| 31 LoopMarks forward; // accumulated marks in the forward direction | |
| 32 LoopMarks backward; // accumulated marks in the backward direction | |
| 33 LoopMarks loop_mark; // loop mark for header nodes; encodes loop_num | |
| 34 | |
| 35 bool MarkBackward(LoopMarks bw) { | |
| 36 LoopMarks prev = backward; | |
| 37 LoopMarks next = backward | bw; | |
| 38 backward = next; | |
| 39 return prev != next; | |
| 40 } | |
| 41 | |
| 42 bool MarkForward(LoopMarks fw) { | |
| 43 LoopMarks prev = forward; | |
| 44 LoopMarks next = forward | fw; | |
| 45 forward = next; | |
| 46 return prev != next; | |
| 47 } | |
| 48 | |
| 49 bool IsInLoop(size_t loop_num) { | |
| 50 DCHECK(loop_num > 0 && loop_num <= 31); | |
| 51 return forward & backward & (1 << loop_num); | |
| 52 } | |
| 53 | |
| 54 bool IsLoopHeader() { return loop_mark != 0; } | |
| 55 bool IsInAnyLoop() { return (forward & backward) > kVisited; } | |
| 56 | |
| 57 bool IsInHeaderForLoop(size_t loop_num) { | |
| 58 DCHECK(loop_num > 0); | |
| 59 return loop_mark == (kVisited | (1 << loop_num)); | |
| 60 } | |
| 61 }; | 29 }; |
| 62 | 30 |
| 63 | 31 |
| 64 // Temporary loop info needed during traversal and building the loop tree. | 32 // Temporary loop info needed during traversal and building the loop tree. |
| 65 struct LoopInfo { | 33 struct LoopInfo { |
| 66 Node* header; | 34 Node* header; |
| 67 NodeInfo* header_list; | 35 NodeInfo* header_list; |
| 68 NodeInfo* body_list; | 36 NodeInfo* body_list; |
| 69 LoopTree::Loop* loop; | 37 LoopTree::Loop* loop; |
| 70 }; | 38 }; |
| 71 | 39 |
| 72 | 40 |
| 73 static const NodeInfo kEmptyNodeInfo = {nullptr, nullptr, 0, 0, 0}; | |
| 74 | |
| 75 | |
| 76 // Encapsulation of the loop finding algorithm. | 41 // Encapsulation of the loop finding algorithm. |
| 77 // ----------------------------------------------------------------------------- | 42 // ----------------------------------------------------------------------------- |
| 78 // Conceptually, the contents of a loop are those nodes that are "between" the | 43 // Conceptually, the contents of a loop are those nodes that are "between" the |
| 79 // loop header and the backedges of the loop. Graphs in the soup of nodes can | 44 // loop header and the backedges of the loop. Graphs in the soup of nodes can |
| 80 // form improper cycles, so standard loop finding algorithms that work on CFGs | 45 // form improper cycles, so standard loop finding algorithms that work on CFGs |
| 81 // aren't sufficient. However, in valid TurboFan graphs, all cycles involve | 46 // aren't sufficient. However, in valid TurboFan graphs, all cycles involve |
| 82 // either a {Loop} node or a phi. The {Loop} node itself and its accompanying | 47 // either a {Loop} node or a phi. The {Loop} node itself and its accompanying |
| 83 // phis are treated together as a set referred to here as the loop header. | 48 // phis are treated together as a set referred to here as the loop header. |
| 84 // This loop finding algorithm works by traversing the graph in two directions, | 49 // This loop finding algorithm works by traversing the graph in two directions, |
| 85 // first from nodes to their inputs, starting at {end}, then in the reverse | 50 // first from nodes to their inputs, starting at {end}, then in the reverse |
| 86 // direction, from nodes to their uses, starting at loop headers. | 51 // direction, from nodes to their uses, starting at loop headers. |
| 87 // 1 bit per loop per node per direction are required during the marking phase. | 52 // 1 bit per loop per node per direction are required during the marking phase. |
| 88 // To handle nested loops correctly, the algorithm must filter some reachability | 53 // To handle nested loops correctly, the algorithm must filter some reachability |
| 89 // marks on edges into/out-of the loop header nodes. | 54 // marks on edges into/out-of the loop header nodes. |
| 90 class LoopFinderImpl { | 55 class LoopFinderImpl { |
| 91 public: | 56 public: |
| 92 LoopFinderImpl(Graph* graph, LoopTree* loop_tree, Zone* zone) | 57 LoopFinderImpl(Graph* graph, LoopTree* loop_tree, Zone* zone) |
| 93 : end_(graph->end()), | 58 : zone_(zone), |
| 59 end_(graph->end()), |
| 94 queue_(zone), | 60 queue_(zone), |
| 95 queued_(graph, 2), | 61 queued_(graph, 2), |
| 96 info_(graph->NodeCount(), kEmptyNodeInfo, zone), | 62 info_(graph->NodeCount(), {nullptr, nullptr}, zone), |
| 97 loops_(zone), | 63 loops_(zone), |
| 64 loop_num_(graph->NodeCount(), -1, zone), |
| 98 loop_tree_(loop_tree), | 65 loop_tree_(loop_tree), |
| 99 loops_found_(0) {} | 66 loops_found_(0), |
| 67 width_(0), |
| 68 backward_(nullptr), |
| 69 forward_(nullptr) {} |
| 100 | 70 |
| 101 void Run() { | 71 void Run() { |
| 102 PropagateBackward(); | 72 PropagateBackward(); |
| 103 PropagateForward(); | 73 PropagateForward(); |
| 104 FinishLoopTree(); | 74 FinishLoopTree(); |
| 105 } | 75 } |
| 106 | 76 |
| 107 void Print() { | 77 void Print() { |
| 108 // Print out the results. | 78 // Print out the results. |
| 109 for (NodeInfo& ni : info_) { | 79 for (NodeInfo& ni : info_) { |
| 110 if (ni.node == nullptr) continue; | 80 if (ni.node == nullptr) continue; |
| 111 for (size_t i = 1; i <= loops_.size(); i++) { | 81 for (int i = 1; i <= loops_found_; i++) { |
| 112 if (ni.IsInLoop(i)) { | 82 int index = ni.node->id() * width_ + INDEX(i); |
| 83 bool marked_forward = forward_[index] & BIT(i); |
| 84 bool marked_backward = backward_[index] & BIT(i); |
| 85 if (marked_forward && marked_backward) { |
| 113 PrintF("X"); | 86 PrintF("X"); |
| 114 } else if (ni.forward & (1 << i)) { | 87 } else if (marked_forward) { |
| 115 PrintF("/"); | 88 PrintF("/"); |
| 116 } else if (ni.backward & (1 << i)) { | 89 } else if (marked_backward) { |
| 117 PrintF("\\"); | 90 PrintF("\\"); |
| 118 } else { | 91 } else { |
| 119 PrintF(" "); | 92 PrintF(" "); |
| 120 } | 93 } |
| 121 } | 94 } |
| 122 PrintF(" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic()); | 95 PrintF(" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic()); |
| 123 } | 96 } |
| 124 | 97 |
| 125 int i = 0; | 98 int i = 0; |
| 126 for (LoopInfo& li : loops_) { | 99 for (LoopInfo& li : loops_) { |
| 127 PrintF("Loop %d headed at #%d\n", i, li.header->id()); | 100 PrintF("Loop %d headed at #%d\n", i, li.header->id()); |
| 128 i++; | 101 i++; |
| 129 } | 102 } |
| 130 | 103 |
| 131 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { | 104 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { |
| 132 PrintLoop(loop); | 105 PrintLoop(loop); |
| 133 } | 106 } |
| 134 } | 107 } |
| 135 | 108 |
| 136 private: | 109 private: |
| 110 Zone* zone_; |
| 137 Node* end_; | 111 Node* end_; |
| 138 NodeDeque queue_; | 112 NodeDeque queue_; |
| 139 NodeMarker<bool> queued_; | 113 NodeMarker<bool> queued_; |
| 140 ZoneVector<NodeInfo> info_; | 114 ZoneVector<NodeInfo> info_; |
| 141 ZoneVector<LoopInfo> loops_; | 115 ZoneVector<LoopInfo> loops_; |
| 116 ZoneVector<int> loop_num_; |
| 142 LoopTree* loop_tree_; | 117 LoopTree* loop_tree_; |
| 143 size_t loops_found_; | 118 int loops_found_; |
| 119 int width_; |
| 120 uint32_t* backward_; |
| 121 uint32_t* forward_; |
| 122 |
| 123 int num_nodes() { |
| 124 return static_cast<int>(loop_tree_->node_to_loop_num_.size()); |
| 125 } |
| 126 |
| 127 // Tb = Tb | (Fb - loop_filter) |
| 128 bool PropagateBackwardMarks(Node* from, Node* to, int loop_filter) { |
| 129 if (from == to) return false; |
| 130 uint32_t* fp = &backward_[from->id() * width_]; |
| 131 uint32_t* tp = &backward_[to->id() * width_]; |
| 132 bool change = false; |
| 133 for (int i = 0; i < width_; i++) { |
| 134 uint32_t mask = i == INDEX(loop_filter) ? ~BIT(loop_filter) : 0xFFFFFFFF; |
| 135 uint32_t prev = tp[i]; |
| 136 uint32_t next = prev | (fp[i] & mask); |
| 137 tp[i] = next; |
| 138 if (!change && (prev != next)) change = true; |
| 139 } |
| 140 return change; |
| 141 } |
| 142 |
| 143 // Tb = Tb | B |
| 144 bool SetBackwardMark(Node* to, int loop_num) { |
| 145 uint32_t* tp = &backward_[to->id() * width_ + INDEX(loop_num)]; |
| 146 uint32_t prev = tp[0]; |
| 147 uint32_t next = prev | BIT(loop_num); |
| 148 tp[0] = next; |
| 149 return next != prev; |
| 150 } |
| 151 |
| 152 // Tf = Tf | B |
| 153 bool SetForwardMark(Node* to, int loop_num) { |
| 154 uint32_t* tp = &forward_[to->id() * width_ + INDEX(loop_num)]; |
| 155 uint32_t prev = tp[0]; |
| 156 uint32_t next = prev | BIT(loop_num); |
| 157 tp[0] = next; |
| 158 return next != prev; |
| 159 } |
| 160 |
| 161 // Tf = Tf | (Ff & Tb) |
| 162 bool PropagateForwardMarks(Node* from, Node* to) { |
| 163 if (from == to) return false; |
| 164 bool change = false; |
| 165 int findex = from->id() * width_; |
| 166 int tindex = to->id() * width_; |
| 167 for (int i = 0; i < width_; i++) { |
| 168 uint32_t marks = backward_[tindex + i] & forward_[findex + i]; |
| 169 uint32_t prev = forward_[tindex + i]; |
| 170 uint32_t next = prev | marks; |
| 171 forward_[tindex + i] = next; |
| 172 if (!change && (prev != next)) change = true; |
| 173 } |
| 174 return change; |
| 175 } |
| 176 |
| 177 bool IsInLoop(Node* node, int loop_num) { |
| 178 int offset = node->id() * width_ + INDEX(loop_num); |
| 179 return backward_[offset] & forward_[offset] & BIT(loop_num); |
| 180 } |
| 144 | 181 |
| 145 // Propagate marks backward from loop headers. | 182 // Propagate marks backward from loop headers. |
| 146 void PropagateBackward() { | 183 void PropagateBackward() { |
| 147 PropagateBackward(end_, kVisited); | 184 ResizeBackwardMarks(); |
| 185 SetBackwardMark(end_, 0); |
| 186 Queue(end_); |
| 148 | 187 |
| 149 while (!queue_.empty()) { | 188 while (!queue_.empty()) { |
| 150 Node* node = queue_.front(); | 189 Node* node = queue_.front(); |
| 190 info(node); |
| 151 queue_.pop_front(); | 191 queue_.pop_front(); |
| 152 queued_.Set(node, false); | 192 queued_.Set(node, false); |
| 153 | 193 |
| 194 int loop_num = -1; |
| 154 // Setup loop headers first. | 195 // Setup loop headers first. |
| 155 NodeInfo& ni = info(node); | |
| 156 if (node->opcode() == IrOpcode::kLoop) { | 196 if (node->opcode() == IrOpcode::kLoop) { |
| 157 // found the loop node first. | 197 // found the loop node first. |
| 158 CreateLoopInfo(node, ni); | 198 loop_num = CreateLoopInfo(node); |
| 159 } else if (node->opcode() == IrOpcode::kPhi || | 199 } else if (node->opcode() == IrOpcode::kPhi || |
| 160 node->opcode() == IrOpcode::kEffectPhi) { | 200 node->opcode() == IrOpcode::kEffectPhi) { |
| 161 // found a phi first. | 201 // found a phi first. |
| 162 Node* merge = node->InputAt(node->InputCount() - 1); | 202 Node* merge = node->InputAt(node->InputCount() - 1); |
| 163 if (merge->opcode() == IrOpcode::kLoop) { | 203 if (merge->opcode() == IrOpcode::kLoop) { |
| 164 NodeInfo& mi = info(merge); | 204 loop_num = CreateLoopInfo(merge); |
| 165 CreateLoopInfo(merge, mi); | |
| 166 ni.MarkBackward(mi.loop_mark); | |
| 167 } | 205 } |
| 168 } | 206 } |
| 169 | 207 |
| 170 // Propagate reachability marks backwards from this node. | 208 // Propagate marks backwards from this node. |
| 171 if (ni.IsLoopHeader()) { | 209 for (int i = 0; i < node->InputCount(); i++) { |
| 172 // Handle edges from loop header nodes specially. | 210 Node* input = node->InputAt(i); |
| 173 for (int i = 0; i < node->InputCount(); i++) { | 211 if (loop_num > 0 && i != kAssumedLoopEntryIndex) { |
| 174 if (i == kAssumedLoopEntryIndex) { | 212 // Only propagate the loop mark on backedges. |
| 175 // Don't propagate the loop mark backwards on the entry edge. | 213 if (SetBackwardMark(input, loop_num)) Queue(input); |
| 176 PropagateBackward(node->InputAt(0), | 214 } else { |
| 177 kVisited | (ni.backward & ~ni.loop_mark)); | 215 // Entry or normal edge. Propagate all marks except loop_num. |
| 178 } else { | 216 if (PropagateBackwardMarks(node, input, loop_num)) Queue(input); |
| 179 // Only propagate the loop mark on backedges. | |
| 180 PropagateBackward(node->InputAt(i), ni.loop_mark); | |
| 181 } | |
| 182 } | |
| 183 } else { | |
| 184 // Propagate all loop marks backwards for a normal node. | |
| 185 for (Node* const input : node->inputs()) { | |
| 186 PropagateBackward(input, ni.backward); | |
| 187 } | 217 } |
| 188 } | 218 } |
| 189 } | 219 } |
| 190 } | 220 } |
| 191 | 221 |
| 192 // Make a new loop header for the given node. | 222 // Make a new loop if necessary for the given node. |
| 193 void CreateLoopInfo(Node* node, NodeInfo& ni) { | 223 int CreateLoopInfo(Node* node) { |
| 194 if (ni.IsLoopHeader()) return; // loop already set up. | 224 int loop_num = LoopNum(node); |
| 225 if (loop_num > 0) return loop_num; |
| 195 | 226 |
| 196 loops_found_++; | 227 loop_num = ++loops_found_; |
| 197 size_t loop_num = loops_.size() + 1; | 228 if (INDEX(loop_num) >= width_) ResizeBackwardMarks(); |
| 198 CHECK(loops_found_ <= kMaxLoops); // TODO(titzer): don't crash. | 229 |
| 199 // Create a new loop. | 230 // Create a new loop. |
| 200 loops_.push_back({node, nullptr, nullptr, nullptr}); | 231 loops_.push_back({node, nullptr, nullptr, nullptr}); |
| 201 loop_tree_->NewLoop(); | 232 loop_tree_->NewLoop(); |
| 202 LoopMarks loop_mark = kVisited | (1 << loop_num); | 233 SetBackwardMark(node, loop_num); |
| 203 ni.loop_mark = loop_mark; | 234 loop_tree_->node_to_loop_num_[node->id()] = loop_num; |
| 204 | 235 |
| 205 // Setup loop mark for phis attached to loop header. | 236 // Setup loop mark for phis attached to loop header. |
| 206 for (Node* use : node->uses()) { | 237 for (Node* use : node->uses()) { |
| 207 if (use->opcode() == IrOpcode::kPhi || | 238 if (use->opcode() == IrOpcode::kPhi || |
| 208 use->opcode() == IrOpcode::kEffectPhi) { | 239 use->opcode() == IrOpcode::kEffectPhi) { |
| 209 info(use).loop_mark = loop_mark; | 240 SetBackwardMark(use, loop_num); |
| 241 loop_tree_->node_to_loop_num_[use->id()] = loop_num; |
| 210 } | 242 } |
| 211 } | 243 } |
| 244 |
| 245 return loop_num; |
| 246 } |
| 247 |
| 248 void ResizeBackwardMarks() { |
| 249 int new_width = width_ + 1; |
| 250 int max = num_nodes(); |
| 251 uint32_t* new_backward = zone_->NewArray<uint32_t>(new_width * max); |
| 252 memset(new_backward, 0, new_width * max * sizeof(uint32_t)); |
| 253 if (width_ > 0) { // copy old matrix data. |
| 254 for (int i = 0; i < max; i++) { |
| 255 uint32_t* np = &new_backward[i * new_width]; |
| 256 uint32_t* op = &backward_[i * width_]; |
| 257 for (int j = 0; j < width_; j++) np[j] = op[j]; |
| 258 } |
| 259 } |
| 260 width_ = new_width; |
| 261 backward_ = new_backward; |
| 262 } |
| 263 |
| 264 void ResizeForwardMarks() { |
| 265 int max = num_nodes(); |
| 266 forward_ = zone_->NewArray<uint32_t>(width_ * max); |
| 267 memset(forward_, 0, width_ * max * sizeof(uint32_t)); |
| 212 } | 268 } |
| 213 | 269 |
| 214 // Propagate marks forward from loops. | 270 // Propagate marks forward from loops. |
| 215 void PropagateForward() { | 271 void PropagateForward() { |
| 272 ResizeForwardMarks(); |
| 216 for (LoopInfo& li : loops_) { | 273 for (LoopInfo& li : loops_) { |
| 217 queued_.Set(li.header, true); | 274 SetForwardMark(li.header, LoopNum(li.header)); |
| 218 queue_.push_back(li.header); | 275 Queue(li.header); |
| 219 NodeInfo& ni = info(li.header); | |
| 220 ni.forward = ni.loop_mark; | |
| 221 } | 276 } |
| 222 // Propagate forward on paths that were backward reachable from backedges. | 277 // Propagate forward on paths that were backward reachable from backedges. |
| 223 while (!queue_.empty()) { | 278 while (!queue_.empty()) { |
| 224 Node* node = queue_.front(); | 279 Node* node = queue_.front(); |
| 225 queue_.pop_front(); | 280 queue_.pop_front(); |
| 226 queued_.Set(node, false); | 281 queued_.Set(node, false); |
| 227 NodeInfo& ni = info(node); | |
| 228 for (Edge edge : node->use_edges()) { | 282 for (Edge edge : node->use_edges()) { |
| 229 Node* use = edge.from(); | 283 Node* use = edge.from(); |
| 230 NodeInfo& ui = info(use); | 284 if (!IsBackedge(use, edge)) { |
| 231 if (IsBackedge(use, ui, edge)) continue; // skip backedges. | 285 if (PropagateForwardMarks(node, use)) Queue(use); |
| 232 LoopMarks both = ni.forward & ui.backward; | |
| 233 if (ui.MarkForward(both) && !queued_.Get(use)) { | |
| 234 queued_.Set(use, true); | |
| 235 queue_.push_back(use); | |
| 236 } | 286 } |
| 237 } | 287 } |
| 238 } | 288 } |
| 239 } | 289 } |
| 240 | 290 |
| 241 bool IsBackedge(Node* use, NodeInfo& ui, Edge& edge) { | 291 bool IsBackedge(Node* use, Edge& edge) { |
| 242 // TODO(titzer): checking for backedges here is ugly. | 292 if (LoopNum(use) <= 0) return false; |
| 243 if (!ui.IsLoopHeader()) return false; | |
| 244 if (edge.index() == kAssumedLoopEntryIndex) return false; | 293 if (edge.index() == kAssumedLoopEntryIndex) return false; |
| 245 if (use->opcode() == IrOpcode::kPhi || | 294 if (use->opcode() == IrOpcode::kPhi || |
| 246 use->opcode() == IrOpcode::kEffectPhi) { | 295 use->opcode() == IrOpcode::kEffectPhi) { |
| 247 return !NodeProperties::IsControlEdge(edge); | 296 return !NodeProperties::IsControlEdge(edge); |
| 248 } | 297 } |
| 249 return true; | 298 return true; |
| 250 } | 299 } |
| 251 | 300 |
| 301 int LoopNum(Node* node) { return loop_tree_->node_to_loop_num_[node->id()]; } |
| 302 |
| 252 NodeInfo& info(Node* node) { | 303 NodeInfo& info(Node* node) { |
| 253 NodeInfo& i = info_[node->id()]; | 304 NodeInfo& i = info_[node->id()]; |
| 254 if (i.node == nullptr) i.node = node; | 305 if (i.node == nullptr) i.node = node; |
| 255 return i; | 306 return i; |
| 256 } | 307 } |
| 257 | 308 |
| 258 void PropagateBackward(Node* node, LoopMarks marks) { | 309 void Queue(Node* node) { |
| 259 if (info(node).MarkBackward(marks) && !queued_.Get(node)) { | 310 if (!queued_.Get(node)) { |
| 260 queue_.push_back(node); | 311 queue_.push_back(node); |
| 261 queued_.Set(node, true); | 312 queued_.Set(node, true); |
| 262 } | 313 } |
| 263 } | 314 } |
| 264 | 315 |
| 265 void FinishLoopTree() { | 316 void FinishLoopTree() { |
| 317 DCHECK(loops_found_ == static_cast<int>(loops_.size())); |
| 318 DCHECK(loops_found_ == static_cast<int>(loop_tree_->all_loops_.size())); |
| 319 |
| 266 // Degenerate cases. | 320 // Degenerate cases. |
| 267 if (loops_.size() == 0) return; | 321 if (loops_found_ == 0) return; |
| 268 if (loops_.size() == 1) return FinishSingleLoop(); | 322 if (loops_found_ == 1) return FinishSingleLoop(); |
| 269 | 323 |
| 270 for (size_t i = 1; i <= loops_.size(); i++) ConnectLoopTree(i); | 324 for (int i = 1; i <= loops_found_; i++) ConnectLoopTree(i); |
| 271 | 325 |
| 272 size_t count = 0; | 326 size_t count = 0; |
| 273 // Place the node into the innermost nested loop of which it is a member. | 327 // Place the node into the innermost nested loop of which it is a member. |
| 274 for (NodeInfo& ni : info_) { | 328 for (NodeInfo& ni : info_) { |
| 275 if (ni.node == nullptr || !ni.IsInAnyLoop()) continue; | 329 if (ni.node == nullptr) continue; |
| 276 | 330 |
| 277 LoopInfo* innermost = nullptr; | 331 LoopInfo* innermost = nullptr; |
| 278 size_t index = 0; | 332 int innermost_index = 0; |
| 279 for (size_t i = 1; i <= loops_.size(); i++) { | 333 int pos = ni.node->id() * width_; |
| 280 if (ni.IsInLoop(i)) { | 334 // Search the marks word by word. |
| 281 LoopInfo* loop = &loops_[i - 1]; | 335 for (int i = 0; i < width_; i++) { |
| 282 if (innermost == nullptr || | 336 uint32_t marks = backward_[pos + i] & forward_[pos + i]; |
| 283 loop->loop->depth_ > innermost->loop->depth_) { | 337 for (int j = 0; j < 32; j++) { |
| 284 innermost = loop; | 338 if (marks & (1u << j)) { |
| 285 index = i; | 339 int loop_num = i * 32 + j; |
| 340 if (loop_num == 0) continue; |
| 341 LoopInfo* loop = &loops_[loop_num - 1]; |
| 342 if (innermost == nullptr || |
| 343 loop->loop->depth_ > innermost->loop->depth_) { |
| 344 innermost = loop; |
| 345 innermost_index = loop_num; |
| 346 } |
| 286 } | 347 } |
| 287 } | 348 } |
| 288 } | 349 } |
| 289 if (ni.IsInHeaderForLoop(index)) { | 350 if (innermost == nullptr) continue; |
| 351 if (LoopNum(ni.node) == innermost_index) { |
| 290 ni.next = innermost->header_list; | 352 ni.next = innermost->header_list; |
| 291 innermost->header_list = ∋ | 353 innermost->header_list = ∋ |
| 292 } else { | 354 } else { |
| 293 ni.next = innermost->body_list; | 355 ni.next = innermost->body_list; |
| 294 innermost->body_list = ∋ | 356 innermost->body_list = ∋ |
| 295 } | 357 } |
| 296 count++; | 358 count++; |
| 297 } | 359 } |
| 298 | 360 |
| 299 // Serialize the node lists for loops into the loop tree. | 361 // Serialize the node lists for loops into the loop tree. |
| 300 loop_tree_->loop_nodes_.reserve(count); | 362 loop_tree_->loop_nodes_.reserve(count); |
| 301 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { | 363 for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { |
| 302 SerializeLoop(loop); | 364 SerializeLoop(loop); |
| 303 } | 365 } |
| 304 } | 366 } |
| 305 | 367 |
| 306 // Handle the simpler case of a single loop (no checks for nesting necessary). | 368 // Handle the simpler case of a single loop (no checks for nesting necessary). |
| 307 void FinishSingleLoop() { | 369 void FinishSingleLoop() { |
| 308 DCHECK(loops_.size() == 1); | |
| 309 DCHECK(loop_tree_->all_loops_.size() == 1); | |
| 310 | |
| 311 // Place nodes into the loop header and body. | 370 // Place nodes into the loop header and body. |
| 312 LoopInfo* li = &loops_[0]; | 371 LoopInfo* li = &loops_[0]; |
| 313 li->loop = &loop_tree_->all_loops_[0]; | 372 li->loop = &loop_tree_->all_loops_[0]; |
| 314 loop_tree_->SetParent(nullptr, li->loop); | 373 loop_tree_->SetParent(nullptr, li->loop); |
| 315 size_t count = 0; | 374 size_t count = 0; |
| 316 for (NodeInfo& ni : info_) { | 375 for (NodeInfo& ni : info_) { |
| 317 if (ni.node == nullptr || !ni.IsInAnyLoop()) continue; | 376 if (ni.node == nullptr || !IsInLoop(ni.node, 1)) continue; |
| 318 DCHECK(ni.IsInLoop(1)); | 377 if (LoopNum(ni.node) == 1) { |
| 319 if (ni.IsInHeaderForLoop(1)) { | |
| 320 ni.next = li->header_list; | 378 ni.next = li->header_list; |
| 321 li->header_list = ∋ | 379 li->header_list = ∋ |
| 322 } else { | 380 } else { |
| 323 ni.next = li->body_list; | 381 ni.next = li->body_list; |
| 324 li->body_list = ∋ | 382 li->body_list = ∋ |
| 325 } | 383 } |
| 326 count++; | 384 count++; |
| 327 } | 385 } |
| 328 | 386 |
| 329 // Serialize the node lists for the loop into the loop tree. | 387 // Serialize the node lists for the loop into the loop tree. |
| 330 loop_tree_->loop_nodes_.reserve(count); | 388 loop_tree_->loop_nodes_.reserve(count); |
| 331 SerializeLoop(li->loop); | 389 SerializeLoop(li->loop); |
| 332 } | 390 } |
| 333 | 391 |
| 334 // Recursively serialize the list of header nodes and body nodes | 392 // Recursively serialize the list of header nodes and body nodes |
| 335 // so that nested loops occupy nested intervals. | 393 // so that nested loops occupy nested intervals. |
| 336 void SerializeLoop(LoopTree::Loop* loop) { | 394 void SerializeLoop(LoopTree::Loop* loop) { |
| 337 size_t loop_num = loop_tree_->LoopNum(loop); | 395 int loop_num = loop_tree_->LoopNum(loop); |
| 338 LoopInfo& li = loops_[loop_num - 1]; | 396 LoopInfo& li = loops_[loop_num - 1]; |
| 339 | 397 |
| 340 // Serialize the header. | 398 // Serialize the header. |
| 341 loop->header_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); | 399 loop->header_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); |
| 342 for (NodeInfo* ni = li.header_list; ni != nullptr; ni = ni->next) { | 400 for (NodeInfo* ni = li.header_list; ni != nullptr; ni = ni->next) { |
| 343 loop_tree_->loop_nodes_.push_back(ni->node); | 401 loop_tree_->loop_nodes_.push_back(ni->node); |
| 344 // TODO(titzer): lift loop count restriction. | 402 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num; |
| 345 loop_tree_->node_to_loop_num_[ni->node->id()] = | |
| 346 static_cast<uint8_t>(loop_num); | |
| 347 } | 403 } |
| 348 | 404 |
| 349 // Serialize the body. | 405 // Serialize the body. |
| 350 loop->body_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); | 406 loop->body_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); |
| 351 for (NodeInfo* ni = li.body_list; ni != nullptr; ni = ni->next) { | 407 for (NodeInfo* ni = li.body_list; ni != nullptr; ni = ni->next) { |
| 352 loop_tree_->loop_nodes_.push_back(ni->node); | 408 loop_tree_->loop_nodes_.push_back(ni->node); |
| 353 // TODO(titzer): lift loop count restriction. | 409 loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num; |
| 354 loop_tree_->node_to_loop_num_[ni->node->id()] = | |
| 355 static_cast<uint8_t>(loop_num); | |
| 356 } | 410 } |
| 357 | 411 |
| 358 // Serialize nested loops. | 412 // Serialize nested loops. |
| 359 for (LoopTree::Loop* child : loop->children_) SerializeLoop(child); | 413 for (LoopTree::Loop* child : loop->children_) SerializeLoop(child); |
| 360 | 414 |
| 361 loop->body_end_ = static_cast<int>(loop_tree_->loop_nodes_.size()); | 415 loop->body_end_ = static_cast<int>(loop_tree_->loop_nodes_.size()); |
| 362 } | 416 } |
| 363 | 417 |
| 364 // Connect the LoopTree loops to their parents recursively. | 418 // Connect the LoopTree loops to their parents recursively. |
| 365 LoopTree::Loop* ConnectLoopTree(size_t loop_num) { | 419 LoopTree::Loop* ConnectLoopTree(int loop_num) { |
| 366 LoopInfo& li = loops_[loop_num - 1]; | 420 LoopInfo& li = loops_[loop_num - 1]; |
| 367 if (li.loop != nullptr) return li.loop; | 421 if (li.loop != nullptr) return li.loop; |
| 368 | 422 |
| 369 NodeInfo& ni = info(li.header); | 423 NodeInfo& ni = info(li.header); |
| 370 LoopTree::Loop* parent = nullptr; | 424 LoopTree::Loop* parent = nullptr; |
| 371 for (size_t i = 1; i <= loops_.size(); i++) { | 425 for (int i = 1; i <= loops_found_; i++) { |
| 372 if (i == loop_num) continue; | 426 if (i == loop_num) continue; |
| 373 if (ni.IsInLoop(i)) { | 427 if (IsInLoop(ni.node, i)) { |
| 374 // recursively create potential parent loops first. | 428 // recursively create potential parent loops first. |
| 375 LoopTree::Loop* upper = ConnectLoopTree(i); | 429 LoopTree::Loop* upper = ConnectLoopTree(i); |
| 376 if (parent == nullptr || upper->depth_ > parent->depth_) { | 430 if (parent == nullptr || upper->depth_ > parent->depth_) { |
| 377 parent = upper; | 431 parent = upper; |
| 378 } | 432 } |
| 379 } | 433 } |
| 380 } | 434 } |
| 381 li.loop = &loop_tree_->all_loops_[loop_num - 1]; | 435 li.loop = &loop_tree_->all_loops_[loop_num - 1]; |
| 382 loop_tree_->SetParent(parent, li.loop); | 436 loop_tree_->SetParent(parent, li.loop); |
| 383 return li.loop; | 437 return li.loop; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 406 finder.Run(); | 460 finder.Run(); |
| 407 if (FLAG_trace_turbo_graph) { | 461 if (FLAG_trace_turbo_graph) { |
| 408 finder.Print(); | 462 finder.Print(); |
| 409 } | 463 } |
| 410 return loop_tree; | 464 return loop_tree; |
| 411 } | 465 } |
| 412 | 466 |
| 413 } // namespace compiler | 467 } // namespace compiler |
| 414 } // namespace internal | 468 } // namespace internal |
| 415 } // namespace v8 | 469 } // namespace v8 |
| OLD | NEW |