docc 0.8.3 (0d44999b)
C++ API Reference
Loading...
Searching...
No Matches
structured_data_flow_analysis.h
Go to the documentation of this file.
1#pragma once
2
3#include <unordered_set>
4
15
16namespace sdfg {
17namespace analysis {
18
23
24template<typename T>
26 using ExposedType = T;
27
28 virtual ~DataFlowState() = default;
29
30 virtual bool ran_at_least_once() const = 0;
31
37 virtual bool update(const T& incoming) = 0;
38
42 virtual const T& forward_exposed() const = 0;
43
49 virtual bool update_incoming(const T& incoming) = 0;
50
56 virtual bool update_forward_exposed(const T& forward_exposed) = 0;
57};
58
60
61template<typename T, typename I>
62struct ElementIdMapDataFlowState : public DataFlowState<std::unordered_map<ElementId, T>> {
64
65protected:
68 bool ran_ = false;
69
70public:
71 bool ran_at_least_once() const override {
72 return ran_;
73 }
74
75 bool update(const ExposedType& incoming) override {
76 bool needs_update = update_incoming(incoming);
77
78 if (!needs_update) {
79 return false;
80 }
81
82 ExposedType exposed = incoming_;
84
85 return update_forward_exposed(exposed);
86 }
87
88 bool update_incoming(const ExposedType& incoming) override {
89 bool any_changes = false;
90 for (auto it = incoming.begin(); it != incoming.end(); ++it) {
91 auto [placed, changed] = incoming_.insert(*it);
92 any_changes |= changed;
93 }
94 return any_changes || !ran_;
95 }
96
98 bool any_changes = false;
99 for (auto it = forward_exposed.begin(); it != forward_exposed.end(); ++it) {
100 auto [placed, changed] = forward_exposed_.insert(*it);
101 any_changes |= changed;
102 }
103 if (!ran_) {
104 ran_ = true;
105 return true;
106 } else {
107 return any_changes;
108 }
109 }
110
111 const ExposedType& forward_exposed() const override {
112 return forward_exposed_;
113 }
114
116 return ExposedType();
117 }
118
119 static void merge(ExposedType& merge_into, const ExposedType& other, MergeMode mode = MergeMode::CUMULATIVE) {
120 if (mode == MergeMode::BRANCHES) {
121 for (auto it = merge_into.begin(); it != merge_into.end();) {
122 auto key = it->first;
123 if (!other.contains(key)) {
124 it = merge_into.erase(it);
125 continue;
126 }
127 ++it;
128 }
129 } else {
130 merge_into.insert(other.begin(), other.end());
131 }
132 }
133
134 virtual void apply_kills_and_changes(ExposedType& exposed) const = 0;
135};
136
164template<typename State>
166public:
168
169 using ExposedType = typename State::ExposedType;
170
171 // -----------------------------------------------------------------
172 // Main entry point
173 // -----------------------------------------------------------------
174
185
191 solve(root, boundary());
192 }
193
194 // -----------------------------------------------------------------
195 // Query results
196 // -----------------------------------------------------------------
197
204 return *states_.at(&node);
205 }
206
208 return states_.contains(&node);
209 }
210
211protected:
213 auto& ptr = states_[&node];
214 if (!ptr) {
215 ptr = create_initial_state(node);
216 }
217 return *ptr;
218 }
219
220 virtual std::unique_ptr<State> create_initial_state(const structured_control_flow::ControlFlowNode& node) = 0;
221 // -----------------------------------------------------------------
222 // Merge at join points
223 // -----------------------------------------------------------------
224
232 return State::empty_in();
233 }
234
235private:
236 std::unordered_map<const structured_control_flow::ControlFlowNode*, std::unique_ptr<State>> states_;
237
238 // -----------------------------------------------------------------
239 // Recursive solvers for each node type
240 // -----------------------------------------------------------------
241
249 std::pair<bool, const ExposedType&> solve(structured_control_flow::ControlFlowNode& node, const ExposedType& in) {
250 // Dispatch to the concrete type
251 if (auto* seq = dyn_cast<structured_control_flow::Sequence*>(&node)) {
252 return solve(*seq, in);
253 }
254 if (auto* if_else = dyn_cast<structured_control_flow::IfElse*>(&node)) {
255 return solve(*if_else, in);
256 }
258 return solve_loop(*sloop, in);
259 }
260 if (auto* while_loop = dyn_cast<structured_control_flow::While*>(&node)) {
261 return solve(*while_loop, in);
262 }
263
264 // Unknown node – treat as transparent
265 auto& s = get_or_create_state(node);
266 bool changed = s.update(in);
267 return {changed, s.forward_exposed()};
268 }
269
270 // -- Sequence: propagate through children left-to-right ---------------
271
272 std::pair<bool, const ExposedType&> solve(structured_control_flow::Sequence& seq, const ExposedType& in) {
273 auto& seq_state = get_or_create_state(seq);
274 seq_state.update_incoming(in);
275
276 const ExposedType* current = &in;
277 bool updating = true;
278 for (size_t i = 0; i < seq.size() && updating; ++i) {
279 auto& child = seq.at(i);
280 auto [changed, output] = solve(child, *current);
281 updating = changed;
282 current = &output;
283 }
284
285 if (updating) {
286 auto changed = seq_state.update_forward_exposed(*current);
287 return {changed, *current};
288 } else {
289 return {false, seq_state.forward_exposed()};
290 }
291 }
292
293 // -- IfElse: propagate into each branch, merge results ----------------
294
295 std::pair<bool, const ExposedType&> solve(structured_control_flow::IfElse& if_else, const ExposedType& in) {
296 auto& state = get_or_create_state(if_else);
297 state.update_incoming(in);
298
299 ExposedType merged = State::empty_in();
300 bool first = true;
301 bool changed = true;
302 for (size_t i = 0; i < if_else.size(); ++i) {
303 auto [branch_seq, cond] = if_else.at(i);
304 auto [branch_changed, branch_out] = solve(branch_seq, in);
305 changed |= branch_changed;
306 State::merge(merged, branch_out, first ? MergeMode::CUMULATIVE : MergeMode::BRANCHES);
307 first = false;
308 }
309
310 // If the IfElse is not complete (no else-branch covering all cases)
311 // the input can also flow through unchanged.
312 if (!if_else.is_complete()) {
313 State::merge(merged, in, MergeMode::BRANCHES);
314 }
315
316 if (changed) {
317 changed = state.update_forward_exposed(merged);
318 }
319 return {changed, state.forward_exposed()};
320 }
321
322 // -- StructuredLoop (For / Map): fixed-point iteration ----------------
323
324 std::pair<bool, const ExposedType&> solve_loop(structured_control_flow::StructuredLoop& loop, const ExposedType& in) {
325 // todo factor in loop header exposes
326
327 return solve_loop_body(get_or_create_state(loop), loop.root(), in, [&](ExposedType& after_body) {
328 // todo factor in loop update exposes
329 });
330 }
331
332 std::pair<bool, const ExposedType&> solve_loop_body(
333 State& state,
334 structured_control_flow::Sequence& body,
335 const ExposedType& in,
336 std::function<void(ExposedType&)> apply_after_body
337 ) {
338 state.update_incoming(in);
339
340 ExposedType current = in;
341 bool changing = false;
342 bool changed = false;
343 do {
344 auto [body_changed, body_out] = solve(body, current);
345 changing = body_changed;
346 changed |= body_changed;
347
348 if (body_changed) {
349 State::merge(current, body_out, MergeMode::BRANCHES);
350 }
351
352 if (apply_after_body) {
353 apply_after_body(current);
354 }
355 } while (changing);
356
357 if (changed) {
358 changed = state.update_forward_exposed(current);
359 }
360
361 return {changed, state.forward_exposed()};
362 }
363
364 // -- While: same fixed-point strategy ---------------------------------
365
366 std::pair<bool, const ExposedType&> solve(structured_control_flow::While& loop, const ExposedType& in) {
367 return solve_loop_body(get_or_create_state(loop), loop.root(), in, nullptr);
368 }
369};
370
371} // namespace analysis
372} // namespace sdfg
BLAS (Basic Linear Algebra Subprograms) library node definitions.
Base class for forward data-flow analysis over structured control flow.
Definition structured_data_flow_analysis.h:165
virtual std::unique_ptr< State > create_initial_state(const structured_control_flow::ControlFlowNode &node)=0
State & get_or_create_state(const structured_control_flow::ControlFlowNode &node)
Definition structured_data_flow_analysis.h:212
bool has_state(const structured_control_flow::ControlFlowNode &node) const
Definition structured_data_flow_analysis.h:207
virtual ExposedType boundary()
Provide the initial set flowing into the root.
Definition structured_data_flow_analysis.h:231
void run_forward(structured_control_flow::Sequence &root)
Run the analysis starting from the given root sequence.
Definition structured_data_flow_analysis.h:190
typename State::ExposedType ExposedType
Definition structured_data_flow_analysis.h:169
const State & state(const structured_control_flow::ControlFlowNode &node) const
Retrieve the computed data-flow state for a node.
Definition structured_data_flow_analysis.h:203
A state in a Stateful DataFlow Graph (SDFG).
Definition state.h:38
Base class for all structured control flow nodes in a StructuredSDFG.
Definition control_flow_node.h:44
Represents a conditional if-else control flow node with multiple cases.
Definition if_else.h:47
A sequential container of control flow nodes.
Definition sequence.h:52
Base class for structured loop constructs.
Definition structured_loop.h:244
Represents a while-loop with condition-controlled iteration.
Definition while.h:37
Definition analysis.h:8
sdfg::ElementId ElementId
Definition structured_data_flow_analysis.h:59
MergeMode
Definition structured_data_flow_analysis.h:19
@ CUMULATIVE
Definition structured_data_flow_analysis.h:20
@ BRANCHES
Definition structured_data_flow_analysis.h:21
@ s
Definition blas_node.h:55
Definition analysis.h:7
@ State
Definition element.h:73
element_cast_target_t< T > * dyn_cast(Element *element)
Efficient down-cast to T, or nullptr if element is not a T.
Definition element.h:246
size_t ElementId
Definition element.h:215
Definition structured_data_flow_analysis.h:25
virtual bool ran_at_least_once() const =0
virtual bool update(const T &incoming)=0
All-in-one for leaf-nodes.
virtual const T & forward_exposed() const =0
Get the current state of live elements leaving the node in forward direction.
virtual ~DataFlowState()=default
virtual bool update_forward_exposed(const T &forward_exposed)=0
For non-leaf nodes: update outputs.
virtual bool update_incoming(const T &incoming)=0
For non-leaf nodes: update inputs.
T ExposedType
Definition structured_data_flow_analysis.h:26
Definition structured_data_flow_analysis.h:62
ExposedType forward_exposed_
Definition structured_data_flow_analysis.h:67
ExposedType incoming_
Definition structured_data_flow_analysis.h:66
static void merge(ExposedType &merge_into, const ExposedType &other, MergeMode mode=MergeMode::CUMULATIVE)
Definition structured_data_flow_analysis.h:119
bool ran_at_least_once() const override
Definition structured_data_flow_analysis.h:71
bool update_forward_exposed(const ExposedType &forward_exposed) override
For non-leaf nodes: update outputs.
Definition structured_data_flow_analysis.h:97
bool update_incoming(const ExposedType &incoming) override
For non-leaf nodes: update inputs.
Definition structured_data_flow_analysis.h:88
static ExposedType empty_in()
Definition structured_data_flow_analysis.h:115
virtual void apply_kills_and_changes(ExposedType &exposed) const =0
bool update(const ExposedType &incoming) override
All-in-one for leaf-nodes.
Definition structured_data_flow_analysis.h:75
DataFlowState< std::unordered_map< ElementId, T > >::ExposedType ExposedType
Definition structured_data_flow_analysis.h:63
bool ran_
Definition structured_data_flow_analysis.h:68
const ExposedType & forward_exposed() const override
Get the current state of live elements leaving the node in forward direction.
Definition structured_data_flow_analysis.h:111
Definition structured_data_flow_analysis.h:175
std::variant< structured_control_flow::ControlFlowNode *, structured_control_flow::StructuredLoop *, structured_control_flow::While *, structured_control_flow::IfElse *, structured_control_flow::Sequence * > node
Definition structured_data_flow_analysis.h:182
int index
Definition structured_data_flow_analysis.h:183