• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / docc / 26556322966

27 May 2026 03:45PM UTC coverage: 60.869% (-0.02%) from 60.886%
26556322966

push

github

web-flow
Libnode ptr edges (#719)

Migrating SDFGs to treat pointers as inputs to libNodes / Calls as scalars.
A pointer will only appear in an output edge if its actually returned from the function (like malloc).

* Stdlib, Blas and Tensor Matmul nodes were migrated to this new format. Other, currently transitory Tensor Nodes are not yet migrated.
* DOCC version was bumped to incorporate previous docc-llvm versions (up to 0.4.0) that had been counted separately.
! Until all passes consider the use / leak of pointers as uncertainty / hiding potential writes, TensorNodes are declared as general side-effect.
* Lots of utility functions to centralize the creation (and edges) of various libNodes that needed to be changed.
* Fixed & unified docc paths across python and llvm front-ends.
* Skip BlockFusion test that fails to its libNodes currently having side effects
~ Prevent a crash in DotViz when using symbolic offsets into structs
* Removing old ConstProp pass, it is not safe for the new pointer representation and should not be all too critical

961 of 1749 new or added lines in 52 files covered. (54.95%)

87 existing lines in 28 files now uncovered.

35225 of 57870 relevant lines covered (60.87%)

11046.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.26
/sdfg/src/builder/structured_sdfg_builder.cpp
1
#include "sdfg/builder/structured_sdfg_builder.h"
2

3
#include <cstddef>
4

5
#include "sdfg/data_flow/library_node.h"
6
#include "sdfg/structured_control_flow/map.h"
7
#include "sdfg/structured_control_flow/sequence.h"
8
#include "sdfg/structured_control_flow/structured_loop.h"
9
#include "sdfg/types/utils.h"
10

11
#define TRAVERSE_CUTOFF 30
100✔
12

13
using namespace sdfg::control_flow;
14
using namespace sdfg::structured_control_flow;
15

16
namespace sdfg {
17
namespace builder {
18

19
std::unordered_set<const control_flow::State*> StructuredSDFGBuilder::
20
    determine_loop_nodes(SDFG& sdfg, const control_flow::State& start, const control_flow::State& end) const {
13✔
21
    std::unordered_set<const control_flow::State*> nodes;
13✔
22
    std::unordered_set<const control_flow::State*> visited;
13✔
23
    std::list<const control_flow::State*> queue = {&start};
13✔
24
    while (!queue.empty()) {
56✔
25
        auto curr = queue.front();
43✔
26
        queue.pop_front();
43✔
27
        if (visited.find(curr) != visited.end()) {
43✔
28
            continue;
1✔
29
        }
1✔
30
        visited.insert(curr);
42✔
31

32
        nodes.insert(curr);
42✔
33
        if (curr == &end) {
42✔
34
            continue;
13✔
35
        }
13✔
36

37
        for (auto& iedge : sdfg.in_edges(*curr)) {
30✔
38
            queue.push_back(&iedge.src());
30✔
39
        }
30✔
40
    }
29✔
41

42
    // Iteratively expand nodes to reduce frontier size
43
    auto dom_tree = sdfg.dominator_tree();
13✔
44
    auto dominates = [&](const control_flow::State* a, const control_flow::State* b) {
13✔
45
        const control_flow::State* curr = b;
12✔
46
        while (curr != nullptr) {
42✔
47
            if (curr == a) return true;
42✔
48
            if (dom_tree.find(curr) == dom_tree.end()) break;
30✔
49
            curr = dom_tree.at(curr);
30✔
50
        }
30✔
51
        return false;
×
52
    };
12✔
53

54
    // Identify header exits
55
    std::unordered_set<const control_flow::State*> stop_nodes;
13✔
56
    for (auto& edge : sdfg.out_edges(end)) {
24✔
57
        if (nodes.find(&edge.dst()) == nodes.end()) {
24✔
58
            stop_nodes.insert(&edge.dst());
11✔
59
        }
11✔
60
    }
24✔
61

62
    // If no header exits, check latch exits (Do-While)
63
    if (stop_nodes.empty()) {
13✔
64
        for (auto& edge : sdfg.out_edges(start)) {
4✔
65
            if (nodes.find(&edge.dst()) == nodes.end()) {
4✔
66
                stop_nodes.insert(&edge.dst());
2✔
67
            }
2✔
68
        }
4✔
69
    }
2✔
70

71
    // If still no exits, check any natural loop exit (e.g. infinite loop with break)
72
    if (stop_nodes.empty()) {
13✔
73
        for (auto node : nodes) {
×
74
            for (auto& edge : sdfg.out_edges(*node)) {
×
75
                if (nodes.find(&edge.dst()) == nodes.end()) {
×
76
                    stop_nodes.insert(&edge.dst());
×
77
                }
×
78
            }
×
79
        }
×
80
    }
×
81

82
    while (true) {
21✔
83
        std::unordered_set<const control_flow::State*> frontier;
21✔
84
        for (auto node : nodes) {
85✔
85
            for (auto& edge : sdfg.out_edges(*node)) {
139✔
86
                if (nodes.find(&edge.dst()) == nodes.end()) {
139✔
87
                    frontier.insert(&edge.dst());
40✔
88
                }
40✔
89
            }
139✔
90
        }
85✔
91

92
        bool changed = false;
21✔
93
        for (auto f : frontier) {
33✔
94
            // If f is a stop node, do not include it
95
            if (stop_nodes.find(f) != stop_nodes.end()) {
33✔
96
                continue;
21✔
97
            }
21✔
98
            // If f is dominated by the header, it belongs to the loop body (extended)
99
            if (dominates(&end, f)) {
12✔
100
                nodes.insert(f);
12✔
101
                changed = true;
12✔
102
            }
12✔
103
        }
12✔
104

105
        if (!changed) break;
21✔
106
    }
21✔
107

108
    return nodes;
13✔
109
};
13✔
110

111
bool post_dominates(
112
    const State* pdom,
113
    const State* node,
114
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree
115
) {
21✔
116
    if (pdom == node) {
21✔
117
        return true;
12✔
118
    }
12✔
119

120
    auto current = pdom_tree.at(node);
9✔
121
    while (current != nullptr) {
9✔
122
        if (current == pdom) {
3✔
123
            return true;
3✔
124
        }
3✔
125
        current = pdom_tree.at(current);
×
126
    }
×
127

128
    return false;
6✔
129
}
9✔
130

131

132
void StructuredSDFGBuilder::traverse(SDFG& sdfg) {
16✔
133
    // Start of SDFGS
134
    Sequence& root = *structured_sdfg_->root_;
16✔
135
    const State* start_state = &sdfg.start_state();
16✔
136

137
    auto pdom_tree = sdfg.post_dominator_tree();
16✔
138

139
    std::unordered_set<const InterstateEdge*> breaks;
16✔
140
    std::unordered_set<const InterstateEdge*> continues;
16✔
141
    for (auto& edge : sdfg.back_edges()) {
16✔
142
        continues.insert(edge);
13✔
143
    }
13✔
144

145
    this->current_traverse_loop_ = nullptr;
16✔
146
    std::unordered_set<const control_flow::State*> visited;
16✔
147
    this->structure_region(sdfg, root, start_state, nullptr, continues, breaks, pdom_tree, visited);
16✔
148
};
16✔
149

150
void StructuredSDFGBuilder::structure_region(
151
    SDFG& sdfg,
152
    Sequence& scope,
153
    const State* entry,
154
    const State* exit,
155
    const std::unordered_set<const InterstateEdge*>& continues,
156
    const std::unordered_set<const InterstateEdge*>& breaks,
157
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
158
    std::unordered_set<const control_flow::State*>& visited,
159
    bool is_loop_body
160
) {
64✔
161
    const State* current = entry;
64✔
162
    while (current != exit) {
138✔
163
        if (current == nullptr) {
100✔
164
            break;
×
165
        }
×
166

167

168
        // Cutoff
169
        if (this->function().element_counter_ > sdfg.states().size() * TRAVERSE_CUTOFF) {
100✔
170
            throw UnstructuredControlFlowException();
×
171
        }
×
172

173
        if (visited.find(current) != visited.end()) {
100✔
174
            throw UnstructuredControlFlowException();
×
175
        }
×
176
        visited.insert(current);
100✔
177

178
        // Loop detection
179
        bool is_loop_header = false;
100✔
180
        if (!is_loop_body || current != entry) {
100✔
181
            for (auto& iedge : sdfg.in_edges(*current)) {
100✔
182
                if (continues.find(&iedge) != continues.end()) {
100✔
183
                    is_loop_header = true;
9✔
184
                    break;
9✔
185
                }
9✔
186
            }
100✔
187
        }
91✔
188

189
        if (is_loop_header) {
100✔
190
            // 1. Determine nodes of loop body
191
            std::unordered_set<const InterstateEdge*> loop_edges;
9✔
192
            for (auto& iedge : sdfg.in_edges(*current)) {
22✔
193
                if (continues.find(&iedge) != continues.end()) {
22✔
194
                    loop_edges.insert(&iedge);
13✔
195
                }
13✔
196
            }
22✔
197

198
            std::unordered_set<const control_flow::State*> body;
9✔
199
            for (auto back_edge : loop_edges) {
13✔
200
                auto loop_nodes = this->determine_loop_nodes(sdfg, back_edge->src(), back_edge->dst());
13✔
201
                body.insert(loop_nodes.begin(), loop_nodes.end());
13✔
202
            }
13✔
203

204
            // 2. Determine exit states and exit edges
205
            std::unordered_set<const control_flow::State*> exit_states;
9✔
206
            std::unordered_set<const control_flow::InterstateEdge*> exit_edges;
9✔
207
            for (auto node : body) {
34✔
208
                for (auto& edge : sdfg.out_edges(*node)) {
52✔
209
                    if (body.find(&edge.dst()) == body.end()) {
52✔
210
                        if (continues.find(&edge) != continues.end()) {
12✔
211
                            continue;
×
212
                        }
×
213
                        exit_edges.insert(&edge);
12✔
214
                        exit_states.insert(&edge.dst());
12✔
215
                    }
12✔
216
                }
52✔
217
            }
34✔
218

219
            if (exit_states.size() > 1) {
9✔
220
                std::unordered_set<const control_flow::State*> non_return_exits;
×
221
                for (auto s : exit_states) {
×
222
                    if (dynamic_cast<const control_flow::ReturnState*>(s)) {
×
223
                        continue;
×
224
                    }
×
225
                    if (sdfg.out_degree(*s) > 0) {
×
226
                        non_return_exits.insert(s);
×
227
                    }
×
228
                }
×
229
                if (non_return_exits.size() == 1) {
×
230
                    exit_states = non_return_exits;
×
231
                }
×
232
            }
×
233

234
            if (exit_states.size() != 1) {
9✔
235
                throw UnstructuredControlFlowException();
×
236
            }
×
237
            const control_flow::State* exit_state = *exit_states.begin();
9✔
238

239
            for (auto& edge : breaks) {
9✔
240
                exit_edges.insert(edge);
1✔
241
            }
1✔
242

243
            // Collect debug information
244
            DebugInfo dbg_info = current->debug_info();
9✔
245
            for (auto& edge : sdfg.in_edges(*current)) {
22✔
246
                dbg_info = DebugInfo::merge(dbg_info, edge.debug_info());
22✔
247
            }
22✔
248
            for (auto node : body) {
34✔
249
                dbg_info = DebugInfo::merge(dbg_info, node->debug_info());
34✔
250
            }
34✔
251
            for (auto edge : exit_edges) {
13✔
252
                dbg_info = DebugInfo::merge(dbg_info, edge->debug_info());
13✔
253
            }
13✔
254

255
            // 3. Add while loop
256
            While& loop = this->add_while(scope, {}, dbg_info);
9✔
257
            auto last_loop_ = this->current_traverse_loop_;
9✔
258
            this->current_traverse_loop_ = &loop;
9✔
259

260
            std::unordered_set<const control_flow::State*> loop_visited(visited);
9✔
261
            loop_visited.erase(current);
9✔
262

263
            this->structure_region(
9✔
264
                sdfg, loop.root(), current, exit_state, continues, exit_edges, pdom_tree, loop_visited, true
9✔
265
            );
9✔
266
            this->current_traverse_loop_ = last_loop_;
9✔
267

268
            current = exit_state;
9✔
269
            continue;
9✔
270
        }
9✔
271

272
        auto out_edges = sdfg.out_edges(*current);
91✔
273
        auto out_degree = sdfg.out_degree(*current);
91✔
274

275
        // Case 1: Sink node
276
        if (out_degree == 0) {
91✔
277
            if (!std::ranges::empty(current->dataflow().nodes())) {
17✔
278
                this->add_block(scope, current->dataflow(), {}, current->debug_info());
×
279
            }
×
280

281
            auto return_state = dynamic_cast<const control_flow::ReturnState*>(current);
17✔
282
            assert(return_state != nullptr);
17✔
283
            if (return_state->is_data()) {
17✔
284
                this->add_return(scope, return_state->data(), {}, return_state->debug_info());
17✔
285
            } else if (return_state->is_constant()) {
17✔
286
                this->add_constant_return(
×
287
                    scope, return_state->data(), return_state->type(), {}, return_state->debug_info()
×
288
                );
×
289
            } else {
×
290
                assert(false && "Unknown return state type");
×
291
            }
×
292

293
            break;
17✔
294
        }
17✔
295

296
        // Case 2: Transition
297
        if (out_degree == 1) {
74✔
298
            auto& oedge = *out_edges.begin();
45✔
299
            if (!oedge.is_unconditional()) {
45✔
300
                throw UnstructuredControlFlowException();
×
301
            }
×
302

303
            if (!std::ranges::empty(current->dataflow().nodes()) || !oedge.assignments().empty()) {
45✔
304
                this->add_block(scope, current->dataflow(), oedge.assignments(), current->debug_info());
10✔
305
            }
10✔
306

307
            if (continues.find(&oedge) != continues.end()) {
45✔
308
                if (this->current_traverse_loop_ == nullptr) {
7✔
309
                    throw UnstructuredControlFlowException();
×
310
                }
×
311
                this->add_continue(scope, {}, oedge.debug_info());
7✔
312
                break;
7✔
313
            } else if (breaks.find(&oedge) != breaks.end()) {
38✔
314
                if (this->current_traverse_loop_ == nullptr) {
1✔
315
                    throw UnstructuredControlFlowException();
×
316
                }
×
317
                this->add_break(scope, {}, oedge.debug_info());
1✔
318
                break;
1✔
319
            } else {
37✔
320
                current = &oedge.dst();
37✔
321
            }
37✔
322
            continue;
37✔
323
        }
45✔
324

325
        // Case 3: Branches
326
        if (out_degree > 1) {
29✔
327
            if (!std::ranges::empty(current->dataflow().nodes())) {
29✔
328
                this->add_block(scope, current->dataflow(), {}, current->debug_info());
×
329
            }
×
330

331
            // Determine Merge Point
332
            const State* merge = nullptr;
29✔
333
            if (pdom_tree.find(current) != pdom_tree.end()) {
29✔
334
                merge = pdom_tree.at(current);
29✔
335
            }
29✔
336

337

338
            // If merge is beyond exit, clamp to exit
339
            if (exit != nullptr && merge != nullptr) {
29✔
340
                if (post_dominates(merge, exit, pdom_tree)) {
21✔
341
                    merge = exit;
15✔
342
                }
15✔
343
            }
21✔
344

345
            if (merge != nullptr && visited.find(merge) != visited.end()) {
29✔
346
                merge = exit;
4✔
347
            }
4✔
348

349
            if (merge == nullptr && exit != nullptr) {
29✔
350
                merge = exit;
×
351
            }
×
352

353
            auto& if_else = this->add_if_else(scope, {}, current->debug_info());
29✔
354
            for (auto& out_edge : out_edges) {
57✔
355
                auto& branch = this->add_case(if_else, out_edge.condition(), out_edge.debug_info());
57✔
356
                if (!out_edge.assignments().empty()) {
57✔
357
                    this->add_block(branch, out_edge.assignments(), out_edge.debug_info());
5✔
358
                }
5✔
359
                if (continues.find(&out_edge) != continues.end()) {
57✔
360
                    if (this->current_traverse_loop_ == nullptr) {
7✔
361
                        throw UnstructuredControlFlowException();
1✔
362
                    }
1✔
363
                    this->add_continue(branch, {}, out_edge.debug_info());
6✔
364
                } else if (breaks.find(&out_edge) != breaks.end()) {
50✔
365
                    if (this->current_traverse_loop_ == nullptr) {
11✔
366
                        throw UnstructuredControlFlowException();
×
367
                    }
×
368
                    this->add_break(branch, {}, out_edge.debug_info());
11✔
369
                } else {
39✔
370
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
39✔
371
                    this->structure_region(
39✔
372
                        sdfg, branch, &out_edge.dst(), merge, continues, breaks, pdom_tree, branch_visited
39✔
373
                    );
39✔
374
                }
39✔
375
            }
57✔
376

377
            current = merge;
28✔
378
            continue;
28✔
379
        }
29✔
380
    }
29✔
381
}
64✔
382

383
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
54,404✔
384

385
StructuredSDFGBuilder::StructuredSDFGBuilder(StructuredSDFG& sdfg)
386
    : FunctionBuilder(), structured_sdfg_(&sdfg, owned(false)) {};
×
387

388
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
389
    : FunctionBuilder(), structured_sdfg_(sdfg.release(), owned(true)) {};
295✔
390

391
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
392
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type), owned(true)) {};
1,693✔
393

394
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
395
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type, return_type), owned(true)) {};
35✔
396

397
StructuredSDFGBuilder::StructuredSDFGBuilder(SDFG& sdfg)
398
    : FunctionBuilder(),
16✔
399
      structured_sdfg_(new StructuredSDFG(sdfg.name(), sdfg.type(), sdfg.return_type()), owned(true)) {
16✔
400
    for (auto& entry : sdfg.structures_) {
16✔
401
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
402
    }
×
403

404
    for (auto& entry : sdfg.containers_) {
27✔
405
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
27✔
406
    }
27✔
407

408
    for (auto& arg : sdfg.arguments_) {
16✔
409
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
410
    }
2✔
411

412
    for (auto& ext : sdfg.externals_) {
16✔
413
        this->structured_sdfg_->externals_.push_back(ext);
1✔
414
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
1✔
415
    }
1✔
416

417
    for (auto& entry : sdfg.assumptions_) {
25✔
418
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
25✔
419
    }
25✔
420

421
    for (auto& entry : sdfg.metadata_) {
16✔
422
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
423
    }
2✔
424

425
    this->traverse(sdfg);
16✔
426
};
16✔
427

428
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
6,581✔
429

430
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
552✔
431
#ifndef NDEBUG
552✔
432
    this->structured_sdfg_->validate();
552✔
433
#endif
552✔
434

435
    if (!structured_sdfg_.get_deleter().should_delete_) {
552✔
436
        throw InvalidSDFGException("StructuredSDFGBuilder: Cannot move a non-owned SDFG");
×
437
    }
×
438

439
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
552✔
440
};
552✔
441

442
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
443
    FunctionBuilder::rename_container(old_name, new_name);
×
444

445
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
446
};
×
447

448
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
54✔
449
    auto& sdfg = this->subject();
54✔
450
    std::list<Element*> queue = {&sdfg.root()};
54✔
451
    while (!queue.empty()) {
230✔
452
        auto current = queue.front();
230✔
453
        queue.pop_front();
230✔
454

455
        if (current->element_id() == element_id) {
230✔
456
            return current;
54✔
457
        }
54✔
458

459
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
176✔
460
            auto& dataflow = block_stmt->dataflow();
8✔
461
            for (auto& node : dataflow.nodes()) {
31✔
462
                queue.push_back(&node);
31✔
463
            }
31✔
464
            for (auto& edge : dataflow.edges()) {
23✔
465
                queue.push_back(&edge);
23✔
466
            }
23✔
467
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
168✔
468
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
170✔
469
                queue.push_back(&sequence_stmt->at(i).first);
87✔
470
                queue.push_back(&sequence_stmt->at(i).second);
87✔
471
            }
87✔
472
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
85✔
473
            // Do nothing
474
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
85✔
475
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
476
                queue.push_back(&if_else_stmt->at(i).first);
×
477
            }
×
478
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
85✔
479
            queue.push_back(&for_stmt->root());
5✔
480
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
80✔
481
            queue.push_back(&while_stmt->root());
×
482
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
80✔
483
            // Do nothing
484
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
80✔
485
            // Do nothing
486
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
80✔
487
            queue.push_back(&map_stmt->root());
27✔
488
        }
27✔
489
    }
176✔
490

491
    return nullptr;
×
492
};
54✔
493

494
Sequence& StructuredSDFGBuilder::
495
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
28✔
496
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
28✔
497

498
    parent.transitions_
28✔
499
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
28✔
500
        );
28✔
501

502
    return static_cast<Sequence&>(*parent.children_.back().get());
28✔
503
};
28✔
504

505
Sequence& StructuredSDFGBuilder::add_sequence_before(
506
    Sequence& parent,
507
    ControlFlowNode& child,
508
    const sdfg::control_flow::Assignments& assignments,
509
    const DebugInfo& debug_info
510
) {
579✔
511
    int index = parent.index(child);
579✔
512
    if (index == -1) {
579✔
513
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
514
    }
×
515

516
    parent.children_.insert(
579✔
517
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
579✔
518
    );
579✔
519

520
    parent.transitions_.insert(
579✔
521
        parent.transitions_.begin() + index,
579✔
522
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
579✔
523
    );
579✔
524

525
    return static_cast<Sequence&>(*parent.children_.at(index).get());
579✔
526
};
579✔
527

528
Sequence& StructuredSDFGBuilder::add_sequence_after(
529
    Sequence& parent,
530
    ControlFlowNode& child,
531
    const sdfg::control_flow::Assignments& assignments,
532
    const DebugInfo& debug_info
533
) {
×
534
    int index = parent.index(child);
×
535
    if (index == -1) {
×
536
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
537
    }
×
538

539
    parent.children_.insert(
×
540
        parent.children_.begin() + index + 1,
×
541
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
542
    );
×
543

544
    parent.transitions_.insert(
×
545
        parent.transitions_.begin() + index + 1,
×
546
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
547
    );
×
548

549
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
550
};
×
551

552
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
553
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
554
    int index = parent.index(child);
×
555
    if (index == -1) {
×
556
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
557
    }
×
558

559
    parent.children_.insert(
×
560
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
561
    );
×
562

563
    parent.transitions_.insert(
×
564
        parent.transitions_.begin() + index,
×
565
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
566
    );
×
567

568
    auto new_entry = parent.at(index);
×
569
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
570

571
    return {new_block, new_entry.second};
×
572
};
×
573

574
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
825✔
575
    parent.children_.erase(parent.children_.begin() + index);
825✔
576
    parent.transitions_.erase(parent.transitions_.begin() + index);
825✔
577
};
825✔
578

579
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
580
    parent.children_.clear();
×
581
    parent.transitions_.clear();
×
582
};
×
583

584
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
114✔
585
    size_t target_index = target.size();
114✔
586
    if (&source == &target) {
114✔
587
        target_index--;
×
588
    }
×
589
    this->move_child(source, source_index, target, target_index);
114✔
590
};
114✔
591

592
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
142✔
593
    auto node_ptr = std::move(source.children_.at(source_index));
142✔
594
    auto trans_ptr = std::move(source.transitions_.at(source_index));
142✔
595
    source.children_.erase(source.children_.begin() + source_index);
142✔
596
    source.transitions_.erase(source.transitions_.begin() + source_index);
142✔
597

598
    trans_ptr->parent_ = &target;
142✔
599
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
142✔
600
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
142✔
601
};
142✔
602

603
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
209✔
604
    this->move_children(source, target, target.size());
209✔
605
};
209✔
606

607
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
232✔
608
    target.children_.insert(
232✔
609
        target.children_.begin() + target_index,
232✔
610
        std::make_move_iterator(source.children_.begin()),
232✔
611
        std::make_move_iterator(source.children_.end())
232✔
612
    );
232✔
613
    target.transitions_.insert(
232✔
614
        target.transitions_.begin() + target_index,
232✔
615
        std::make_move_iterator(source.transitions_.begin()),
232✔
616
        std::make_move_iterator(source.transitions_.end())
232✔
617
    );
232✔
618
    for (auto& trans : target.transitions_) {
443✔
619
        trans->parent_ = &target;
443✔
620
    }
443✔
621
    source.children_.clear();
232✔
622
    source.transitions_.clear();
232✔
623
};
232✔
624

625
Sequence& StructuredSDFGBuilder::hoist_root() {
×
626
    auto current_root = std::move(this->structured_sdfg_->root_);
×
627

628
    this->structured_sdfg_->root_ =
×
629
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), current_root->debug_info()));
×
630

631
    this->structured_sdfg_->root_->children_.push_back(std::move(current_root));
×
632
    this->structured_sdfg_->root_->transitions_.push_back(std::unique_ptr<Transition>(
×
633
        new Transition(this->new_element_id(), current_root->debug_info(), *this->structured_sdfg_->root_)
×
634
    ));
×
635
    return *this->structured_sdfg_->root_;
×
636
};
×
637

638
Block& StructuredSDFGBuilder::
639
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
3,022✔
640
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
3,022✔
641

642
    parent.transitions_
3,022✔
643
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3,022✔
644
        );
3,022✔
645

646
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
3,022✔
647
    (*new_block.dataflow_).parent_ = &new_block;
3,022✔
648

649
    return new_block;
3,022✔
650
};
3,022✔
651

652
Block& StructuredSDFGBuilder::add_block(
653
    Sequence& parent,
654
    const data_flow::DataFlowGraph& data_flow_graph,
655
    const sdfg::control_flow::Assignments& assignments,
656
    const DebugInfo& debug_info
657
) {
19✔
658
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
19✔
659

660
    parent.transitions_
19✔
661
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
19✔
662
        );
19✔
663

664
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
19✔
665
    (*new_block.dataflow_).parent_ = &new_block;
19✔
666

667
    this->add_dataflow(data_flow_graph, new_block);
19✔
668

669
    return new_block;
19✔
670
};
19✔
671

672
Block& StructuredSDFGBuilder::add_block_before(
673
    Sequence& parent,
674
    ControlFlowNode& child,
675
    const sdfg::control_flow::Assignments& assignments,
676
    const DebugInfo& debug_info
677
) {
147✔
678
    int index = parent.index(child);
147✔
679
    if (index == -1) {
147✔
680
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
681
    }
×
682

683
    parent.children_
147✔
684
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
147✔
685

686
    parent.transitions_.insert(
147✔
687
        parent.transitions_.begin() + index,
147✔
688
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
147✔
689
    );
147✔
690

691
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
147✔
692
    (*new_block.dataflow_).parent_ = &new_block;
147✔
693

694
    return new_block;
147✔
695
};
147✔
696

697
Block& StructuredSDFGBuilder::add_block_before(
698
    Sequence& parent,
699
    ControlFlowNode& child,
700
    data_flow::DataFlowGraph& data_flow_graph,
701
    const sdfg::control_flow::Assignments& assignments,
702
    const DebugInfo& debug_info
703
) {
×
704
    int index = parent.index(child);
×
705
    if (index == -1) {
×
706
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
707
    }
×
708

709
    parent.children_
×
710
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
711

712
    parent.transitions_.insert(
×
713
        parent.transitions_.begin() + index,
×
714
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
715
    );
×
716

717
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
718
    (*new_block.dataflow_).parent_ = &new_block;
×
719
    this->add_dataflow(data_flow_graph, new_block);
×
720

721
    return new_block;
×
722
};
×
723

724
Block& StructuredSDFGBuilder::add_block_after(
725
    Sequence& parent,
726
    ControlFlowNode& child,
727
    const sdfg::control_flow::Assignments& assignments,
728
    const DebugInfo& debug_info
729
) {
148✔
730
    int index = parent.index(child);
148✔
731
    if (index == -1) {
148✔
732
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
733
    }
×
734

735
    parent.children_.insert(
148✔
736
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
148✔
737
    );
148✔
738

739
    parent.transitions_.insert(
148✔
740
        parent.transitions_.begin() + index + 1,
148✔
741
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
148✔
742
    );
148✔
743

744
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
148✔
745
    (*new_block.dataflow_).parent_ = &new_block;
148✔
746

747
    return new_block;
148✔
748
};
148✔
749

750
Block& StructuredSDFGBuilder::add_block_after(
751
    Sequence& parent,
752
    ControlFlowNode& child,
753
    data_flow::DataFlowGraph& data_flow_graph,
754
    const sdfg::control_flow::Assignments& assignments,
755
    const DebugInfo& debug_info
756
) {
×
757
    int index = parent.index(child);
×
758
    if (index == -1) {
×
759
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
760
    }
×
761

762
    parent.children_.insert(
×
763
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
764
    );
×
765

766
    parent.transitions_.insert(
×
767
        parent.transitions_.begin() + index + 1,
×
768
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
769
    );
×
770

771
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
772
    (*new_block.dataflow_).parent_ = &new_block;
×
773
    this->add_dataflow(data_flow_graph, new_block);
×
774

775
    return new_block;
×
776
};
×
777

778
std::pair<Block&, Transition&> StructuredSDFGBuilder::
779
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
780
    int index = parent.index(child);
×
781
    if (index == -1) {
×
782
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
783
    }
×
784

785
    parent.children_
×
786
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
787

788
    parent.transitions_.insert(
×
789
        parent.transitions_.begin() + index,
×
790
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
791
    );
×
792

793
    auto new_entry = parent.at(index);
×
794
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
795
    (*new_block.dataflow_).parent_ = &new_block;
×
796

797
    return {new_block, new_entry.second};
×
798
};
×
799

800
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
801
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
802
) {
×
803
    int index = parent.index(child);
×
804
    if (index == -1) {
×
805
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
806
    }
×
807

808
    parent.children_
×
809
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
810

811
    parent.transitions_.insert(
×
812
        parent.transitions_.begin() + index,
×
813
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
814
    );
×
815

816
    auto new_entry = parent.at(index);
×
817
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
818
    (*new_block.dataflow_).parent_ = &new_block;
×
819

820
    this->add_dataflow(data_flow_graph, new_block);
×
821

822
    return {new_block, new_entry.second};
×
823
};
×
824

825
std::pair<Block&, Transition&> StructuredSDFGBuilder::
826
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
827
    int index = parent.index(child);
×
828
    if (index == -1) {
×
829
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
830
    }
×
831

832
    parent.children_.insert(
×
833
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
834
    );
×
835

836
    parent.transitions_.insert(
×
837
        parent.transitions_.begin() + index + 1,
×
838
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
839
    );
×
840

841
    auto new_entry = parent.at(index + 1);
×
842
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
843
    (*new_block.dataflow_).parent_ = &new_block;
×
844

845
    return {new_block, new_entry.second};
×
846
};
×
847

848
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
849
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
850
) {
×
851
    int index = parent.index(child);
×
852
    if (index == -1) {
×
853
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
854
    }
×
855

856
    parent.children_.insert(
×
857
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
858
    );
×
859

860
    parent.transitions_.insert(
×
861
        parent.transitions_.begin() + index + 1,
×
862
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
863
    );
×
864

865
    auto new_entry = parent.at(index + 1);
×
866
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
867
    (*new_block.dataflow_).parent_ = &new_block;
×
868

869
    this->add_dataflow(data_flow_graph, new_block);
×
870

871
    return {new_block, new_entry.second};
×
872
};
×
873

874
IfElse& StructuredSDFGBuilder::
875
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
105✔
876
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
105✔
877

878
    parent.transitions_
105✔
879
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
105✔
880
        );
105✔
881

882
    return static_cast<IfElse&>(*parent.children_.back().get());
105✔
883
};
105✔
884

885
IfElse& StructuredSDFGBuilder::add_if_else_before(
886
    Sequence& parent,
887
    ControlFlowNode& child,
888
    const sdfg::control_flow::Assignments& assignments,
889
    const DebugInfo& debug_info
890
) {
10✔
891
    int index = parent.index(child);
10✔
892
    if (index == -1) {
10✔
893
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
894
    }
×
895

896
    parent.children_
10✔
897
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
10✔
898

899
    parent.transitions_.insert(
10✔
900
        parent.transitions_.begin() + index,
10✔
901
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
10✔
902
    );
10✔
903

904
    return static_cast<IfElse&>(*parent.children_.at(index));
10✔
905
};
10✔
906

907
IfElse& StructuredSDFGBuilder::add_if_else_after(
908
    Sequence& parent,
909
    ControlFlowNode& child,
910
    const sdfg::control_flow::Assignments& assignments,
911
    const DebugInfo& debug_info
912
) {
×
913
    int index = parent.index(child);
×
914
    if (index == -1) {
×
915
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
916
    }
×
917

918
    parent.children_.insert(
×
919
        parent.children_.begin() + index + 1, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info))
×
920
    );
×
921

922
    parent.transitions_.insert(
×
923
        parent.transitions_.begin() + index + 1,
×
924
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
925
    );
×
926

927
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
928
};
×
929

930
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
931
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
932
    int index = parent.index(child);
×
933
    if (index == -1) {
×
934
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
935
    }
×
936

937
    parent.children_
×
938
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
×
939

940
    parent.transitions_.insert(
×
941
        parent.transitions_.begin() + index,
×
942
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
943
    );
×
944

945
    auto new_entry = parent.at(index);
×
946
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
947

948
    return {new_block, new_entry.second};
×
949
};
×
950

951
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
203✔
952
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
203✔
953

954
    scope.conditions_.push_back(cond);
203✔
955
    return *scope.cases_.back();
203✔
956
};
203✔
957

958
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
959
    scope.cases_.erase(scope.cases_.begin() + index);
×
960
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
961
};
×
962

963
While& StructuredSDFGBuilder::
964
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
52✔
965
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
52✔
966

967
    // Increment element id for body node
968
    this->new_element_id();
52✔
969

970
    parent.transitions_
52✔
971
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
52✔
972
        );
52✔
973

974
    return static_cast<While&>(*parent.children_.back().get());
52✔
975
};
52✔
976

977
For& StructuredSDFGBuilder::add_for(
978
    Sequence& parent,
979
    const symbolic::Symbol indvar,
980
    const symbolic::Condition condition,
981
    const symbolic::Expression init,
982
    const symbolic::Expression update,
983
    const sdfg::control_flow::Assignments& assignments,
984
    const DebugInfo& debug_info
985
) {
657✔
986
    parent.children_
657✔
987
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
657✔
988

989
    // Increment element id for body node
990
    this->new_element_id();
657✔
991

992
    parent.transitions_
657✔
993
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
657✔
994
        );
657✔
995

996
    return static_cast<For&>(*parent.children_.back().get());
657✔
997
};
657✔
998

999
For& StructuredSDFGBuilder::add_for_before(
1000
    Sequence& parent,
1001
    ControlFlowNode& child,
1002
    const symbolic::Symbol indvar,
1003
    const symbolic::Condition condition,
1004
    const symbolic::Expression init,
1005
    const symbolic::Expression update,
1006
    const sdfg::control_flow::Assignments& assignments,
1007
    const DebugInfo& debug_info
1008
) {
39✔
1009
    int index = parent.index(child);
39✔
1010
    if (index == -1) {
39✔
1011
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1012
    }
×
1013

1014
    parent.children_.insert(
39✔
1015
        parent.children_.begin() + index,
39✔
1016
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
39✔
1017
    );
39✔
1018

1019
    // Increment element id for body node
1020
    this->new_element_id();
39✔
1021

1022
    parent.transitions_.insert(
39✔
1023
        parent.transitions_.begin() + index,
39✔
1024
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
39✔
1025
    );
39✔
1026

1027
    return static_cast<For&>(*parent.children_.at(index).get());
39✔
1028
};
39✔
1029

1030
For& StructuredSDFGBuilder::add_for_after(
1031
    Sequence& parent,
1032
    ControlFlowNode& child,
1033
    const symbolic::Symbol indvar,
1034
    const symbolic::Condition condition,
1035
    const symbolic::Expression init,
1036
    const symbolic::Expression update,
1037
    const sdfg::control_flow::Assignments& assignments,
1038
    const DebugInfo& debug_info
1039
) {
62✔
1040
    int index = parent.index(child);
62✔
1041
    if (index == -1) {
62✔
1042
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1043
    }
×
1044

1045
    parent.children_.insert(
62✔
1046
        parent.children_.begin() + index + 1,
62✔
1047
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
62✔
1048
    );
62✔
1049

1050
    // Increment element id for body node
1051
    this->new_element_id();
62✔
1052

1053
    parent.transitions_.insert(
62✔
1054
        parent.transitions_.begin() + index + 1,
62✔
1055
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
62✔
1056
    );
62✔
1057

1058
    return static_cast<For&>(*parent.children_.at(index + 1).get());
62✔
1059
};
62✔
1060

1061
Map& StructuredSDFGBuilder::add_map(
1062
    Sequence& parent,
1063
    const symbolic::Symbol indvar,
1064
    const symbolic::Condition condition,
1065
    const symbolic::Expression init,
1066
    const symbolic::Expression update,
1067
    const ScheduleType& schedule_type,
1068
    const sdfg::control_flow::Assignments& assignments,
1069
    const DebugInfo& debug_info
1070
) {
1,945✔
1071
    parent.children_
1,945✔
1072
        .push_back(std::unique_ptr<
1,945✔
1073
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
1,945✔
1074

1075
    // Increment element id for body node
1076
    this->new_element_id();
1,945✔
1077

1078
    parent.transitions_
1,945✔
1079
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
1,945✔
1080
        );
1,945✔
1081

1082
    return static_cast<Map&>(*parent.children_.back().get());
1,945✔
1083
};
1,945✔
1084

1085
Map& StructuredSDFGBuilder::add_map_before(
1086
    Sequence& parent,
1087
    ControlFlowNode& child,
1088
    const symbolic::Symbol indvar,
1089
    const symbolic::Condition condition,
1090
    const symbolic::Expression init,
1091
    const symbolic::Expression update,
1092
    const ScheduleType& schedule_type,
1093
    const sdfg::control_flow::Assignments& assignments,
1094
    const DebugInfo& debug_info
1095
) {
83✔
1096
    int index = parent.index(child);
83✔
1097
    if (index == -1) {
83✔
1098
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1099
    }
×
1100

1101
    parent.children_.insert(
83✔
1102
        parent.children_.begin() + index,
83✔
1103
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
83✔
1104
        )
83✔
1105
    );
83✔
1106

1107
    // Increment element id for body node
1108
    this->new_element_id();
83✔
1109

1110
    parent.transitions_.insert(
83✔
1111
        parent.transitions_.begin() + index,
83✔
1112
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
83✔
1113
    );
83✔
1114

1115
    return static_cast<Map&>(*parent.children_.at(index).get());
83✔
1116
};
83✔
1117

1118
Map& StructuredSDFGBuilder::add_map_after(
1119
    Sequence& parent,
1120
    ControlFlowNode& child,
1121
    const symbolic::Symbol indvar,
1122
    const symbolic::Condition condition,
1123
    const symbolic::Expression init,
1124
    const symbolic::Expression update,
1125
    const ScheduleType& schedule_type,
1126
    const sdfg::control_flow::Assignments& assignments,
1127
    const DebugInfo& debug_info
1128
) {
90✔
1129
    int index = parent.index(child);
90✔
1130
    if (index == -1) {
90✔
1131
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1132
    }
×
1133

1134
    parent.children_.insert(
90✔
1135
        parent.children_.begin() + index + 1,
90✔
1136
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
90✔
1137
        )
90✔
1138
    );
90✔
1139

1140
    // Increment element id for body node
1141
    this->new_element_id();
90✔
1142

1143
    parent.transitions_.insert(
90✔
1144
        parent.transitions_.begin() + index + 1,
90✔
1145
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
90✔
1146
    );
90✔
1147

1148
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
90✔
1149
};
90✔
1150

1151
Continue& StructuredSDFGBuilder::
1152
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
27✔
1153
    parent.children_.push_back(std::unique_ptr<Continue>(new Continue(this->new_element_id(), debug_info)));
27✔
1154

1155
    parent.transitions_
27✔
1156
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
27✔
1157
        );
27✔
1158

1159
    return static_cast<Continue&>(*parent.children_.back().get());
27✔
1160
};
27✔
1161

1162
Break& StructuredSDFGBuilder::
1163
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
28✔
1164
    parent.children_.push_back(std::unique_ptr<Break>(new Break(this->new_element_id(), debug_info)));
28✔
1165

1166
    parent.transitions_
28✔
1167
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
28✔
1168
        );
28✔
1169

1170
    return static_cast<Break&>(*parent.children_.back().get());
28✔
1171
};
28✔
1172

1173
Return& StructuredSDFGBuilder::add_return(
1174
    Sequence& parent,
1175
    const std::string& data,
1176
    const sdfg::control_flow::Assignments& assignments,
1177
    const DebugInfo& debug_info
1178
) {
56✔
1179
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
56✔
1180

1181
    parent.transitions_
56✔
1182
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
56✔
1183
        );
56✔
1184

1185
    return static_cast<Return&>(*parent.children_.back().get());
56✔
1186
};
56✔
1187

1188
Return& StructuredSDFGBuilder::add_constant_return(
1189
    Sequence& parent,
1190
    const std::string& data,
1191
    const types::IType& type,
1192
    const sdfg::control_flow::Assignments& assignments,
1193
    const DebugInfo& debug_info
1194
) {
×
1195
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1196

1197
    parent.transitions_
×
1198
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1199
        );
×
1200

1201
    return static_cast<Return&>(*parent.children_.back().get());
×
1202
};
×
1203

1204
For& StructuredSDFGBuilder::convert_while(
1205
    Sequence& parent,
1206
    While& loop,
1207
    const symbolic::Symbol indvar,
1208
    const symbolic::Condition condition,
1209
    const symbolic::Expression init,
1210
    const symbolic::Expression update
1211
) {
×
1212
    int index = parent.index(loop);
×
1213
    if (index == -1) {
×
1214
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1215
    }
×
1216

1217
    auto iter = parent.children_.begin() + index;
×
1218
    auto& new_iter = *parent.children_.insert(
×
1219
        iter + 1,
×
1220
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1221
    );
×
1222

1223
    // Increment element id for body node
1224
    this->new_element_id();
×
1225

1226
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1227
    this->move_children(loop.root(), for_loop.root());
×
1228

1229
    // Remove while loop
1230
    parent.children_.erase(parent.children_.begin() + index);
×
1231

1232
    return for_loop;
×
1233
};
×
1234

1235
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
77✔
1236
    int index = parent.index(loop);
77✔
1237
    if (index == -1) {
77✔
1238
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1239
    }
×
1240

1241
    auto iter = parent.children_.begin() + index;
77✔
1242
    auto& new_iter = *parent.children_.insert(
77✔
1243
        iter + 1,
77✔
1244
        std::unique_ptr<Map>(new Map(
77✔
1245
            this->new_element_id(),
77✔
1246
            loop.debug_info(),
77✔
1247
            loop.indvar(),
77✔
1248
            loop.init(),
77✔
1249
            loop.update(),
77✔
1250
            loop.condition(),
77✔
1251
            ScheduleType_Sequential::create()
77✔
1252
        ))
77✔
1253
    );
77✔
1254

1255
    // Increment element id for body node
1256
    this->new_element_id();
77✔
1257

1258
    auto& map = dynamic_cast<Map&>(*new_iter);
77✔
1259
    this->move_children(loop.root(), map.root());
77✔
1260

1261
    // Remove for loop
1262
    parent.children_.erase(parent.children_.begin() + index);
77✔
1263

1264
    return map;
77✔
1265
};
77✔
1266

1267
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1268
    if (index >= if_else.conditions_.size()) {
×
1269
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1270
    }
×
1271
    if_else.conditions_.at(index) = condition;
×
1272
};
×
1273

1274
void StructuredSDFGBuilder::update_loop(
1275
    StructuredLoop& loop,
1276
    const symbolic::Symbol indvar,
1277
    const symbolic::Condition condition,
1278
    const symbolic::Expression init,
1279
    const symbolic::Expression update
1280
) {
115✔
1281
    loop.indvar_ = indvar;
115✔
1282
    loop.condition_ = condition;
115✔
1283
    loop.init_ = init;
115✔
1284
    loop.update_ = update;
115✔
1285
};
115✔
1286

1287
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
18✔
1288
    map.schedule_type_ = schedule_type;
18✔
1289
}
18✔
1290

1291
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
×
1292
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
×
1293
    while (!queue.empty()) {
×
1294
        auto current = queue.front();
×
1295
        queue.pop_front();
×
1296

1297
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
×
1298
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
×
1299
                if (&sequence_stmt->at(i).first == &node) {
×
1300
                    return *sequence_stmt;
×
1301
                }
×
1302
                queue.push_back(&sequence_stmt->at(i).first);
×
1303
            }
×
1304
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1305
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1306
                queue.push_back(&if_else_stmt->at(i).first);
×
1307
            }
×
1308
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1309
            queue.push_back(&while_stmt->root());
×
1310
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1311
            queue.push_back(&loop_stmt->root());
×
1312
        }
×
1313
    }
×
1314

1315
    return this->structured_sdfg_->root();
×
1316
};
×
1317

1318
/***** Section: Dataflow Graph *****/
1319

1320
data_flow::AccessNode& StructuredSDFGBuilder::
1321
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
6,600✔
1322
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
6,600✔
1323
    auto res = block.dataflow_->nodes_.insert(
6,600✔
1324
        {vertex,
6,600✔
1325
         std::unique_ptr<data_flow::AccessNode>(
6,600✔
1326
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
6,600✔
1327
         )}
6,600✔
1328
    );
6,600✔
1329

1330
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
6,600✔
1331
};
6,600✔
1332

1333
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
1334
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1335
) {
379✔
1336
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
379✔
1337
    auto res = block.dataflow_->nodes_.insert(
379✔
1338
        {vertex,
379✔
1339
         std::unique_ptr<data_flow::ConstantNode>(
379✔
1340
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
379✔
1341
         )}
379✔
1342
    );
379✔
1343

1344
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
379✔
1345
};
379✔
1346

1347

1348
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
1349
    structured_control_flow::Block& block,
1350
    const data_flow::TaskletCode code,
1351
    const std::string& output,
1352
    const std::vector<std::string>& inputs,
1353
    const DebugInfo& debug_info
1354
) {
1,449✔
1355
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
1,449✔
1356
    auto res = block.dataflow_->nodes_.insert(
1,449✔
1357
        {vertex,
1,449✔
1358
         std::unique_ptr<data_flow::Tasklet>(
1,449✔
1359
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
1,449✔
1360
         )}
1,449✔
1361
    );
1,449✔
1362

1363
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
1,449✔
1364
};
1,449✔
1365

1366
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
1367
    structured_control_flow::Block& block,
1368
    data_flow::DataFlowNode& src,
1369
    const std::string& src_conn,
1370
    data_flow::DataFlowNode& dst,
1371
    const std::string& dst_conn,
1372
    const data_flow::Subset& subset,
1373
    const types::IType& base_type,
1374
    const DebugInfo& debug_info
1375
) {
7,225✔
1376
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
7,225✔
1377
    auto res = block.dataflow_->edges_.insert(
7,225✔
1378
        {edge.first,
7,225✔
1379
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
7,225✔
1380
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
7,225✔
1381
         ))}
7,225✔
1382
    );
7,225✔
1383

1384
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
7,225✔
1385
#ifndef NDEBUG
7,225✔
1386
    memlet.validate(*this->structured_sdfg_);
7,225✔
1387
#endif
7,225✔
1388

1389
    return memlet;
7,225✔
1390
};
7,225✔
1391

1392
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1393
    structured_control_flow::Block& block,
1394
    data_flow::AccessNode& src,
1395
    data_flow::CodeNode& dst,
1396
    const std::string& dst_conn,
1397
    const data_flow::Subset& subset,
1398
    const types::IType& base_type,
1399
    const DebugInfo& debug_info
1400
) {
3,203✔
1401
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
3,203✔
1402
};
3,203✔
1403

1404
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1405
    structured_control_flow::Block& block,
1406
    data_flow::CodeNode& src,
1407
    const std::string& src_conn,
1408
    data_flow::AccessNode& dst,
1409
    const data_flow::Subset& subset,
1410
    const types::IType& base_type,
1411
    const DebugInfo& debug_info
1412
) {
1,943✔
1413
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
1,943✔
1414
};
1,943✔
1415

1416
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1417
    structured_control_flow::Block& block,
1418
    data_flow::AccessNode& src,
1419
    data_flow::Tasklet& dst,
1420
    const std::string& dst_conn,
1421
    const data_flow::Subset& subset,
1422
    const DebugInfo& debug_info
1423
) {
960✔
1424
    const types::IType* src_type = nullptr;
960✔
1425
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
960✔
1426
        src_type = &cnode->type();
218✔
1427
    } else {
742✔
1428
        src_type = &this->structured_sdfg_->type(src.data());
742✔
1429
    }
742✔
1430
    auto base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
960✔
1431
    if (base_type->type_id() != types::TypeID::Scalar) {
960✔
1432
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1433
    }
×
1434
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
960✔
1435
};
960✔
1436

1437
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1438
    structured_control_flow::Block& block,
1439
    data_flow::Tasklet& src,
1440
    const std::string& src_conn,
1441
    data_flow::AccessNode& dst,
1442
    const data_flow::Subset& subset,
1443
    const DebugInfo& debug_info
1444
) {
588✔
1445
    auto& dst_type = this->structured_sdfg_->type(dst.data());
588✔
1446
    auto base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
588✔
1447
    if (base_type->type_id() != types::TypeID::Scalar) {
588✔
1448
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1449
    }
×
1450
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
588✔
1451
};
588✔
1452

1453
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
1454
    structured_control_flow::Block& block,
1455
    data_flow::AccessNode& src,
1456
    data_flow::AccessNode& dst,
1457
    const data_flow::Subset& subset,
1458
    const types::IType& base_type,
1459
    const DebugInfo& debug_info
1460
) {
120✔
1461
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
120✔
1462
};
120✔
1463

1464
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
1465
    structured_control_flow::Block& block,
1466
    data_flow::AccessNode& src,
1467
    data_flow::AccessNode& dst,
1468
    bool derefs_src,
1469
    const types::IType& base_type,
1470
    const DebugInfo& debug_info
1471
) {
23✔
1472
    if (derefs_src) {
23✔
1473
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
14✔
1474
    } else {
14✔
1475
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
9✔
1476
    }
9✔
1477
};
23✔
1478

1479
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
1,619✔
1480
    auto& graph = block.dataflow();
1,619✔
1481
    auto e = edge.edge();
1,619✔
1482
    boost::remove_edge(e, graph.graph_);
1,619✔
1483
    graph.edges_.erase(e);
1,619✔
1484
};
1,619✔
1485

1486
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
2,141✔
1487
    auto& graph = block.dataflow();
2,141✔
1488
    auto v = node.vertex();
2,141✔
1489
    boost::remove_vertex(v, graph.graph_);
2,141✔
1490
    graph.nodes_.erase(v);
2,141✔
1491
};
2,141✔
1492

1493
void StructuredSDFGBuilder::clear_code_node_legacy(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
45✔
1494
    auto& graph = block.dataflow();
45✔
1495

1496
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
45✔
1497

1498
    // Delete incoming
1499
    std::list<const data_flow::Memlet*> iedges;
45✔
1500
    for (auto& iedge : graph.in_edges(node)) {
62✔
1501
        iedges.push_back(&iedge);
62✔
1502
    }
62✔
1503
    for (auto iedge : iedges) {
62✔
1504
        auto& src = iedge->src();
62✔
1505
        to_delete.insert(&src);
62✔
1506

1507
        auto edge = iedge->edge();
62✔
1508
        graph.edges_.erase(edge);
62✔
1509
        boost::remove_edge(edge, graph.graph_);
62✔
1510
    }
62✔
1511

1512
    // Delete outgoing
1513
    std::list<const data_flow::Memlet*> oedges;
45✔
1514
    for (auto& oedge : graph.out_edges(node)) {
45✔
1515
        oedges.push_back(&oedge);
39✔
1516
    }
39✔
1517
    for (auto oedge : oedges) {
45✔
1518
        auto& dst = oedge->dst();
39✔
1519
        to_delete.insert(&dst);
39✔
1520

1521
        auto edge = oedge->edge();
39✔
1522
        graph.edges_.erase(edge);
39✔
1523
        boost::remove_edge(edge, graph.graph_);
39✔
1524
    }
39✔
1525

1526
    // Delete nodes
1527
    for (auto obsolete_node : to_delete) {
146✔
1528
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
146✔
1529
            auto vertex = obsolete_node->vertex();
146✔
1530
            graph.nodes_.erase(vertex);
146✔
1531
            boost::remove_vertex(vertex, graph.graph_);
146✔
1532
        }
146✔
1533
    }
146✔
1534
}
45✔
1535

1536
void StructuredSDFGBuilder::
1537
    clear_access_node_legacy(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
3✔
1538
    auto& graph = block.dataflow();
3✔
1539

1540
    std::list<const data_flow::Memlet*> tmp;
3✔
1541
    std::list<const data_flow::DataFlowNode*> queue = {&node};
3✔
1542
    while (!queue.empty()) {
9✔
1543
        auto current = queue.front();
6✔
1544
        queue.pop_front();
6✔
1545
        if (current != &node) {
6✔
1546
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
3✔
UNCOV
1547
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1548
                    continue;
×
1549
                }
×
UNCOV
1550
            }
×
1551
        }
3✔
1552

1553
        tmp.clear();
6✔
1554
        for (auto& iedge : graph.in_edges(*current)) {
6✔
1555
            tmp.push_back(&iedge);
3✔
1556
        }
3✔
1557
        for (auto iedge : tmp) {
6✔
1558
            auto& src = iedge->src();
3✔
1559
            queue.push_back(&src);
3✔
1560

1561
            auto edge = iedge->edge();
3✔
1562
            graph.edges_.erase(edge);
3✔
1563
            boost::remove_edge(edge, graph.graph_);
3✔
1564
        }
3✔
1565

1566
        if (current != &node || graph.out_degree(*current) == 0) {
6✔
1567
            auto vertex = current->vertex();
6✔
1568
            graph.nodes_.erase(vertex);
6✔
1569
            boost::remove_vertex(vertex, graph.graph_);
6✔
1570
        }
6✔
1571
    }
6✔
1572
}
3✔
1573

1574
int StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
13✔
1575
    return clear_node(block, node, {&node});
13✔
1576
}
13✔
1577

1578
int StructuredSDFGBuilder::clear_node(
1579
    structured_control_flow::Block& block,
1580
    const data_flow::DataFlowNode& node,
1581
    const std::unordered_set<const data_flow::DataFlowNode*>& ignore_side_effects
1582
) {
13✔
1583
    auto& graph = block.dataflow();
13✔
1584

1585
    std::list<const data_flow::Memlet*> tmp;
13✔
1586
    std::list<const data_flow::DataFlowNode*> queue = {&node};
13✔
1587
    std::unordered_set<const data_flow::DataFlowNode*> remove_once_set;
13✔
1588
    std::unordered_set<const data_flow::DataFlowNode*> force_remove_set;
13✔
1589
    int removed_nodes = 0;
13✔
1590

1591
    do {
36✔
1592
        auto current = queue.front();
36✔
1593
        queue.pop_front();
36✔
1594

1595
        if (!remove_once_set.contains(current)) {
36✔
1596
            bool no_more_consumers = graph.out_degree(*current) == 0; // cannot remove nodes still in use
35✔
1597

1598
            auto* access_node = dynamic_cast<const data_flow::AccessNode*>(current);
35✔
1599

1600
            bool ignore_side_effects_on_current = ignore_side_effects.contains(current);
35✔
1601
            bool force_remove = force_remove_set.contains(current);
35✔
1602

1603
            // we can remove nodes without out-edges & side effects.
1604
            if ((no_more_consumers && !current->side_effect()) ||
35✔
1605
                ((ignore_side_effects_on_current || force_remove) && (no_more_consumers || access_node))) {
35✔
1606
                // Or for access-nodes on the ignore list, we can remove the write side (will not remove the node, only
1607
                // inputs) For any other node on the ignore list, we can ignore if it has side effects or not
1608
                tmp.clear();
28✔
1609
                for (auto& iedge : graph.in_edges(*current)) {
28✔
1610
                    tmp.push_back(&iedge);
25✔
1611
                }
25✔
1612
                bool no_in_edges = true;
28✔
1613
                for (auto iedge : tmp) {
28✔
1614
                    auto& src = iedge->src();
25✔
1615

1616
                    auto edge_rem = src.can_remove_out_edge(graph, iedge);
25✔
1617
                    if (edge_rem != data_flow::EdgeRemoveOption::NotRemovable) {
25✔
1618
                        auto src_conn = iedge->src_conn();
23✔
1619
                        queue.push_back(&src);
23✔
1620
                        auto edge = iedge->edge();
23✔
1621
                        graph.edges_.erase(edge);
23✔
1622
                        boost::remove_edge(edge, graph.graph_);
23✔
1623
                        if (edge_rem == data_flow::EdgeRemoveOption::RequiresUpdate) {
23✔
1624
                            const_cast<data_flow::DataFlowNode&>(src).update_edge_removed(src_conn);
×
1625
                        } else if (edge_rem == data_flow::EdgeRemoveOption::RemoveNodeAfter) {
23✔
1626
                            force_remove_set.insert(&src);
7✔
1627
                        }
7✔
1628
                    } else {
23✔
1629
                        no_in_edges = false;
2✔
1630
                    }
2✔
1631
                }
25✔
1632

1633
                if (no_more_consumers && no_in_edges) {
28✔
1634
                    remove_once_set.insert(current);
25✔
1635
                    auto vertex = current->vertex();
25✔
1636
                    graph.nodes_.erase(vertex);
25✔
1637
                    boost::remove_vertex(vertex, graph.graph_);
25✔
1638
                    ++removed_nodes;
25✔
1639
                } else if (!no_more_consumers && force_remove) {
25✔
1640
                    throw std::runtime_error(
×
1641
                        "Not yet supported: RemoveNodeAfter with more than 1 edge: #" +
×
1642
                        std::to_string(current->element_id())
×
1643
                    );
×
1644
                }
×
1645
            }
28✔
1646
        }
35✔
1647
    } while (!queue.empty());
36✔
1648

1649
    return removed_nodes;
13✔
1650
}
13✔
1651

1652
int StructuredSDFGBuilder::clear_ptr_borrow_edge(Block& block, const data_flow::Memlet& edge) {
1✔
1653
    auto& graph = block.dataflow();
1✔
1654
    auto& src = edge.src();
1✔
1655
    auto& dst = edge.dst();
1✔
1656

1657
    auto edge_removal = dst.can_remove_in_edge(graph, &edge);
1✔
1658
    int removed = 0;
1✔
1659
    if (edge_removal == data_flow::EdgeRemoveOption::Trivially) {
1✔
NEW
1660
        remove_memlet(block, edge);
×
NEW
1661
        ++removed;
×
1662
    } else if (edge_removal == data_flow::EdgeRemoveOption::RemoveNodeAfter) {
1✔
1663
        removed = 1 + clear_node(block, dst);
1✔
1664
    } else if (edge_removal == data_flow::EdgeRemoveOption::RequiresUpdate) {
1✔
NEW
1665
        remove_memlet(block, edge);
×
NEW
1666
        const_cast<data_flow::DataFlowNode&>(dst).update_edge_removed(edge.dst_conn());
×
NEW
1667
    } else if (edge_removal == data_flow::EdgeRemoveOption::NotRemovable) {
×
NEW
1668
        return 0;
×
NEW
1669
    }
×
1670

1671
    return removed;
1✔
1672
}
1✔
1673

1674
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
19✔
1675
    auto& to_dataflow = to.dataflow();
19✔
1676

1677
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
19✔
1678
    for (auto& entry : from.nodes_) {
21✔
1679
        auto vertex = boost::add_vertex(to_dataflow.graph_);
21✔
1680
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
21✔
1681
        node_mapping.insert({entry.first, vertex});
21✔
1682
    }
21✔
1683

1684
    for (auto& entry : from.edges_) {
19✔
1685
        auto src = node_mapping[entry.second->src().vertex()];
14✔
1686
        auto dst = node_mapping[entry.second->dst().vertex()];
14✔
1687

1688
        auto edge = boost::add_edge(src, dst, to_dataflow.graph_);
14✔
1689

1690
        to_dataflow.edges_.insert(
14✔
1691
            {edge.first,
14✔
1692
             entry.second->clone(
14✔
1693
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
14✔
1694
             )}
14✔
1695
        );
14✔
1696
    }
14✔
1697
};
19✔
1698

1699
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
21✔
1700
    auto& user_graph = source_node.get_parent();
21✔
1701
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
21✔
1702
    if (!block) {
21✔
1703
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1704
    }
×
1705

1706
    // Merge access nodes if they access the same container on a code node
1707
    for (auto& oedge : user_graph.out_edges(source_node)) {
21✔
1708
        if (auto* code_node = dynamic_cast<data_flow::CodeNode*>(&oedge.dst())) {
15✔
1709
            std::unordered_set<data_flow::Memlet*> iedges;
8✔
1710
            for (auto& iedge : user_graph.in_edges(*code_node)) {
10✔
1711
                iedges.insert(&iedge);
10✔
1712
            }
10✔
1713
            for (auto* iedge : iedges) {
10✔
1714
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
10✔
1715
                    continue;
×
1716
                }
×
1717
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
10✔
1718
                if (access_node == &source_node || access_node->data() != source_node.data()) {
10✔
1719
                    continue;
9✔
1720
                }
9✔
1721
                this->add_memlet(
1✔
1722
                    *block,
1✔
1723
                    source_node,
1✔
1724
                    iedge->src_conn(),
1✔
1725
                    *code_node,
1✔
1726
                    iedge->dst_conn(),
1✔
1727
                    iedge->subset(),
1✔
1728
                    iedge->base_type(),
1✔
1729
                    iedge->debug_info()
1✔
1730
                );
1✔
1731
                this->remove_memlet(*block, *iedge);
1✔
1732
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
1✔
1733
            }
1✔
1734
        }
8✔
1735
    }
15✔
1736

1737
    // Also merge "output" access nodes if they access the same container on a library node
1738
    for (auto& iedge : user_graph.in_edges(source_node)) {
21✔
1739
        if (auto* libnode = dynamic_cast<data_flow::LibraryNode*>(&iedge.src())) {
7✔
1740
            std::unordered_set<data_flow::Memlet*> oedges;
×
1741
            for (auto& oedge : user_graph.out_edges(*libnode)) {
×
1742
                oedges.insert(&oedge);
×
1743
            }
×
1744
            for (auto* oedge : oedges) {
×
1745
                auto* access_node = static_cast<data_flow::AccessNode*>(&oedge->dst());
×
1746
                if (access_node == &source_node || access_node->data() != source_node.data()) {
×
1747
                    continue;
×
1748
                }
×
1749
                this->add_memlet(
×
1750
                    *block,
×
1751
                    *libnode,
×
1752
                    oedge->src_conn(),
×
1753
                    source_node,
×
1754
                    oedge->dst_conn(),
×
1755
                    oedge->subset(),
×
1756
                    oedge->base_type(),
×
1757
                    oedge->debug_info()
×
1758
                );
×
1759
                this->remove_memlet(*block, *oedge);
×
1760
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
×
1761
            }
×
1762
        }
×
1763
    }
7✔
1764
}
21✔
1765

1766
} // namespace builder
1767
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc