1// Copyright 2022 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
5#ifndef V8_MAGLEV_MAGLEV_GRAPH_PROCESSOR_H_
6#define V8_MAGLEV_MAGLEV_GRAPH_PROCESSOR_H_
7
8#include "src/compiler/bytecode-analysis.h"
9#include "src/maglev/maglev-basic-block.h"
10#include "src/maglev/maglev-graph.h"
11#include "src/maglev/maglev-interpreter-frame-state.h"
12#include "src/maglev/maglev-ir.h"
13
14namespace v8 {
15namespace internal {
16namespace maglev {
17
18// The GraphProcessor takes a NodeProcessor, and applies it to each Node in the
19// Graph by calling NodeProcessor::Process on each Node.
20//
21// The GraphProcessor also keeps track of the current ProcessingState, including
22// the inferred corresponding InterpreterFrameState and (optionally) the state
23// at the most recent Checkpoint, and passes this to the Process method.
24//
25// It expects a NodeProcessor class with:
26//
27//   // A function that processes the graph before the nodes are walked.
28//   void PreProcessGraph(MaglevCompilationUnit*, Graph* graph);
29//
30//   // A function that processes the graph after the nodes are walked.
31//   void PostProcessGraph(MaglevCompilationUnit*, Graph* graph);
32//
33//   // A function that processes each basic block before its nodes are walked.
34//   void PreProcessBasicBlock(MaglevCompilationUnit*, BasicBlock* block);
35//
36//   // Process methods for each Node type. The GraphProcessor switches over
37//   // the Node's opcode, casts it to the appropriate FooNode, and dispatches
38//   // to NodeProcessor::Process. It's then up to the NodeProcessor to provide
39//   // either distinct Process methods per Node type, or using templates or
40//   // overloading as appropriate to group node processing.
41//   void Process(FooNode* node, const ProcessingState& state) {}
42//
43template <typename NodeProcessor>
44class GraphProcessor;
45
46class ProcessingState {
47 public:
48  explicit ProcessingState(MaglevCompilationUnit* compilation_unit,
49                           BlockConstIterator block_it)
50      : compilation_unit_(compilation_unit), block_it_(block_it) {}
51
52  // Disallow copies, since the underlying frame states stay mutable.
53  ProcessingState(const ProcessingState&) = delete;
54  ProcessingState& operator=(const ProcessingState&) = delete;
55
56  BasicBlock* block() const { return *block_it_; }
57  BasicBlock* next_block() const { return *(block_it_ + 1); }
58
59  MaglevCompilationUnit* compilation_unit() const { return compilation_unit_; }
60
61  int register_count() const { return compilation_unit_->register_count(); }
62  int parameter_count() const { return compilation_unit_->parameter_count(); }
63
64  MaglevGraphLabeller* graph_labeller() const {
65    return compilation_unit_->graph_labeller();
66  }
67
68 private:
69  MaglevCompilationUnit* compilation_unit_;
70  BlockConstIterator block_it_;
71};
72
73template <typename NodeProcessor>
74class GraphProcessor {
75 public:
76  template <typename... Args>
77  explicit GraphProcessor(MaglevCompilationUnit* compilation_unit,
78                          Args&&... args)
79      : compilation_unit_(compilation_unit),
80        node_processor_(std::forward<Args>(args)...) {}
81
82  void ProcessGraph(Graph* graph) {
83    graph_ = graph;
84
85    node_processor_.PreProcessGraph(compilation_unit_, graph);
86
87    for (block_it_ = graph->begin(); block_it_ != graph->end(); ++block_it_) {
88      BasicBlock* block = *block_it_;
89
90      node_processor_.PreProcessBasicBlock(compilation_unit_, block);
91
92      if (block->has_phi()) {
93        for (Phi* phi : *block->phis()) {
94          node_processor_.Process(phi, GetCurrentState());
95        }
96      }
97
98      for (node_it_ = block->nodes().begin(); node_it_ != block->nodes().end();
99           ++node_it_) {
100        Node* node = *node_it_;
101        ProcessNodeBase(node, GetCurrentState());
102      }
103
104      ProcessNodeBase(block->control_node(), GetCurrentState());
105    }
106
107    node_processor_.PostProcessGraph(compilation_unit_, graph);
108  }
109
110  NodeProcessor& node_processor() { return node_processor_; }
111  const NodeProcessor& node_processor() const { return node_processor_; }
112
113 private:
114  ProcessingState GetCurrentState() {
115    return ProcessingState(compilation_unit_, block_it_);
116  }
117
118  void ProcessNodeBase(NodeBase* node, const ProcessingState& state) {
119    switch (node->opcode()) {
120#define CASE(OPCODE)                                      \
121  case Opcode::k##OPCODE:                                 \
122    PreProcess(node->Cast<OPCODE>(), state);              \
123    node_processor_.Process(node->Cast<OPCODE>(), state); \
124    break;
125      NODE_BASE_LIST(CASE)
126#undef CASE
127    }
128  }
129
130  void PreProcess(NodeBase* node, const ProcessingState& state) {}
131
132  int register_count() const { return compilation_unit_->register_count(); }
133  const compiler::BytecodeAnalysis& bytecode_analysis() const {
134    return compilation_unit_->bytecode_analysis();
135  }
136
137  MaglevCompilationUnit* const compilation_unit_;
138  NodeProcessor node_processor_;
139  Graph* graph_;
140  BlockConstIterator block_it_;
141  NodeConstIterator node_it_;
142};
143
144// A NodeProcessor that wraps multiple NodeProcessors, and forwards to each of
145// them iteratively.
146template <typename... Processors>
147class NodeMultiProcessor;
148
149template <>
150class NodeMultiProcessor<> {
151 public:
152  void PreProcessGraph(MaglevCompilationUnit*, Graph* graph) {}
153  void PostProcessGraph(MaglevCompilationUnit*, Graph* graph) {}
154  void PreProcessBasicBlock(MaglevCompilationUnit*, BasicBlock* block) {}
155  void Process(NodeBase* node, const ProcessingState& state) {}
156};
157
158template <typename Processor, typename... Processors>
159class NodeMultiProcessor<Processor, Processors...>
160    : NodeMultiProcessor<Processors...> {
161  using Base = NodeMultiProcessor<Processors...>;
162
163 public:
164  template <typename Node>
165  void Process(Node* node, const ProcessingState& state) {
166    processor_.Process(node, state);
167    Base::Process(node, state);
168  }
169  void PreProcessGraph(MaglevCompilationUnit* unit, Graph* graph) {
170    processor_.PreProcessGraph(unit, graph);
171    Base::PreProcessGraph(unit, graph);
172  }
173  void PostProcessGraph(MaglevCompilationUnit* unit, Graph* graph) {
174    // Post process in reverse order because that kind of makes sense.
175    Base::PostProcessGraph(unit, graph);
176    processor_.PostProcessGraph(unit, graph);
177  }
178  void PreProcessBasicBlock(MaglevCompilationUnit* unit, BasicBlock* block) {
179    processor_.PreProcessBasicBlock(unit, block);
180    Base::PreProcessBasicBlock(unit, block);
181  }
182
183 private:
184  Processor processor_;
185};
186
187template <typename... Processors>
188using GraphMultiProcessor = GraphProcessor<NodeMultiProcessor<Processors...>>;
189
190}  // namespace maglev
191}  // namespace internal
192}  // namespace v8
193
194#endif  // V8_MAGLEV_MAGLEV_GRAPH_PROCESSOR_H_
195