v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
maglev-graph-processor.h
Go to the documentation of this file.
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/base/macros.h"
15
16namespace v8 {
17namespace internal {
18namespace maglev {
19
20// The GraphProcessor takes a NodeProcessor, and applies it to each Node in the
21// Graph by calling NodeProcessor::Process on each Node.
22//
23// The GraphProcessor also keeps track of the current ProcessingState, and
24// passes this to the Process method.
25//
26// It expects a NodeProcessor class with:
27//
28// // A function that processes the graph before the nodes are walked.
29// void PreProcessGraph(Graph* graph);
30//
31// // A function that processes the graph after the nodes are walked.
32// void PostProcessGraph(Graph* graph);
33//
34// // A function that processes each basic block before its nodes are walked.
35// BlockProcessResult PreProcessBasicBlock(BasicBlock* block);
36//
37// // Process methods for each Node type. The GraphProcessor switches over
38// // the Node's opcode, casts it to the appropriate FooNode, and dispatches
39// // to NodeProcessor::Process. It's then up to the NodeProcessor to provide
40// // either distinct Process methods per Node type, or using templates or
41// // overloading as appropriate to group node processing.
42// void Process(FooNode* node, const ProcessingState& state) {}
43//
44template <typename NodeProcessor, bool visit_identity_nodes = false>
45class GraphProcessor;
46
48 kContinue, // Process exited normally.
49 kSkip, // Skip processing this block (no MultiProcessor support).
50};
51
52enum class ProcessResult {
53 kContinue, // Process exited normally, and the following processors will be
54 // called on the node.
55 kRemove, // Remove the current node from the graph (and do not call the
56 // following processors).
57 kHoist, // Hoist the current instruction to the parent basic block
58 // and reset the current instruction to the beginning of the
59 // block. Parent block must be dominating.
60 kAbort, // Stop processing now, do not process subsequent nodes/blocks.
61 // Should not be used when processing Constants.
62 kSkipBlock, // Stop processing this block and skip the remaining nodes (no
63 // MultiProcessor support).
64};
65
67 public:
69 NodeIterator* node_it = nullptr)
70 : block_it_(block_it), node_it_(node_it) {}
71
72 // Disallow copies, since the underlying frame states stay mutable.
75
76 BasicBlock* block() const { return *block_it_; }
77 BasicBlock* next_block() const { return *(block_it_ + 1); }
78
81 return node_it_;
82 }
83
84 private:
87};
88
89template <typename NodeProcessor, bool visit_identity_nodes>
91 public:
92 template <typename... Args>
93 explicit GraphProcessor(Args&&... args)
94 : node_processor_(std::forward<Args>(args)...) {}
95
96 void ProcessGraph(Graph* graph) {
97 graph_ = graph;
98
99 node_processor_.PreProcessGraph(graph);
100
101 auto process_constants = [&](auto& map) {
102 for (auto it = map.begin(); it != map.end();) {
104 node_processor_.Process(it->second, GetCurrentState());
105 switch (result) {
106 [[likely]] case ProcessResult::kContinue:
107 ++it;
108 break;
110 it = map.erase(it);
111 break;
115 UNREACHABLE();
116 }
117 }
118 };
119 process_constants(graph->constants());
120 process_constants(graph->root());
121 process_constants(graph->smi());
122 process_constants(graph->tagged_index());
123 process_constants(graph->int32());
124 process_constants(graph->uint32());
125 process_constants(graph->float64());
126 process_constants(graph->external_references());
127 process_constants(graph->trusted_constants());
128
129 for (block_it_ = graph->begin(); block_it_ != graph->end(); ++block_it_) {
130 BasicBlock* block = *block_it_;
131
132 BlockProcessResult preprocess_result =
133 node_processor_.PreProcessBasicBlock(block);
134 switch (preprocess_result) {
135 [[likely]] case BlockProcessResult::kContinue:
136 break;
138 continue;
139 }
140
141 if (block->has_phi()) {
142 auto& phis = *block->phis();
143 for (auto it = phis.begin(); it != phis.end();) {
144 Phi* phi = *it;
146 node_processor_.Process(phi, GetCurrentState());
147 switch (result) {
148 [[likely]] case ProcessResult::kContinue:
149 ++it;
150 break;
152 it = phis.RemoveAt(it);
153 break;
155 return;
157 goto skip_block;
159 UNREACHABLE();
160 }
161 }
162 }
163
164 node_processor_.PostPhiProcessing();
165
166 for (node_it_ = block->nodes().begin(); node_it_ != block->nodes().end();
167 ++node_it_) {
168 Node* node = *node_it_;
169 if (node == nullptr) continue;
171 switch (result) {
172 [[likely]] case ProcessResult::kContinue:
173 break;
175 *node_it_ = nullptr;
176 break;
178 DCHECK(block->predecessor_count() == 1 ||
179 (block->predecessor_count() == 2 && block->is_loop()));
180 BasicBlock* target = block->predecessor_at(0);
181 DCHECK(target->successors().size() == 1);
182 Node* cur = *node_it_;
183 cur->set_owner(target);
184 *node_it_ = nullptr;
185 target->nodes().push_back(cur);
186 node_it_ = block->nodes().begin();
187 break;
188 }
190 return;
192 goto skip_block;
193 }
194 }
195
196 {
197 ProcessResult control_result =
198 ProcessNodeBase(block->control_node(), GetCurrentState());
199 switch (control_result) {
200 [[likely]] case ProcessResult::kContinue:
202 break;
204 return;
207 UNREACHABLE();
208 }
209 }
210 skip_block:
211 node_processor_.PostProcessBasicBlock(block);
212 continue;
213 }
214
215 node_processor_.PostProcessGraph(graph);
216 }
217
218 NodeProcessor& node_processor() { return node_processor_; }
219 const NodeProcessor& node_processor() const { return node_processor_; }
220
221 private:
225
227 switch (node->opcode()) {
228#define CASE(OPCODE) \
229 case Opcode::k##OPCODE: \
230 if constexpr (!visit_identity_nodes && \
231 Opcode::k##OPCODE == Opcode::kIdentity) { \
232 return ProcessResult::kContinue; \
233 } \
234 PreProcess(node->Cast<OPCODE>(), state); \
235 return node_processor_.Process(node->Cast<OPCODE>(), state);
236
238#undef CASE
239 }
240 }
241
242 void PreProcess(NodeBase* node, const ProcessingState& state) {}
243
244 NodeProcessor node_processor_;
248};
249
250// A NodeProcessor that wraps multiple NodeProcessors, and forwards to each of
251// them iteratively.
252template <typename... Processors>
254
255template <>
270
271template <typename Processor, typename... Processors>
272class NodeMultiProcessor<Processor, Processors...>
273 : NodeMultiProcessor<Processors...> {
274 using Base = NodeMultiProcessor<Processors...>;
275
276 public:
277 template <typename... Args>
278 explicit NodeMultiProcessor(Processor&& processor, Args&&... processors)
279 : Base(std::forward<Args>(processors)...),
280 processor_(std::forward<Processor>(processor)) {}
281 template <typename... Args>
282 explicit NodeMultiProcessor(Args&&... processors)
283 : Base(std::forward<Args>(processors)...) {}
284
285 template <typename Node>
287 auto res = processor_.Process(node, state);
288 switch (res) {
289 [[likely]] case ProcessResult::kContinue:
290 return Base::Process(node, state);
293 return res;
296 // TODO(olivf): How to combine these with multiple processors depends on
297 // the needs of the actual processors. Implement once needed.
298 UNREACHABLE();
299 }
300 }
301 void PreProcessGraph(Graph* graph) {
302 processor_.PreProcessGraph(graph);
303 Base::PreProcessGraph(graph);
304 }
305 void PostProcessGraph(Graph* graph) {
306 // Post process in reverse order because that kind of makes sense.
307 Base::PostProcessGraph(graph);
308 processor_.PostProcessGraph(graph);
309 }
311 Base::PostProcessBasicBlock(block);
312 processor_.PostProcessBasicBlock(block);
313 }
315 BlockProcessResult res = processor_.PreProcessBasicBlock(block);
316 switch (res) {
317 [[likely]] case BlockProcessResult::kContinue:
318 return Base::PreProcessBasicBlock(block);
320 // TODO(olivf): How to combine this with multiple processors depends on
321 // the needs of the actual processors. Implement once needed.
322 UNREACHABLE();
323 }
324 }
326 processor_.PostPhiProcessing();
327 Base::PostPhiProcessing();
328 }
329
330 private:
332};
333
334template <typename... Processors>
336
337} // namespace maglev
338} // namespace internal
339} // namespace v8
340
341#endif // V8_MAGLEV_MAGLEV_GRAPH_PROCESSOR_H_
TFGraph * graph
BasicBlock * predecessor_at(int i) const
const NodeProcessor & node_processor() const
ProcessResult ProcessNodeBase(NodeBase *node, const ProcessingState &state)
void PreProcess(NodeBase *node, const ProcessingState &state)
void set_owner(BasicBlock *block)
Definition maglev-ir.h:2137
ProcessResult Process(Node *node, const ProcessingState &state)
BlockProcessResult PreProcessBasicBlock(BasicBlock *block)
V8_INLINE ProcessResult Process(NodeBase *node, const ProcessingState &state)
ProcessingState & operator=(const ProcessingState &)=delete
ProcessingState(BlockConstIterator block_it, NodeIterator *node_it=nullptr)
ProcessingState(const ProcessingState &)=delete
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
ProcessorImpl * processor_
Definition mul-fft.cc:474
STL namespace.
ZoneVector< Node * >::iterator NodeIterator
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
#define V8_INLINE
Definition v8config.h:500