11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_COMPILER_CONTROL_EQUIVALENCE_H_ 61cb0ef41Sopenharmony_ci#define V8_COMPILER_CONTROL_EQUIVALENCE_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "src/base/compiler-specific.h" 91cb0ef41Sopenharmony_ci#include "src/common/globals.h" 101cb0ef41Sopenharmony_ci#include "src/compiler/graph.h" 111cb0ef41Sopenharmony_ci#include "src/compiler/node.h" 121cb0ef41Sopenharmony_ci#include "src/zone/zone-containers.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_cinamespace compiler { 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci// Determines control dependence equivalence classes for control nodes. Any two 191cb0ef41Sopenharmony_ci// nodes having the same set of control dependences land in one class. These 201cb0ef41Sopenharmony_ci// classes can in turn be used to: 211cb0ef41Sopenharmony_ci// - Build a program structure tree (PST) for controls in the graph. 221cb0ef41Sopenharmony_ci// - Determine single-entry single-exit (SESE) regions within the graph. 231cb0ef41Sopenharmony_ci// 241cb0ef41Sopenharmony_ci// Note that this implementation actually uses cycle equivalence to establish 251cb0ef41Sopenharmony_ci// class numbers. Any two nodes are cycle equivalent if they occur in the same 261cb0ef41Sopenharmony_ci// set of cycles. It can be shown that control dependence equivalence reduces 271cb0ef41Sopenharmony_ci// to undirected cycle equivalence for strongly connected control flow graphs. 281cb0ef41Sopenharmony_ci// 291cb0ef41Sopenharmony_ci// The algorithm is based on the paper, "The program structure tree: computing 301cb0ef41Sopenharmony_ci// control regions in linear time" by Johnson, Pearson & Pingali (PLDI94) which 311cb0ef41Sopenharmony_ci// also contains proofs for the aforementioned equivalence. References to line 321cb0ef41Sopenharmony_ci// numbers in the algorithm from figure 4 have been added [line:x]. 331cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE ControlEquivalence final 341cb0ef41Sopenharmony_ci : public NON_EXPORTED_BASE(ZoneObject) { 351cb0ef41Sopenharmony_ci public: 361cb0ef41Sopenharmony_ci ControlEquivalence(Zone* zone, Graph* graph) 371cb0ef41Sopenharmony_ci : zone_(zone), 381cb0ef41Sopenharmony_ci graph_(graph), 391cb0ef41Sopenharmony_ci dfs_number_(0), 401cb0ef41Sopenharmony_ci class_number_(1), 411cb0ef41Sopenharmony_ci node_data_(graph->NodeCount(), zone) {} 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci // Run the main algorithm starting from the {exit} control node. This causes 441cb0ef41Sopenharmony_ci // the following iterations over control edges of the graph: 451cb0ef41Sopenharmony_ci // 1) A breadth-first backwards traversal to determine the set of nodes that 461cb0ef41Sopenharmony_ci // participate in the next step. Takes O(E) time and O(N) space. 471cb0ef41Sopenharmony_ci // 2) An undirected depth-first backwards traversal that determines class 481cb0ef41Sopenharmony_ci // numbers for all participating nodes. Takes O(E) time and O(N) space. 491cb0ef41Sopenharmony_ci void Run(Node* exit); 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci // Retrieves a previously computed class number. 521cb0ef41Sopenharmony_ci size_t ClassOf(Node* node) { 531cb0ef41Sopenharmony_ci DCHECK_NE(kInvalidClass, GetClass(node)); 541cb0ef41Sopenharmony_ci return GetClass(node); 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci private: 581cb0ef41Sopenharmony_ci static const size_t kInvalidClass = static_cast<size_t>(-1); 591cb0ef41Sopenharmony_ci enum DFSDirection { kInputDirection, kUseDirection }; 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci struct Bracket { 621cb0ef41Sopenharmony_ci DFSDirection direction; // Direction in which this bracket was added. 631cb0ef41Sopenharmony_ci size_t recent_class; // Cached class when bracket was topmost. 641cb0ef41Sopenharmony_ci size_t recent_size; // Cached set-size when bracket was topmost. 651cb0ef41Sopenharmony_ci Node* from; // Node that this bracket originates from. 661cb0ef41Sopenharmony_ci Node* to; // Node that this bracket points to. 671cb0ef41Sopenharmony_ci }; 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci // The set of brackets for each node during the DFS walk. 701cb0ef41Sopenharmony_ci using BracketList = ZoneLinkedList<Bracket>; 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci struct DFSStackEntry { 731cb0ef41Sopenharmony_ci DFSDirection direction; // Direction currently used in DFS walk. 741cb0ef41Sopenharmony_ci Node::InputEdges::iterator input; // Iterator used for "input" direction. 751cb0ef41Sopenharmony_ci Node::UseEdges::iterator use; // Iterator used for "use" direction. 761cb0ef41Sopenharmony_ci Node* parent_node; // Parent node of entry during DFS walk. 771cb0ef41Sopenharmony_ci Node* node; // Node that this stack entry belongs to. 781cb0ef41Sopenharmony_ci }; 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci // The stack is used during the undirected DFS walk. 811cb0ef41Sopenharmony_ci using DFSStack = ZoneStack<DFSStackEntry>; 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci struct NodeData : ZoneObject { 841cb0ef41Sopenharmony_ci explicit NodeData(Zone* zone) 851cb0ef41Sopenharmony_ci : class_number(kInvalidClass), 861cb0ef41Sopenharmony_ci blist(BracketList(zone)), 871cb0ef41Sopenharmony_ci visited(false), 881cb0ef41Sopenharmony_ci on_stack(false) {} 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci size_t class_number; // Equivalence class number assigned to node. 911cb0ef41Sopenharmony_ci BracketList blist; // List of brackets per node. 921cb0ef41Sopenharmony_ci bool visited : 1; // Indicates node has already been visited. 931cb0ef41Sopenharmony_ci bool on_stack : 1; // Indicates node is on DFS stack during walk. 941cb0ef41Sopenharmony_ci }; 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci // The per-node data computed during the DFS walk. 971cb0ef41Sopenharmony_ci using Data = ZoneVector<NodeData*>; 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci // Called at pre-visit during DFS walk. 1001cb0ef41Sopenharmony_ci void VisitPre(Node* node); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci // Called at mid-visit during DFS walk. 1031cb0ef41Sopenharmony_ci void VisitMid(Node* node, DFSDirection direction); 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci // Called at post-visit during DFS walk. 1061cb0ef41Sopenharmony_ci void VisitPost(Node* node, Node* parent_node, DFSDirection direction); 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci // Called when hitting a back edge in the DFS walk. 1091cb0ef41Sopenharmony_ci void VisitBackedge(Node* from, Node* to, DFSDirection direction); 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci // Performs and undirected DFS walk of the graph. Conceptually all nodes are 1121cb0ef41Sopenharmony_ci // expanded, splitting "input" and "use" out into separate nodes. During the 1131cb0ef41Sopenharmony_ci // traversal, edges towards the representative nodes are preferred. 1141cb0ef41Sopenharmony_ci // 1151cb0ef41Sopenharmony_ci // \ / - Pre-visit: When N1 is visited in direction D the preferred 1161cb0ef41Sopenharmony_ci // x N1 edge towards N is taken next, calling VisitPre(N). 1171cb0ef41Sopenharmony_ci // | - Mid-visit: After all edges out of N2 in direction D have 1181cb0ef41Sopenharmony_ci // | N been visited, we switch the direction and start considering 1191cb0ef41Sopenharmony_ci // | edges out of N1 now, and we call VisitMid(N). 1201cb0ef41Sopenharmony_ci // x N2 - Post-visit: After all edges out of N1 in direction opposite 1211cb0ef41Sopenharmony_ci // / \ to D have been visited, we pop N and call VisitPost(N). 1221cb0ef41Sopenharmony_ci // 1231cb0ef41Sopenharmony_ci // This will yield a true spanning tree (without cross or forward edges) and 1241cb0ef41Sopenharmony_ci // also discover proper back edges in both directions. 1251cb0ef41Sopenharmony_ci void RunUndirectedDFS(Node* exit); 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci void DetermineParticipationEnqueue(ZoneQueue<Node*>& queue, Node* node); 1281cb0ef41Sopenharmony_ci void DetermineParticipation(Node* exit); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci private: 1311cb0ef41Sopenharmony_ci NodeData* GetData(Node* node) { 1321cb0ef41Sopenharmony_ci size_t const index = node->id(); 1331cb0ef41Sopenharmony_ci if (index >= node_data_.size()) node_data_.resize(index + 1); 1341cb0ef41Sopenharmony_ci return node_data_[index]; 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci void AllocateData(Node* node) { 1371cb0ef41Sopenharmony_ci size_t const index = node->id(); 1381cb0ef41Sopenharmony_ci if (index >= node_data_.size()) node_data_.resize(index + 1); 1391cb0ef41Sopenharmony_ci node_data_[index] = zone_->New<NodeData>(zone_); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci int NewClassNumber() { return class_number_++; } 1431cb0ef41Sopenharmony_ci int NewDFSNumber() { return dfs_number_++; } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci bool Participates(Node* node) { return GetData(node) != nullptr; } 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci // Accessors for the equivalence class stored within the per-node data. 1481cb0ef41Sopenharmony_ci size_t GetClass(Node* node) { return GetData(node)->class_number; } 1491cb0ef41Sopenharmony_ci void SetClass(Node* node, size_t number) { 1501cb0ef41Sopenharmony_ci DCHECK(Participates(node)); 1511cb0ef41Sopenharmony_ci GetData(node)->class_number = number; 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci // Accessors for the bracket list stored within the per-node data. 1551cb0ef41Sopenharmony_ci BracketList& GetBracketList(Node* node) { 1561cb0ef41Sopenharmony_ci DCHECK(Participates(node)); 1571cb0ef41Sopenharmony_ci return GetData(node)->blist; 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci void SetBracketList(Node* node, BracketList& list) { 1601cb0ef41Sopenharmony_ci DCHECK(Participates(node)); 1611cb0ef41Sopenharmony_ci GetData(node)->blist = list; 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci // Mutates the DFS stack by pushing an entry. 1651cb0ef41Sopenharmony_ci void DFSPush(DFSStack& stack, Node* node, Node* from, DFSDirection dir); 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci // Mutates the DFS stack by popping an entry. 1681cb0ef41Sopenharmony_ci void DFSPop(DFSStack& stack, Node* node); 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci void BracketListDelete(BracketList& blist, Node* to, DFSDirection direction); 1711cb0ef41Sopenharmony_ci void BracketListTRACE(BracketList& blist); 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci Zone* const zone_; 1741cb0ef41Sopenharmony_ci Graph* const graph_; 1751cb0ef41Sopenharmony_ci int dfs_number_; // Generates new DFS pre-order numbers on demand. 1761cb0ef41Sopenharmony_ci int class_number_; // Generates new equivalence class numbers on demand. 1771cb0ef41Sopenharmony_ci Data node_data_; // Per-node data stored as a side-table. 1781cb0ef41Sopenharmony_ci}; 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci} // namespace compiler 1811cb0ef41Sopenharmony_ci} // namespace internal 1821cb0ef41Sopenharmony_ci} // namespace v8 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci#endif // V8_COMPILER_CONTROL_EQUIVALENCE_H_ 185