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