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 14 namespace v8 { 15 namespace internal { 16 namespace 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 // 43 template <typename NodeProcessor> 44 class GraphProcessor; 45 46 class ProcessingState { 47 public: ProcessingState(MaglevCompilationUnit * compilation_unit,BlockConstIterator block_it)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 block()56 BasicBlock* block() const { return *block_it_; } next_block()57 BasicBlock* next_block() const { return *(block_it_ + 1); } 58 compilation_unit()59 MaglevCompilationUnit* compilation_unit() const { return compilation_unit_; } 60 register_count()61 int register_count() const { return compilation_unit_->register_count(); } parameter_count()62 int parameter_count() const { return compilation_unit_->parameter_count(); } 63 graph_labeller()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 73 template <typename NodeProcessor> 74 class GraphProcessor { 75 public: 76 template <typename... Args> GraphProcessor(MaglevCompilationUnit * compilation_unit,Args &&...args)77 explicit GraphProcessor(MaglevCompilationUnit* compilation_unit, 78 Args&&... args) 79 : compilation_unit_(compilation_unit), 80 node_processor_(std::forward<Args>(args)...) {} 81 ProcessGraph(Graph * graph)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 node_processor()110 NodeProcessor& node_processor() { return node_processor_; } node_processor()111 const NodeProcessor& node_processor() const { return node_processor_; } 112 113 private: GetCurrentState()114 ProcessingState GetCurrentState() { 115 return ProcessingState(compilation_unit_, block_it_); 116 } 117 ProcessNodeBase(NodeBase * node,const ProcessingState & state)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 PreProcess(NodeBase * node,const ProcessingState & state)130 void PreProcess(NodeBase* node, const ProcessingState& state) {} 131 register_count()132 int register_count() const { return compilation_unit_->register_count(); } bytecode_analysis()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. 146 template <typename... Processors> 147 class NodeMultiProcessor; 148 149 template <> 150 class NodeMultiProcessor<> { 151 public: PreProcessGraph(MaglevCompilationUnit *,Graph * graph)152 void PreProcessGraph(MaglevCompilationUnit*, Graph* graph) {} PostProcessGraph(MaglevCompilationUnit *,Graph * graph)153 void PostProcessGraph(MaglevCompilationUnit*, Graph* graph) {} PreProcessBasicBlock(MaglevCompilationUnit *,BasicBlock * block)154 void PreProcessBasicBlock(MaglevCompilationUnit*, BasicBlock* block) {} Process(NodeBase * node,const ProcessingState & state)155 void Process(NodeBase* node, const ProcessingState& state) {} 156 }; 157 158 template <typename Processor, typename... Processors> 159 class NodeMultiProcessor<Processor, Processors...> 160 : NodeMultiProcessor<Processors...> { 161 using Base = NodeMultiProcessor<Processors...>; 162 163 public: 164 template <typename Node> Process(Node * node,const ProcessingState & state)165 void Process(Node* node, const ProcessingState& state) { 166 processor_.Process(node, state); 167 Base::Process(node, state); 168 } PreProcessGraph(MaglevCompilationUnit * unit,Graph * graph)169 void PreProcessGraph(MaglevCompilationUnit* unit, Graph* graph) { 170 processor_.PreProcessGraph(unit, graph); 171 Base::PreProcessGraph(unit, graph); 172 } PostProcessGraph(MaglevCompilationUnit * unit,Graph * graph)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 } PreProcessBasicBlock(MaglevCompilationUnit * unit,BasicBlock * block)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 187 template <typename... Processors> 188 using GraphMultiProcessor = GraphProcessor<NodeMultiProcessor<Processors...>>; 189 190 } // namespace maglev 191 } // namespace internal 192 } // namespace v8 193 194 #endif // V8_MAGLEV_MAGLEV_GRAPH_PROCESSOR_H_ 195