v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
control-path-state.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_COMPILER_CONTROL_PATH_STATE_H_
6#define V8_COMPILER_CONTROL_PATH_STATE_H_
7
12#include "src/compiler/node.h"
15#include "src/zone/zone.h"
16
17namespace v8 {
18namespace internal {
19namespace compiler {
20
22
23// Class for tracking information about path state. It is represented as a
24// linked list of {NodeState} blocks, each of which corresponds to a block of
25// code bewteen an IfTrue/IfFalse and a Merge. Each block is in turn represented
26// as a linked list of {NodeState}s.
27// If {node_uniqueness} is {kMultipleInstances}, different states can be
28// assigned to the same node. The most recent state always takes precedence.
29// States still belong to a block and will be removed if the block gets merged.
30template <typename NodeState, NodeUniqueness node_uniqueness>
32 public:
33 static_assert(
34 std::is_member_function_pointer<decltype(&NodeState::IsSet)>::value,
35 "{NodeState} needs an {IsSet} method");
36 static_assert(
37 std::is_member_object_pointer<decltype(&NodeState::node)>::value,
38 "{NodeState} needs to hold a pointer to the {Node*} owner of the state");
39
40 explicit ControlPathState(Zone* zone) : states_(zone) {}
41
42 // Returns the {NodeState} assigned to node, or the default value
43 // {NodeState()} if it is not assigned.
44 NodeState LookupState(Node* node) const;
45
46 // Adds a state in the current code block, or a new block if the block list is
47 // empty.
48 void AddState(Zone* zone, Node* node, NodeState state, ControlPathState hint);
49
50 // Adds a state in a new block.
51 void AddStateInNewBlock(Zone* zone, Node* node, NodeState state);
52
53 // Reset this {ControlPathState} to its longest prefix that is common with
54 // {other}.
56
57 bool IsEmpty() { return blocks_.Size() == 0; }
58
59 bool operator==(const ControlPathState& other) const {
60 return blocks_ == other.blocks_;
61 }
62 bool operator!=(const ControlPathState& other) const {
63 return blocks_ != other.blocks_;
64 }
65
66 private:
67 using NodeWithPathDepth = std::pair<Node*, size_t>;
68
69 size_t depth(size_t depth_if_multiple_instances) {
70 return node_uniqueness == kMultipleInstances ? depth_if_multiple_instances
71 : 0;
72 }
73
74#if DEBUG
75 bool BlocksAndStatesInvariant();
76#endif
77
79 // This is an auxilliary data structure that provides fast lookups in the
80 // set of states. It should hold at any point that the contents of {blocks_}
81 // and {states_} is the same, which is implemented in
82 // {BlocksAndStatesInvariant}.
84};
85
86template <typename NodeState, NodeUniqueness node_uniqueness>
88 protected:
90 TFGraph* graph)
91 : AdvancedReducer(editor),
92 zone_(zone),
93 node_states_(graph->NodeCount(), zone),
94 reduced_(graph->NodeCount(), zone) {}
96 // Update the state of {state_owner} to {new_state}.
98 Node* state_owner,
100 // Update the state of {state_owner} to {prev_states}, plus {additional_state}
101 // assigned to {additional_node}. Force the new state in a new block if
102 // {in_new_block}.
104 Node* state_owner,
106 Node* additional_node, NodeState additional_state, bool in_new_block);
107 Zone* zone() { return zone_; }
111 bool IsReduced(Node* node) { return reduced_.Get(node); }
112
113 private:
115 // Maps each control node to the node's current state.
116 // If the information is nullptr, then we have not calculated the information
117 // yet.
122};
123
124template <typename NodeState, NodeUniqueness node_uniqueness>
126 Node* node) const {
127 if (node_uniqueness == kUniqueInstance) return states_.Get({node, 0});
128 for (size_t depth = blocks_.Size(); depth > 0; depth--) {
129 NodeState state = states_.Get({node, depth});
130 if (state.IsSet()) return state;
131 }
132 return {};
133}
134
135template <typename NodeState, NodeUniqueness node_uniqueness>
137 Zone* zone, Node* node, NodeState state,
139 NodeState previous_state = LookupState(node);
140 if (node_uniqueness == kUniqueInstance ? previous_state.IsSet()
141 : previous_state == state) {
142 return;
143 }
144
146 if (hint.blocks_.Size() > 0) {
147 prev_front.PushFront(state, zone, hint.blocks_.Front());
148 } else {
149 prev_front.PushFront(state, zone);
150 }
151 blocks_.DropFront();
152 blocks_.PushFront(prev_front, zone);
153 states_.Set({node, depth(blocks_.Size())}, state);
154 SLOW_DCHECK(BlocksAndStatesInvariant());
155}
156
157template <typename NodeState, NodeUniqueness node_uniqueness>
159 Zone* zone, Node* node, NodeState state) {
161 NodeState previous_state = LookupState(node);
162 if (node_uniqueness == kUniqueInstance ? !previous_state.IsSet()
163 : previous_state != state) {
164 new_block.PushFront(state, zone);
165 states_.Set({node, depth(blocks_.Size() + 1)}, state);
166 }
167 blocks_.PushFront(new_block, zone);
168 SLOW_DCHECK(BlocksAndStatesInvariant());
169}
170
171template <typename NodeState, NodeUniqueness node_uniqueness>
174 while (other.blocks_.Size() > blocks_.Size()) other.blocks_.DropFront();
175 while (blocks_.Size() > other.blocks_.Size()) {
176 for (NodeState state : blocks_.Front()) {
177 states_.Set({state.node, depth(blocks_.Size())}, {});
178 }
179 blocks_.DropFront();
180 }
181 while (blocks_ != other.blocks_) {
182 for (NodeState state : blocks_.Front()) {
183 states_.Set({state.node, depth(blocks_.Size())}, {});
184 }
185 blocks_.DropFront();
186 other.blocks_.DropFront();
187 }
188 SLOW_DCHECK(BlocksAndStatesInvariant());
189}
190
191#if DEBUG
192template <typename NodeState, NodeUniqueness node_uniqueness>
195 size_t current_depth = blocks_.Size();
196 for (auto block : blocks_) {
197 std::unordered_set<Node*> seen_this_block;
198 for (NodeState state : block) {
199 // Every element of blocks_ has to be in states_.
200 if (seen_this_block.count(state.node) == 0) {
201 if (states_copy.Get({state.node, depth(current_depth)}) != state) {
202 return false;
203 }
204 states_copy.Set({state.node, depth(current_depth)}, {});
205 seen_this_block.emplace(state.node);
206 }
207 }
208 current_depth--;
209 }
210 // Every element of {states_} has to be in {blocks_}. We removed all
211 // elements of blocks_ from states_copy, so if it is not empty, the
212 // invariant fails.
213 return states_copy.begin() == states_copy.end();
214}
215#endif
216
217template <typename NodeState, NodeUniqueness node_uniqueness>
218Reduction AdvancedReducerWithControlPathState<
219 NodeState, node_uniqueness>::TakeStatesFromFirstControl(Node* node) {
220 // We just propagate the information from the control input (ideally,
221 // we would only revisit control uses if there is change).
222 Node* input = NodeProperties::GetControlInput(node, 0);
223 if (!reduced_.Get(input)) return NoChange();
224 return UpdateStates(node, node_states_.Get(input));
225}
226
227template <typename NodeState, NodeUniqueness node_uniqueness>
230 Node* state_owner, ControlPathState<NodeState, node_uniqueness> new_state) {
231 // Only signal that the node has {Changed} if its state has changed.
232 bool reduced_changed = reduced_.Set(state_owner, true);
233 bool node_states_changed = node_states_.Set(state_owner, new_state);
234 if (reduced_changed || node_states_changed) {
235 return Changed(state_owner);
236 }
237 return NoChange();
238}
239
240template <typename NodeState, NodeUniqueness node_uniqueness>
243 Node* state_owner, ControlPathState<NodeState, node_uniqueness> prev_states,
244 Node* additional_node, NodeState additional_state, bool in_new_block) {
245 if (in_new_block || prev_states.IsEmpty()) {
246 prev_states.AddStateInNewBlock(zone_, additional_node, additional_state);
247 } else {
249 node_states_.Get(state_owner);
250 prev_states.AddState(zone_, additional_node, additional_state, original);
251 }
252 return UpdateStates(state_owner, prev_states);
253}
254
255} // namespace compiler
256} // namespace internal
257} // namespace v8
258
259#endif // V8_COMPILER_CONTROL_PATH_STATE_H_
#define SLOW_DCHECK(condition)
Definition checks.h:21
Reduction UpdateStates(Node *state_owner, ControlPathState< NodeState, node_uniqueness > new_state)
AdvancedReducerWithControlPathState(Editor *editor, Zone *zone, TFGraph *graph)
ControlPathState< NodeState, node_uniqueness > GetState(Node *node)
Reduction UpdateStates(Node *state_owner, ControlPathState< NodeState, node_uniqueness > prev_states, Node *additional_node, NodeState additional_state, bool in_new_block)
NodeAuxData< ControlPathState< NodeState, node_uniqueness >, ZoneConstruct< ControlPathState< NodeState, node_uniqueness > > > node_states_
bool operator==(const ControlPathState &other) const
bool operator!=(const ControlPathState &other) const
void ResetToCommonAncestor(ControlPathState other)
size_t depth(size_t depth_if_multiple_instances)
FunctionalList< FunctionalList< NodeState > > blocks_
void AddState(Zone *zone, Node *node, NodeState state, ControlPathState hint)
void AddStateInNewBlock(Zone *zone, Node *node, NodeState state)
PersistentMap< NodeWithPathDepth, NodeState > states_
std::pair< Node *, size_t > NodeWithPathDepth
static Node * GetControlInput(Node *node, int index=0)
Zone * zone_
Node * node
LiftoffAssembler::CacheState state
T ZoneConstruct(Zone *zone)
return value
Definition map-inl.h:893
std::vector< std::vector< ValueType > > blocks_