docc 0.8.3 (0d44999b)
C++ API Reference
Loading...
Searching...
No Matches
library_node_expansion_pass.h
Go to the documentation of this file.
1
32
33#pragma once
34
38#include "sdfg/passes/pass.h"
40
41namespace sdfg {
42namespace passes {
43
44class MathNodeExpander : public TypedLibNodeExpander<math::MathNode> {
45public:
47};
48
49namespace expansion {
58
59struct NodeOutcome : public BlockOutcome {
61
65};
66} // namespace expansion
67
69 using StorageType = std::shared_ptr<LibNodeExpander>;
71
72 SingleExpanderHolder(const LibNodeExpander& expander) : expander_(expander) {
73 }
75 }
76
78 return expander_.for_lib_node(node);
79 }
80};
81
82template<typename Holder>
83concept HolderPolicy = requires(Holder& h, const data_flow::LibraryNode& node) { h.get_expander_for(node); };
84
85template<HolderPolicy Holder = SingleExpanderHolder>
87
88template<HolderPolicy Holder = SingleExpanderHolder>
91
92public:
93
94private:
96 analysis::AnalysisManager& analysis_manager_;
97 bool expanded_any_ = false;
98 Holder holder_;
99 bool force_expand_;
100
101
102 expansion::NodeOutcome try_expand(Sequence& parent, size_t child_idx, Block& block, sdfg::data_flow::LibraryNode& node) {
103 auto expander = holder_.get_expander_for(node);
104
105 if (expander) {
107 ctx(this->builder_, parent, child_idx, block, node, analysis_manager_.options());
108
109 auto outcome = expander->handle_expand(ctx, block, node);
110
111 if (ctx.expanded()) {
112 ctx.cleanup();
113 return {true, ctx.dropped_block()};
114 }
115 }
116
117 return {};
118 }
119
120public:
128 analysis::AnalysisManager& analysis_manager,
129 Holder holder,
130 bool force_expand
131 )
132 : visitor::ActualStructuredSDFGVisitor(), builder_(builder), analysis_manager_(analysis_manager),
133 holder_(holder), force_expand_(force_expand) {
134 }
135
137 bool may_contain_libnodes = true;
138 size_t i = 0;
139
140 // expansion can remove and replace entire blocks, so need smarter sequence visiting that can keep iterating
141 // even when the children change expansion can only remove the current node and add 1 or more children in its
142 // stead, so idx will never decrease but we do need the info what was changed to avoid invalidated parts
143
144 do {
145 size_t total_children = seq.size();
146 if (total_children == 0) {
147 may_contain_libnodes = false;
148 } else if (i >= total_children) {
149 return true;
150 }
151
152 for (; i < total_children; ++i) {
153 auto& child = seq.at(i);
154 if (auto* block = dyn_cast<structured_control_flow::Block*>(&child)) {
155 auto outcome = handle_block(seq, i, *block);
156
157 if (outcome.block_removed) { // recheck with same i, its now a new block
158 if (outcome.skip_count) {
159 i += outcome.skip_count;
160 }
161 break;
162 } else if (outcome.skip_count) {
163 i += outcome.skip_count;
164 // +1 from for loop
165 }
166 } else {
167 dispatch(child);
168 }
169 }
170 } while (may_contain_libnodes);
171
172 return true;
173 }
174
176 auto& schedType = loop.schedule_type();
177 int scope_id = -1;
178 if constexpr (requires { holder_.scope_enter(schedType); }) {
179 scope_id = holder_.scope_enter(schedType);
180 }
181
182 auto res = ActualStructuredSDFGVisitor::handleStructuredLoop(loop);
183
184 if constexpr (requires { holder_.scope_exit(schedType); }) {
185 holder_.scope_exit(scope_id);
186 }
187
188 return res;
189 }
190
193 ) {
194 auto& dataflow = block.dataflow();
195
196 ElementId last_element_id = 0;
197
198 bool may_contain_lib_nodes = true;
199 bool handled_any = false;
200
201 const bool force_expand = force_expand_;
202
203 do {
204 // expansion may change the contents of this block or even remove it.
205 // to ensure stable order, order by element_id
206 // track the last handled element_id, because changes are not allowed to affect other libnodes.
207 // So if the current block gets invalidated (but not removed) we can restart iterating above the last
208 // processed element_id
209 auto libnodes = dataflow.nodes() | std::views::transform([](auto& n) {
210 return dynamic_cast<const data_flow::LibraryNode*>(&n);
211 }) |
212 std::views::filter([](auto* n) {
213 return n != nullptr;
214 }) |
215 std::views::filter([last_element_id, force_expand](auto* n) {
216 return (force_expand ||
217 n->implementation_type() == data_flow::ImplementationType_NONE) &&
218 n->element_id() > last_element_id;
219 });
220 std::vector<const data_flow::LibraryNode*> sorted_nodes(libnodes.begin(), libnodes.end());
221 std::ranges::sort(sorted_nodes, std::less<>{}, [](const auto* n) {
222 return n->element_id();
223 });
224
225 may_contain_lib_nodes = !libnodes.empty();
226
227 bool block_changed = false;
228 for (auto* library_node : sorted_nodes) {
229 last_element_id = library_node->element_id();
230 auto outcome = try_expand(parent, child_idx, block, *const_cast<data_flow::LibraryNode*>(library_node));
231 handled_any |= outcome.expanded;
232
233 if (outcome.block_removed) {
234 this->expanded_any_ = true;
235 return static_cast<expansion::BlockOutcome>(outcome);
236 } else if (outcome.expanded) {
237 // libnodes inside this block have become invalid
238 block_changed = true;
239 break;
240 }
241 }
242 if (block_changed) { // here as a reminder, that we must not do anything else in this iteration, as the
243 // underlying nodes might be invalid now
244 continue;
245 }
246 } while (may_contain_lib_nodes);
247
248 if (handled_any) {
249 this->expanded_any_ = true;
250 }
251
252 return {};
253 }
254};
255
260template<HolderPolicy Holder>
262 Holder::StorageType holder_options_;
263
264public:
265 static constexpr std::string_view NAME{"library_node_expansion"};
266 static constexpr OptionKey<bool> FORCE_EXPAND{"library_node_expansion.force_expand"};
267 static constexpr OptionKey<bool> ONLINE_SOFTMAX{"library_node_expansion.online_softmax"};
268
269 LibraryNodeExpansionPass() : holder_options_(std::make_shared<MathNodeExpander>()) {
270 }
272 : Pass(options), holder_options_(std::make_shared<MathNodeExpander>()) {
273 }
274 LibraryNodeExpansionPass(Holder::StorageType holder, const Options& options = Options::empty())
275 : Pass(options), holder_options_(std::move(holder)) {
276 }
277
278 std::string name() override {
279 return std::string(NAME);
280 }
281
282 std::vector<OptionSpec> options() override {
283 return {
284 FORCE_EXPAND.spec(false, "Also lower all library nodes that already have an implementation type"),
285 ONLINE_SOFTMAX.spec(
286 false,
287 "Expand softmax as the single-pass online (log-sum-exp monoid) form instead of the default "
288 "three-pass (max; exp+sum; normalize) form"
289 )
290 };
291 }
292
295 v(builder, analysis_manager, Holder(holder_options_), this->option(FORCE_EXPAND));
296
297 v.dispatch(builder.subject().root());
298
299 return v.expanded_any_;
300 }
301};
302
303// Deduction guide
304template<typename T>
306
307namespace expansion {
308
311);
312
315
316} // namespace expansion
317
318} // namespace passes
319} // namespace sdfg
Definition options.h:56
static const Options & empty()
Definition options.h:84
Definition analysis.h:53
Note: Even though the class references unique_ptr, it will never delete an SDFG it has a reference to...
Definition structured_sdfg_builder.h:44
Base class for all library nodes in the dataflow graph.
Definition library_node.h:106
Base class for mathematical library nodes with expansion support.
Definition math_node.h:68
Definition lib_node_expander.h:122
Definition lib_node_expander.h:8
Definition library_node_expansion_pass.h:89
expansion::BlockOutcome handle_block(structured_control_flow::Sequence &parent, size_t child_idx, sdfg::structured_control_flow::Block &block)
Definition library_node_expansion_pass.h:191
bool handleStructuredLoop(sdfg::structured_control_flow::StructuredLoop &loop) override
Definition library_node_expansion_pass.h:175
bool visit(sdfg::structured_control_flow::Sequence &seq) override
Definition library_node_expansion_pass.h:136
LibNodeExpansionVisitor(builder::StructuredSDFGBuilder &builder, analysis::AnalysisManager &analysis_manager, Holder holder, bool force_expand)
Construct the expansion visitor.
Definition library_node_expansion_pass.h:126
Looks for and expands library nodes in a single pass, potentially recursively.
Definition library_node_expansion_pass.h:261
std::string name() override
Definition library_node_expansion_pass.h:278
std::vector< OptionSpec > options() override
Definition library_node_expansion_pass.h:282
static constexpr OptionKey< bool > FORCE_EXPAND
Definition library_node_expansion_pass.h:266
LibraryNodeExpansionPass(const Options &options)
Definition library_node_expansion_pass.h:271
LibraryNodeExpansionPass(Holder::StorageType holder, const Options &options=Options::empty())
Definition library_node_expansion_pass.h:274
bool run_pass(builder::StructuredSDFGBuilder &builder, analysis::AnalysisManager &analysis_manager) override
Definition library_node_expansion_pass.h:293
static constexpr std::string_view NAME
Definition library_node_expansion_pass.h:265
LibraryNodeExpansionPass()
Definition library_node_expansion_pass.h:269
static constexpr OptionKey< bool > ONLINE_SOFTMAX
Definition library_node_expansion_pass.h:267
Definition library_node_expansion_pass.h:44
LibNodeExpander::ExpandOutcome handle_expand(ExpandContext &context, Block &block, math::MathNode &node) const override
T option(const OptionKey< T > &key, T fallback=T{}) const
Definition pass.h:41
Definition lib_node_expander.h:168
Definition lib_node_expansion_context.h:9
bool expanded() const
Definition lib_node_expansion_context.h:45
bool dropped_block() const
Definition lib_node_expansion_context.h:49
A control flow node representing a basic block with dataflow computations.
Definition block.h:42
const data_flow::DataFlowGraph & dataflow() const
Access the dataflow graph (const version).
A sequential container of control flow nodes.
Definition sequence.h:52
const ControlFlowNode & at(size_t i) const
Access a child by index (const version).
size_t size() const
Get the number of children in this sequence.
Base class for structured loop constructs.
Definition structured_loop.h:244
const ScheduleType & schedule_type() const
Get the scheduling strategy for this Map.
Visitor for Structured SDFG (not a builder).
Definition structured_sdfg_visitor.h:71
bool dispatch(sdfg::structured_control_flow::ControlFlowNode &node)
Definition structured_sdfg_visitor.h:79
Definition library_node_expansion_pass.h:83
Mathematical library node base class with expansion support.
Definition function_builder.h:10
ImplementationType ImplementationType_NONE
Default implementation type indicating no specific implementation.
Definition library_node.h:84
Definition lib_node_expansion_context.h:5
expansion::NodeOutcome expand_single_node(builder::StructuredSDFGBuilder &builder, Block &block, data_flow::LibraryNode &node, const LibNodeExpander &expanders)
expansion::NodeOutcome expand_single_math_node(builder::StructuredSDFGBuilder &builder, Block &block, data_flow::LibraryNode &node)
Definition approximate_math.h:12
LibraryNodeExpansionPass(T) -> LibraryNodeExpansionPass< T >
Definition control_flow_node.h:16
Definition analysis.h:7
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 options.h:40
Definition lib_node_expander.h:12
SingleExpanderHolder(StorageType expander)
Definition library_node_expansion_pass.h:74
std::shared_ptr< LibNodeExpander > StorageType
Definition library_node_expansion_pass.h:69
const LibNodeExpander & expander_
Definition library_node_expansion_pass.h:70
SingleExpanderHolder(const LibNodeExpander &expander)
Definition library_node_expansion_pass.h:72
const LibNodeExpander * get_expander_for(const data_flow::LibraryNode &node) const
Definition library_node_expansion_pass.h:77
Definition library_node_expansion_pass.h:50
bool block_removed
Definition library_node_expansion_pass.h:51
int skip_count
Definition library_node_expansion_pass.h:52
BlockOutcome(bool block_removed=false, int skip_count=0)
Definition library_node_expansion_pass.h:54
Definition library_node_expansion_pass.h:59
NodeOutcome(bool expanded=false, bool block_removed=false, int skip_count=0)
Definition library_node_expansion_pass.h:62
bool expanded
Definition library_node_expansion_pass.h:60