1 // Copyright 2014 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_COMPILER_GRAPH_REDUCER_H_
6 #define V8_COMPILER_GRAPH_REDUCER_H_
7 
8 #include "src/base/compiler-specific.h"
9 #include "src/common/globals.h"
10 #include "src/compiler/node-marker.h"
11 #include "src/zone/zone-containers.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 class TickCounter;
17 
18 namespace compiler {
19 
20 class Graph;
21 class JSHeapBroker;
22 class Node;
23 class ObserveNodeManager;
24 
25 // NodeIds are identifying numbers for nodes that can be used to index auxiliary
26 // out-of-line data associated with each node.
27 using NodeId = uint32_t;
28 
29 // Possible outcomes for decisions.
30 enum class Decision : uint8_t { kUnknown, kTrue, kFalse };
31 
32 // Represents the result of trying to reduce a node in the graph.
33 class Reduction final {
34  public:
replacement_(replacement)35   explicit Reduction(Node* replacement = nullptr) : replacement_(replacement) {}
36 
replacement()37   Node* replacement() const { return replacement_; }
Changed()38   bool Changed() const { return replacement() != nullptr; }
FollowedBy(Reduction next)39   Reduction FollowedBy(Reduction next) const {
40     if (next.Changed()) return next;
41     return *this;
42   }
43 
44  private:
45   Node* replacement_;
46 };
47 
48 
49 // A reducer can reduce or simplify a given node based on its operator and
50 // inputs. This class functions as an extension point for the graph reducer for
51 // language-specific reductions (e.g. reduction based on types or constant
52 // folding of low-level operators) can be integrated into the graph reduction
53 // phase.
54 class V8_EXPORT_PRIVATE Reducer {
55  public:
56   virtual ~Reducer() = default;
57 
58   // Only used for tracing, when using the --trace_turbo_reduction flag.
59   virtual const char* reducer_name() const = 0;
60 
61   // Try to reduce a node if possible.
62   Reduction Reduce(Node* node, ObserveNodeManager* observe_node_manager);
63 
64   // Invoked by the {GraphReducer} when all nodes are done.  Can be used to
65   // do additional reductions at the end, which in turn can cause a new round
66   // of reductions.
67   virtual void Finalize();
68 
69   // Helper functions for subclasses to produce reductions for a node.
NoChange()70   static Reduction NoChange() { return Reduction(); }
Replace(Node * node)71   static Reduction Replace(Node* node) { return Reduction(node); }
Changed(Node * node)72   static Reduction Changed(Node* node) { return Reduction(node); }
73 
74  private:
75   virtual Reduction Reduce(Node* node) = 0;
76 };
77 
78 
79 // An advanced reducer can also edit the graphs by changing and replacing nodes
80 // other than the one currently being reduced.
81 class AdvancedReducer : public Reducer {
82  public:
83   // Observe the actions of this reducer.
84   class Editor {
85    public:
86     virtual ~Editor() = default;
87 
88     // Replace {node} with {replacement}.
89     virtual void Replace(Node* node, Node* replacement) = 0;
90     // Revisit the {node} again later.
91     virtual void Revisit(Node* node) = 0;
92     // Replace value uses of {node} with {value} and effect uses of {node} with
93     // {effect}. If {effect == nullptr}, then use the effect input to {node}.
94     // All control uses will be relaxed assuming {node} cannot throw.
95     virtual void ReplaceWithValue(Node* node, Node* value, Node* effect,
96                                   Node* control) = 0;
97   };
98 
AdvancedReducer(Editor * editor)99   explicit AdvancedReducer(Editor* editor) : editor_(editor) {}
100 
101  protected:
102   // Helper functions for subclasses to produce reductions for a node.
Replace(Node * node)103   static Reduction Replace(Node* node) { return Reducer::Replace(node); }
104 
105   // Helper functions for subclasses to edit the graph.
Replace(Node * node,Node * replacement)106   void Replace(Node* node, Node* replacement) {
107     DCHECK_NOT_NULL(editor_);
108     editor_->Replace(node, replacement);
109   }
Revisit(Node * node)110   void Revisit(Node* node) {
111     DCHECK_NOT_NULL(editor_);
112     editor_->Revisit(node);
113   }
114   void ReplaceWithValue(Node* node, Node* value, Node* effect = nullptr,
115                         Node* control = nullptr) {
116     DCHECK_NOT_NULL(editor_);
117     editor_->ReplaceWithValue(node, value, effect, control);
118   }
119 
120   // Relax the effects of {node} by immediately replacing effect and control
121   // uses of {node} with the effect and control input to {node}.
122   // TODO(turbofan): replace the effect input to {node} with {graph->start()}.
RelaxEffectsAndControls(Node * node)123   void RelaxEffectsAndControls(Node* node) {
124     ReplaceWithValue(node, node, nullptr, nullptr);
125   }
126 
127   // Relax the control uses of {node} by immediately replacing them with the
128   // control input to {node}.
RelaxControls(Node * node)129   void RelaxControls(Node* node) {
130     ReplaceWithValue(node, node, node, nullptr);
131   }
132 
133  private:
134   Editor* const editor_;
135 };
136 
137 
138 // Performs an iterative reduction of a node graph.
139 class V8_EXPORT_PRIVATE GraphReducer
NON_EXPORTED_BASE(AdvancedReducer::Editor)140     : public NON_EXPORTED_BASE(AdvancedReducer::Editor) {
141  public:
142   GraphReducer(Zone* zone, Graph* graph, TickCounter* tick_counter,
143                JSHeapBroker* broker, Node* dead = nullptr,
144                ObserveNodeManager* observe_node_manager = nullptr);
145   ~GraphReducer() override;
146 
147   GraphReducer(const GraphReducer&) = delete;
148   GraphReducer& operator=(const GraphReducer&) = delete;
149 
150   Graph* graph() const { return graph_; }
151 
152   void AddReducer(Reducer* reducer);
153 
154   // Reduce a single node.
155   void ReduceNode(Node* const);
156   // Reduce the whole graph.
157   void ReduceGraph();
158 
159  private:
160   enum class State : uint8_t;
161   struct NodeState {
162     Node* node;
163     int input_index;
164   };
165 
166   // Reduce a single node.
167   Reduction Reduce(Node* const);
168   // Reduce the node on top of the stack.
169   void ReduceTop();
170 
171   // Replace {node} with {replacement}.
172   void Replace(Node* node, Node* replacement) final;
173 
174   // Replace value uses of {node} with {value} and effect uses of {node} with
175   // {effect}. If {effect == nullptr}, then use the effect input to {node}. All
176   // control uses will be relaxed assuming {node} cannot throw.
177   void ReplaceWithValue(Node* node, Node* value, Node* effect,
178                         Node* control) final;
179 
180   // Replace all uses of {node} with {replacement} if the id of {replacement} is
181   // less than or equal to {max_id}. Otherwise, replace all uses of {node} whose
182   // id is less than or equal to {max_id} with the {replacement}.
183   void Replace(Node* node, Node* replacement, NodeId max_id);
184 
185   // Node stack operations.
186   void Pop();
187   void Push(Node* node);
188 
189   // Revisit queue operations.
190   bool Recurse(Node* node);
191   void Revisit(Node* node) final;
192 
193   Graph* const graph_;
194   Node* const dead_;
195   NodeMarker<State> state_;
196   ZoneVector<Reducer*> reducers_;
197   ZoneQueue<Node*> revisit_;
198   ZoneStack<NodeState> stack_;
199   TickCounter* const tick_counter_;
200   JSHeapBroker* const broker_;
201   ObserveNodeManager* const observe_node_manager_;
202 };
203 
204 }  // namespace compiler
205 }  // namespace internal
206 }  // namespace v8
207 
208 #endif  // V8_COMPILER_GRAPH_REDUCER_H_
209