PageRenderTime 67ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/deps/v8/src/compiler/loop-analysis.cc

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