27template<
typename LibNode>
29 return blk->
dataflow().template is_a_library_node<LibNode>() !=
nullptr;
33template<
typename LibNode>
35 return blk->
dataflow().template is_a_library_node<LibNode>();
39template<
typename LibNode>
42 if (lib_node ==
nullptr) {
47 if (dataflow.out_degree(*lib_node) > 0) {
48 for (
auto& edge : dataflow.out_edges(*lib_node)) {
50 if (access !=
nullptr && access->data() == ref_container) {
60template<
typename LibNode>
63 if (lib_node ==
nullptr) {
68 for (
auto& edge : dataflow.in_edges(*lib_node)) {
70 if (access !=
nullptr && access->data() == ref_container) {
78template<
typename LibNode>
81 if (lib_node ==
nullptr) {
86 if (dataflow.out_degree(*lib_node) > 0) {
87 for (
auto& edge : dataflow.out_edges(*lib_node)) {
89 if (access !=
nullptr && access->data() == ref_container) {
95 for (
auto& edge : dataflow.in_edges(*lib_node)) {
97 if (access !=
nullptr && access->data() == ref_container) {
108template<
class... LibNodes>
111 static constexpr size_t N =
sizeof...(LibNodes);
115 if (dataflow.nodes().size() != 2) {
118 if (dataflow.edges().size() != 1) {
121 auto& edge = *dataflow.
edges().begin();
123 if (access_src ==
nullptr || access_src->data() != container) {
127 if (access_dst ==
nullptr) {
130 return access_dst->
data();
135 if (idx >=
static_cast<int>(seq.
size())) {
139 if (blk ==
nullptr) {
147 using LibNodeAt =
typename std::tuple_element<I, std::tuple<LibNodes...>>::type;
152 std::pair<std::string, std::string>
154 int malloc_idx = base_idx + K * 3;
155 int ref_idx = malloc_idx + 1;
156 int lib_idx = malloc_idx + 2;
158 auto* malloc_blk = get_block(seq, malloc_idx);
159 auto* ref_blk = get_block(seq, ref_idx);
160 auto* lib_blk = get_block(seq, lib_idx);
162 if (!malloc_blk || !ref_blk || !lib_blk) {
166 auto* malloc_node = malloc_blk->template is_a_library_node<stdlib::MallocNode>();
167 if (malloc_node ==
nullptr) {
172 auto& dst = (*malloc_blk->dataflow().out_edges(*malloc_node).begin()).dst();
176 std::string ref_container = references(*ref_blk, malloc_container);
177 if (ref_container.empty()) {
187 if constexpr (K == 0) {
193 else if constexpr (K == N - 1) {
211 return {malloc_container, ref_container};
216 bool verify_all_triples(
220 const std::string& prev_ref_container,
221 std::vector<std::string>& malloc_containers,
222 std::vector<std::string>& ref_containers
224 auto [malloc_container, ref_container] = verify_triple<K>(seq, base_idx, prev_ref_container);
225 if (malloc_container.empty()) {
230 if constexpr (K > 0) {
231 int malloc_idx = base_idx + K * 3;
232 auto* malloc_blk = get_block(seq, malloc_idx);
233 auto* malloc_node = malloc_blk->template is_a_library_node<stdlib::MallocNode>();
234 if (!
symbolic::eq(first_malloc_size, malloc_node->size())) {
239 malloc_containers.push_back(malloc_container);
240 ref_containers.push_back(ref_container);
242 if constexpr (K + 1 < N) {
243 return verify_all_triples<
244 K + 1>(seq, base_idx, first_malloc_size, ref_container, malloc_containers, ref_containers);
251 auto users = users_analysis.
uses(malloc_container);
252 if (
users.size() != 3) {
256 for (
auto& user :
users) {
258 auto& parent_graph = access_node->get_parent();
260 if (parent_blk !=
nullptr && parent_blk->dataflow().is_a_library_node<
stdlib::FreeNode>() !=
nullptr) {
270 if (free_blk ==
nullptr) {
275 if (parent_scope ==
nullptr) {
279 int free_blk_index = parent_scope->index(*free_blk);
280 builder_.remove_child(*parent_scope, free_blk_index);
290 return "LocalBufferReuseN";
294 bool applied =
false;
299 constexpr int pattern_size = N * 3;
302 while (i + pattern_size <=
static_cast<int>(node.
size())) {
303 std::vector<std::string> malloc_containers;
304 std::vector<std::string> ref_containers;
307 auto* first_malloc_blk = get_block(node, i);
308 if (!first_malloc_blk) {
312 auto* first_malloc = first_malloc_blk->template is_a_library_node<stdlib::MallocNode>();
319 if (!verify_all_triples<0>(node, i, first_malloc->
size(),
"", malloc_containers, ref_containers)) {
328 std::vector<structured_control_flow::Block*> free_blocks;
329 bool all_constraints_met =
true;
330 for (
int k = 1; k < static_cast<int>(N); k++) {
331 auto* free_blk = find_free_block(malloc_containers[k], users_analysis);
332 if (free_blk ==
nullptr) {
333 all_constraints_met =
false;
337 if (parent_scope ==
nullptr) {
338 all_constraints_met =
false;
341 free_blocks.push_back(free_blk);
344 if (!all_constraints_met) {
350 for (
int k = N - 1; k >= 1; k--) {
352 int ref_idx = i + k * 3 + 1;
353 auto* ref_blk = get_block(node, ref_idx);
355 for (
auto& n : ref_blk->dataflow().nodes()) {
357 if (access !=
nullptr && access->data() == malloc_containers[k]) {
358 access->data(ref_containers[k - 1]);
364 int malloc_idx = i + k * 3;
365 builder_.remove_child(node, malloc_idx);
368 remove_free_block(free_blocks[k - 1]);
371 "Eliminated tensor with containers " << malloc_containers[0] <<
" and " << malloc_containers[k]
384template<
class T,
class S>
410 Pipeline pipeline(
"LocalBufferReusePipeline");
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
Node representing access to a data container in the dataflow graph.
Definition access_node.h:84
const std::string & data() const
Get the name of the data container.
auto edges() const
Definition data_flow_graph.h:76
In N, C, D0...Dn tensor, applies normalization to per channel in C across all the inner dimensions.
Definition batchnorm_node.h:14
Convolution operation following ONNX Conv operator specification.
Definition conv_node.h:72
Definition relu_node.h:14
Definition local_buffer_reuse.h:109
LocalBufferReuseN(builder::StructuredSDFGBuilder &builder, analysis::AnalysisManager &analysis_manager)
Definition local_buffer_reuse.h:285
static std::string name()
Definition local_buffer_reuse.h:289
virtual bool accept(structured_control_flow::Sequence &node) override
Definition local_buffer_reuse.h:293
void register_pass(Args &&... args)
Definition pipeline.h:43
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).
ControlFlowNode * get_parent()
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.
std::vector< User * > uses() const
Definition structured_sdfg_visitor.h:53
NonStoppingStructuredSDFGVisitor(builder::StructuredSDFGBuilder &builder, analysis::AnalysisManager &analysis_manager)
analysis::AnalysisManager & analysis_manager_
Definition structured_sdfg_visitor.h:19
builder::StructuredSDFGBuilder & builder_
Definition structured_sdfg_visitor.h:18
bool eq(const Expression lhs, const Expression rhs)
Tests structural equality of two expressions.
SymEngine::RCP< const SymEngine::Basic > Expression
Reference-counted pointer to a symbolic expression (SymEngine Basic).
Definition symbolic.h:83
#define DEBUG_PRINTLN(msg)
Definition helpers.h:12
Definition function_builder.h:10
Definition local_buffer_reuse.h:24
bool lib_node_uses_ref(structured_control_flow::Block *blk, const std::string &ref_container)
Definition local_buffer_reuse.h:79
bool block_has_lib_node(structured_control_flow::Block *blk)
Definition local_buffer_reuse.h:28
LibNode * get_lib_node(structured_control_flow::Block *blk)
Definition local_buffer_reuse.h:34
bool lib_node_reads_from_ref(structured_control_flow::Block *blk, const std::string &ref_container)
Definition local_buffer_reuse.h:61
bool lib_node_writes_to_ref(structured_control_flow::Block *blk, const std::string &ref_container)
Definition local_buffer_reuse.h:40
Definition approximate_math.h:12
VisitorPass< LocalBufferReuseN< math::tensor::ConvNode, math::tensor::BatchNormNode, math::tensor::ReLUNode > > ConvBatchNormReLUEliminationPass
Definition local_buffer_reuse.h:393
LocalBufferReuseN< T, S > LocalBufferReuse
Definition local_buffer_reuse.h:385
VisitorPass< LocalBufferReuseN< math::tensor::ConvNode, math::tensor::BatchNormNode, math::tensor::ReLUNode, math::tensor::ConvNode > > ConvBatchNormReLUConvEliminationPass
Definition local_buffer_reuse.h:398
VisitorPass< LocalBufferReuseN< math::tensor::ConvNode, math::tensor::BatchNormNode > > ConvBatchNormEliminationPass
Definition local_buffer_reuse.h:388
VisitorPass< LocalBufferReuseN< math::tensor::ConvNode, math::tensor::BatchNormNode, math::tensor::ReLUNode, math::tensor::ConvNode, math::tensor::BatchNormNode > > ConvBatchNormReLUConvBatchNormEliminationPass
Definition local_buffer_reuse.h:407
Pipeline local_buffer_reuse_pipeline()
Definition local_buffer_reuse.h:409
VisitorPass< LocalBufferReuseN< math::tensor::BatchNormNode, math::tensor::ReLUNode > > BatchNormReLUEliminationPass
Definition local_buffer_reuse.h:389
Definition base_user_visitor.h:5
Definition control_flow_node.h:16
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