11cb0ef41Sopenharmony_ci// Copyright 2015 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#include "src/compiler/control-equivalence.h"
61cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h"
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#define TRACE(...)                                 \
91cb0ef41Sopenharmony_ci  do {                                             \
101cb0ef41Sopenharmony_ci    if (FLAG_trace_turbo_ceq) PrintF(__VA_ARGS__); \
111cb0ef41Sopenharmony_ci  } while (false)
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cinamespace v8 {
141cb0ef41Sopenharmony_cinamespace internal {
151cb0ef41Sopenharmony_cinamespace compiler {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_civoid ControlEquivalence::Run(Node* exit) {
181cb0ef41Sopenharmony_ci  if (!Participates(exit) || GetClass(exit) == kInvalidClass) {
191cb0ef41Sopenharmony_ci    DetermineParticipation(exit);
201cb0ef41Sopenharmony_ci    RunUndirectedDFS(exit);
211cb0ef41Sopenharmony_ci  }
221cb0ef41Sopenharmony_ci}
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// static
261cb0ef41Sopenharmony_ciSTATIC_CONST_MEMBER_DEFINITION const size_t ControlEquivalence::kInvalidClass;
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_civoid ControlEquivalence::VisitPre(Node* node) {
301cb0ef41Sopenharmony_ci  TRACE("CEQ: Pre-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
311cb0ef41Sopenharmony_ci}
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_civoid ControlEquivalence::VisitMid(Node* node, DFSDirection direction) {
351cb0ef41Sopenharmony_ci  TRACE("CEQ: Mid-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
361cb0ef41Sopenharmony_ci  BracketList& blist = GetBracketList(node);
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  // Remove brackets pointing to this node [line:19].
391cb0ef41Sopenharmony_ci  BracketListDelete(blist, node, direction);
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci  // Potentially introduce artificial dependency from start to end.
421cb0ef41Sopenharmony_ci  if (blist.empty()) {
431cb0ef41Sopenharmony_ci    DCHECK_EQ(kInputDirection, direction);
441cb0ef41Sopenharmony_ci    VisitBackedge(node, graph_->end(), kInputDirection);
451cb0ef41Sopenharmony_ci  }
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  // Potentially start a new equivalence class [line:37].
481cb0ef41Sopenharmony_ci  BracketListTRACE(blist);
491cb0ef41Sopenharmony_ci  Bracket* recent = &blist.back();
501cb0ef41Sopenharmony_ci  if (recent->recent_size != blist.size()) {
511cb0ef41Sopenharmony_ci    recent->recent_size = blist.size();
521cb0ef41Sopenharmony_ci    recent->recent_class = NewClassNumber();
531cb0ef41Sopenharmony_ci  }
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  // Assign equivalence class to node.
561cb0ef41Sopenharmony_ci  SetClass(node, recent->recent_class);
571cb0ef41Sopenharmony_ci  TRACE("  Assigned class number is %zu\n", GetClass(node));
581cb0ef41Sopenharmony_ci}
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_civoid ControlEquivalence::VisitPost(Node* node, Node* parent_node,
621cb0ef41Sopenharmony_ci                                   DFSDirection direction) {
631cb0ef41Sopenharmony_ci  TRACE("CEQ: Post-visit of #%d:%s\n", node->id(), node->op()->mnemonic());
641cb0ef41Sopenharmony_ci  BracketList& blist = GetBracketList(node);
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  // Remove brackets pointing to this node [line:19].
671cb0ef41Sopenharmony_ci  BracketListDelete(blist, node, direction);
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  // Propagate bracket list up the DFS tree [line:13].
701cb0ef41Sopenharmony_ci  if (parent_node != nullptr) {
711cb0ef41Sopenharmony_ci    BracketList& parent_blist = GetBracketList(parent_node);
721cb0ef41Sopenharmony_ci    parent_blist.splice(parent_blist.end(), blist);
731cb0ef41Sopenharmony_ci  }
741cb0ef41Sopenharmony_ci}
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_civoid ControlEquivalence::VisitBackedge(Node* from, Node* to,
781cb0ef41Sopenharmony_ci                                       DFSDirection direction) {
791cb0ef41Sopenharmony_ci  TRACE("CEQ: Backedge from #%d:%s to #%d:%s\n", from->id(),
801cb0ef41Sopenharmony_ci        from->op()->mnemonic(), to->id(), to->op()->mnemonic());
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  // Push backedge onto the bracket list [line:25].
831cb0ef41Sopenharmony_ci  Bracket bracket = {direction, kInvalidClass, 0, from, to};
841cb0ef41Sopenharmony_ci  GetBracketList(from).push_back(bracket);
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_civoid ControlEquivalence::RunUndirectedDFS(Node* exit) {
891cb0ef41Sopenharmony_ci  ZoneStack<DFSStackEntry> stack(zone_);
901cb0ef41Sopenharmony_ci  DFSPush(stack, exit, nullptr, kInputDirection);
911cb0ef41Sopenharmony_ci  VisitPre(exit);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  while (!stack.empty()) {  // Undirected depth-first backwards traversal.
941cb0ef41Sopenharmony_ci    DFSStackEntry& entry = stack.top();
951cb0ef41Sopenharmony_ci    Node* node = entry.node;
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci    if (entry.direction == kInputDirection) {
981cb0ef41Sopenharmony_ci      if (entry.input != node->input_edges().end()) {
991cb0ef41Sopenharmony_ci        Edge edge = *entry.input;
1001cb0ef41Sopenharmony_ci        Node* input = edge.to();
1011cb0ef41Sopenharmony_ci        ++(entry.input);
1021cb0ef41Sopenharmony_ci        if (NodeProperties::IsControlEdge(edge)) {
1031cb0ef41Sopenharmony_ci          // Visit next control input.
1041cb0ef41Sopenharmony_ci          if (!Participates(input)) continue;
1051cb0ef41Sopenharmony_ci          if (GetData(input)->visited) continue;
1061cb0ef41Sopenharmony_ci          if (GetData(input)->on_stack) {
1071cb0ef41Sopenharmony_ci            // Found backedge if input is on stack.
1081cb0ef41Sopenharmony_ci            if (input != entry.parent_node) {
1091cb0ef41Sopenharmony_ci              VisitBackedge(node, input, kInputDirection);
1101cb0ef41Sopenharmony_ci            }
1111cb0ef41Sopenharmony_ci          } else {
1121cb0ef41Sopenharmony_ci            // Push input onto stack.
1131cb0ef41Sopenharmony_ci            DFSPush(stack, input, node, kInputDirection);
1141cb0ef41Sopenharmony_ci            VisitPre(input);
1151cb0ef41Sopenharmony_ci          }
1161cb0ef41Sopenharmony_ci        }
1171cb0ef41Sopenharmony_ci        continue;
1181cb0ef41Sopenharmony_ci      }
1191cb0ef41Sopenharmony_ci      if (entry.use != node->use_edges().end()) {
1201cb0ef41Sopenharmony_ci        // Switch direction to uses.
1211cb0ef41Sopenharmony_ci        entry.direction = kUseDirection;
1221cb0ef41Sopenharmony_ci        VisitMid(node, kInputDirection);
1231cb0ef41Sopenharmony_ci        continue;
1241cb0ef41Sopenharmony_ci      }
1251cb0ef41Sopenharmony_ci    }
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci    if (entry.direction == kUseDirection) {
1281cb0ef41Sopenharmony_ci      if (entry.use != node->use_edges().end()) {
1291cb0ef41Sopenharmony_ci        Edge edge = *entry.use;
1301cb0ef41Sopenharmony_ci        Node* use = edge.from();
1311cb0ef41Sopenharmony_ci        ++(entry.use);
1321cb0ef41Sopenharmony_ci        if (NodeProperties::IsControlEdge(edge)) {
1331cb0ef41Sopenharmony_ci          // Visit next control use.
1341cb0ef41Sopenharmony_ci          if (!Participates(use)) continue;
1351cb0ef41Sopenharmony_ci          if (GetData(use)->visited) continue;
1361cb0ef41Sopenharmony_ci          if (GetData(use)->on_stack) {
1371cb0ef41Sopenharmony_ci            // Found backedge if use is on stack.
1381cb0ef41Sopenharmony_ci            if (use != entry.parent_node) {
1391cb0ef41Sopenharmony_ci              VisitBackedge(node, use, kUseDirection);
1401cb0ef41Sopenharmony_ci            }
1411cb0ef41Sopenharmony_ci          } else {
1421cb0ef41Sopenharmony_ci            // Push use onto stack.
1431cb0ef41Sopenharmony_ci            DFSPush(stack, use, node, kUseDirection);
1441cb0ef41Sopenharmony_ci            VisitPre(use);
1451cb0ef41Sopenharmony_ci          }
1461cb0ef41Sopenharmony_ci        }
1471cb0ef41Sopenharmony_ci        continue;
1481cb0ef41Sopenharmony_ci      }
1491cb0ef41Sopenharmony_ci      if (entry.input != node->input_edges().end()) {
1501cb0ef41Sopenharmony_ci        // Switch direction to inputs.
1511cb0ef41Sopenharmony_ci        entry.direction = kInputDirection;
1521cb0ef41Sopenharmony_ci        VisitMid(node, kUseDirection);
1531cb0ef41Sopenharmony_ci        continue;
1541cb0ef41Sopenharmony_ci      }
1551cb0ef41Sopenharmony_ci    }
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci    // Pop node from stack when done with all inputs and uses.
1581cb0ef41Sopenharmony_ci    DCHECK(entry.input == node->input_edges().end());
1591cb0ef41Sopenharmony_ci    DCHECK(entry.use == node->use_edges().end());
1601cb0ef41Sopenharmony_ci    DFSPop(stack, node);
1611cb0ef41Sopenharmony_ci    VisitPost(node, entry.parent_node, entry.direction);
1621cb0ef41Sopenharmony_ci  }
1631cb0ef41Sopenharmony_ci}
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_civoid ControlEquivalence::DetermineParticipationEnqueue(ZoneQueue<Node*>& queue,
1661cb0ef41Sopenharmony_ci                                                       Node* node) {
1671cb0ef41Sopenharmony_ci  if (!Participates(node)) {
1681cb0ef41Sopenharmony_ci    AllocateData(node);
1691cb0ef41Sopenharmony_ci    queue.push(node);
1701cb0ef41Sopenharmony_ci  }
1711cb0ef41Sopenharmony_ci}
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_civoid ControlEquivalence::DetermineParticipation(Node* exit) {
1751cb0ef41Sopenharmony_ci  ZoneQueue<Node*> queue(zone_);
1761cb0ef41Sopenharmony_ci  DetermineParticipationEnqueue(queue, exit);
1771cb0ef41Sopenharmony_ci  while (!queue.empty()) {  // Breadth-first backwards traversal.
1781cb0ef41Sopenharmony_ci    Node* node = queue.front();
1791cb0ef41Sopenharmony_ci    queue.pop();
1801cb0ef41Sopenharmony_ci    int max = NodeProperties::PastControlIndex(node);
1811cb0ef41Sopenharmony_ci    for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
1821cb0ef41Sopenharmony_ci      DetermineParticipationEnqueue(queue, node->InputAt(i));
1831cb0ef41Sopenharmony_ci    }
1841cb0ef41Sopenharmony_ci  }
1851cb0ef41Sopenharmony_ci}
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_civoid ControlEquivalence::DFSPush(DFSStack& stack, Node* node, Node* from,
1891cb0ef41Sopenharmony_ci                                 DFSDirection dir) {
1901cb0ef41Sopenharmony_ci  DCHECK(Participates(node));
1911cb0ef41Sopenharmony_ci  DCHECK(!GetData(node)->visited);
1921cb0ef41Sopenharmony_ci  GetData(node)->on_stack = true;
1931cb0ef41Sopenharmony_ci  Node::InputEdges::iterator input = node->input_edges().begin();
1941cb0ef41Sopenharmony_ci  Node::UseEdges::iterator use = node->use_edges().begin();
1951cb0ef41Sopenharmony_ci  stack.push({dir, input, use, from, node});
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci
1991cb0ef41Sopenharmony_civoid ControlEquivalence::DFSPop(DFSStack& stack, Node* node) {
2001cb0ef41Sopenharmony_ci  DCHECK_EQ(stack.top().node, node);
2011cb0ef41Sopenharmony_ci  GetData(node)->on_stack = false;
2021cb0ef41Sopenharmony_ci  GetData(node)->visited = true;
2031cb0ef41Sopenharmony_ci  stack.pop();
2041cb0ef41Sopenharmony_ci}
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_civoid ControlEquivalence::BracketListDelete(BracketList& blist, Node* to,
2081cb0ef41Sopenharmony_ci                                           DFSDirection direction) {
2091cb0ef41Sopenharmony_ci  // TODO(turbofan): Optimize this to avoid linear search.
2101cb0ef41Sopenharmony_ci  for (BracketList::iterator i = blist.begin(); i != blist.end(); /*nop*/) {
2111cb0ef41Sopenharmony_ci    if (i->to == to && i->direction != direction) {
2121cb0ef41Sopenharmony_ci      TRACE("  BList erased: {%d->%d}\n", i->from->id(), i->to->id());
2131cb0ef41Sopenharmony_ci      i = blist.erase(i);
2141cb0ef41Sopenharmony_ci    } else {
2151cb0ef41Sopenharmony_ci      ++i;
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci  }
2181cb0ef41Sopenharmony_ci}
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_civoid ControlEquivalence::BracketListTRACE(BracketList& blist) {
2221cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_ceq) {
2231cb0ef41Sopenharmony_ci    TRACE("  BList: ");
2241cb0ef41Sopenharmony_ci    for (Bracket bracket : blist) {
2251cb0ef41Sopenharmony_ci      TRACE("{%d->%d} ", bracket.from->id(), bracket.to->id());
2261cb0ef41Sopenharmony_ci    }
2271cb0ef41Sopenharmony_ci    TRACE("\n");
2281cb0ef41Sopenharmony_ci  }
2291cb0ef41Sopenharmony_ci}
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci#undef TRACE
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci}  // namespace compiler
2341cb0ef41Sopenharmony_ci}  // namespace internal
2351cb0ef41Sopenharmony_ci}  // namespace v8
236