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