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

daisytuner / docc / 23677565614

27 Mar 2026 05:43PM UTC coverage: 64.877% (+0.03%) from 64.845%
23677565614

push

github

web-flow
Merge pull request #614 from daisytuner/dde-clean-fix

Fixing DDE & clear_node: block it from removing critical output edges…

96 of 99 new or added lines in 9 files covered. (96.97%)

4 existing lines in 2 files now uncovered.

27037 of 41674 relevant lines covered (64.88%)

407.64 hits per line

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

68.9
/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_); };
45,053✔
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)) {};
173✔
390

391
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
392
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type), owned(true)) {};
1,569✔
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)) {};
37✔
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_; };
5,378✔
429

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

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

439
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
414✔
440
};
414✔
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 {
28✔
449
    auto& sdfg = this->subject();
28✔
450
    std::list<Element*> queue = {&sdfg.root()};
28✔
451
    while (!queue.empty()) {
145✔
452
        auto current = queue.front();
145✔
453
        queue.pop_front();
145✔
454

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

459
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
117✔
460
            auto& dataflow = block_stmt->dataflow();
4✔
461
            for (auto& node : dataflow.nodes()) {
12✔
462
                queue.push_back(&node);
12✔
463
            }
12✔
464
            for (auto& edge : dataflow.edges()) {
8✔
465
                queue.push_back(&edge);
8✔
466
            }
8✔
467
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
113✔
468
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
100✔
469
                queue.push_back(&sequence_stmt->at(i).first);
53✔
470
                queue.push_back(&sequence_stmt->at(i).second);
53✔
471
            }
53✔
472
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
66✔
473
            // Do nothing
474
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
66✔
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)) {
66✔
479
            queue.push_back(&for_stmt->root());
1✔
480
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
65✔
481
            queue.push_back(&while_stmt->root());
1✔
482
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
64✔
483
            // Do nothing
484
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
64✔
485
            // Do nothing
486
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
64✔
487
            queue.push_back(&map_stmt->root());
19✔
488
        }
19✔
489
    }
117✔
490

491
    return nullptr;
×
492
};
28✔
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
) {
582✔
511
    int index = parent.index(child);
582✔
512
    if (index == -1) {
582✔
513
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
514
    }
×
515

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

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

525
    return static_cast<Sequence&>(*parent.children_.at(index).get());
582✔
526
};
582✔
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) {
679✔
575
    parent.children_.erase(parent.children_.begin() + index);
679✔
576
    parent.transitions_.erase(parent.transitions_.begin() + index);
679✔
577
};
679✔
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) {
46✔
585
    size_t target_index = target.size();
46✔
586
    if (&source == &target) {
46✔
587
        target_index--;
×
588
    }
×
589
    this->move_child(source, source_index, target, target_index);
46✔
590
};
46✔
591

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

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

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

607
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
141✔
608
    target.children_.insert(
141✔
609
        target.children_.begin() + target_index,
141✔
610
        std::make_move_iterator(source.children_.begin()),
141✔
611
        std::make_move_iterator(source.children_.end())
141✔
612
    );
141✔
613
    target.transitions_.insert(
141✔
614
        target.transitions_.begin() + target_index,
141✔
615
        std::make_move_iterator(source.transitions_.begin()),
141✔
616
        std::make_move_iterator(source.transitions_.end())
141✔
617
    );
141✔
618
    for (auto& trans : target.transitions_) {
250✔
619
        trans->parent_ = &target;
250✔
620
    }
250✔
621
    source.children_.clear();
141✔
622
    source.transitions_.clear();
141✔
623
};
141✔
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) {
2,543✔
640
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
2,543✔
641

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

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

649
    return new_block;
2,543✔
650
};
2,543✔
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
) {
13✔
658
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
13✔
659

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

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

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

669
    return new_block;
13✔
670
};
13✔
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
) {
77✔
678
    int index = parent.index(child);
77✔
679
    if (index == -1) {
77✔
680
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
681
    }
×
682

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

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

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

694
    return new_block;
77✔
695
};
77✔
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
) {
29✔
730
    int index = parent.index(child);
29✔
731
    if (index == -1) {
29✔
732
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
733
    }
×
734

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

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

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

747
    return new_block;
29✔
748
};
29✔
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) {
99✔
876
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
99✔
877

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

882
    return static_cast<IfElse&>(*parent.children_.back().get());
99✔
883
};
99✔
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
) {
5✔
891
    int index = parent.index(child);
5✔
892
    if (index == -1) {
5✔
893
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
894
    }
×
895

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

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

904
    return static_cast<IfElse&>(*parent.children_.at(index));
5✔
905
};
5✔
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) {
180✔
952
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
180✔
953

954
    scope.conditions_.push_back(cond);
180✔
955
    return *scope.cases_.back();
180✔
956
};
180✔
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) {
56✔
965
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
56✔
966

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

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

974
    return static_cast<While&>(*parent.children_.back().get());
56✔
975
};
56✔
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
) {
468✔
986
    parent.children_
468✔
987
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
468✔
988

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

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

996
    return static_cast<For&>(*parent.children_.back().get());
468✔
997
};
468✔
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
) {
12✔
1009
    int index = parent.index(child);
12✔
1010
    if (index == -1) {
12✔
1011
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1012
    }
×
1013

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

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

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

1027
    return static_cast<For&>(*parent.children_.at(index).get());
12✔
1028
};
12✔
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
) {
12✔
1040
    int index = parent.index(child);
12✔
1041
    if (index == -1) {
12✔
1042
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1043
    }
×
1044

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

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

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

1058
    return static_cast<For&>(*parent.children_.at(index + 1).get());
12✔
1059
};
12✔
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,807✔
1071
    parent.children_
1,807✔
1072
        .push_back(std::unique_ptr<
1,807✔
1073
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
1,807✔
1074

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

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

1082
    return static_cast<Map&>(*parent.children_.back().get());
1,807✔
1083
};
1,807✔
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
) {
58✔
1096
    int index = parent.index(child);
58✔
1097
    if (index == -1) {
58✔
1098
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1099
    }
×
1100

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

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

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

1115
    return static_cast<Map&>(*parent.children_.at(index).get());
58✔
1116
};
58✔
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
) {
20✔
1129
    int index = parent.index(child);
20✔
1130
    if (index == -1) {
20✔
1131
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1132
    }
×
1133

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

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

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

1148
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
20✔
1149
};
20✔
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) {
71✔
1236
    int index = parent.index(loop);
71✔
1237
    if (index == -1) {
71✔
1238
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1239
    }
×
1240

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

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

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

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

1264
    return map;
71✔
1265
};
71✔
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
) {
34✔
1281
    loop.indvar_ = indvar;
34✔
1282
    loop.condition_ = condition;
34✔
1283
    loop.init_ = init;
34✔
1284
    loop.update_ = update;
34✔
1285
};
34✔
1286

1287
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
26✔
1288
    map.schedule_type_ = schedule_type;
26✔
1289
}
26✔
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) {
5,300✔
1322
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
5,300✔
1323
    auto res = block.dataflow_->nodes_.insert(
5,300✔
1324
        {vertex,
5,300✔
1325
         std::unique_ptr<data_flow::AccessNode>(
5,300✔
1326
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
5,300✔
1327
         )}
5,300✔
1328
    );
5,300✔
1329

1330
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
5,300✔
1331
};
5,300✔
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
) {
238✔
1336
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
238✔
1337
    auto res = block.dataflow_->nodes_.insert(
238✔
1338
        {vertex,
238✔
1339
         std::unique_ptr<data_flow::ConstantNode>(
238✔
1340
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
238✔
1341
         )}
238✔
1342
    );
238✔
1343

1344
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
238✔
1345
};
238✔
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,215✔
1355
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
1,215✔
1356
    auto res = block.dataflow_->nodes_.insert(
1,215✔
1357
        {vertex,
1,215✔
1358
         std::unique_ptr<data_flow::Tasklet>(
1,215✔
1359
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
1,215✔
1360
         )}
1,215✔
1361
    );
1,215✔
1362

1363
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
1,215✔
1364
};
1,215✔
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
) {
5,715✔
1376
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
5,715✔
1377
    auto res = block.dataflow_->edges_.insert(
5,715✔
1378
        {edge.first,
5,715✔
1379
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
5,715✔
1380
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
5,715✔
1381
         ))}
5,715✔
1382
    );
5,715✔
1383

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

1389
    return memlet;
5,715✔
1390
};
5,715✔
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
) {
2,496✔
1401
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
2,496✔
1402
};
2,496✔
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,762✔
1413
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
1,762✔
1414
};
1,762✔
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
) {
712✔
1424
    const types::IType* src_type = nullptr;
712✔
1425
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
712✔
1426
        src_type = &cnode->type();
139✔
1427
    } else {
573✔
1428
        src_type = &this->structured_sdfg_->type(src.data());
573✔
1429
    }
573✔
1430
    auto base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
712✔
1431
    if (base_type->type_id() != types::TypeID::Scalar) {
712✔
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);
712✔
1435
};
712✔
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
) {
409✔
1445
    auto& dst_type = this->structured_sdfg_->type(dst.data());
409✔
1446
    auto base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
409✔
1447
    if (base_type->type_id() != types::TypeID::Scalar) {
409✔
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);
409✔
1451
};
409✔
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
) {
62✔
1461
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
62✔
1462
};
62✔
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
) {
24✔
1472
    if (derefs_src) {
24✔
1473
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
15✔
1474
    } else {
15✔
1475
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
9✔
1476
    }
9✔
1477
};
24✔
1478

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1574
int StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
12✔
1575
    return clear_node(block, node, {&node});
12✔
1576
}
12✔
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
) {
12✔
1583
    auto& graph = block.dataflow();
12✔
1584

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

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

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

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

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

1613
                    if (!src.require_out_edge(graph, iedge)) {
25✔
1614
                        queue.push_back(&src);
23✔
1615
                        auto edge = iedge->edge();
23✔
1616
                        graph.edges_.erase(edge);
23✔
1617
                        boost::remove_edge(edge, graph.graph_);
23✔
1618
                    } else {
23✔
1619
                        no_in_edges = false;
2✔
1620
                    }
2✔
1621
                }
25✔
1622

1623
                if (no_more_consumers && no_in_edges) {
27✔
1624
                    remove_once_set.insert(current);
24✔
1625
                    auto vertex = current->vertex();
24✔
1626
                    graph.nodes_.erase(vertex);
24✔
1627
                    boost::remove_vertex(vertex, graph.graph_);
24✔
1628
                    ++removed_nodes;
24✔
1629
                }
24✔
1630
            }
27✔
1631
        }
34✔
1632
    } while (!queue.empty());
35✔
1633

1634
    return removed_nodes;
12✔
1635
};
12✔
1636

1637
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
13✔
1638
    auto& to_dataflow = to.dataflow();
13✔
1639

1640
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
13✔
1641
    for (auto& entry : from.nodes_) {
13✔
1642
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1643
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1644
        node_mapping.insert({entry.first, vertex});
1✔
1645
    }
1✔
1646

1647
    for (auto& entry : from.edges_) {
13✔
1648
        auto src = node_mapping[entry.second->src().vertex()];
×
1649
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1650

1651
        auto edge = boost::add_edge(src, dst, to_dataflow.graph_);
×
1652

1653
        to_dataflow.edges_.insert(
×
1654
            {edge.first,
×
1655
             entry.second->clone(
×
1656
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1657
             )}
×
1658
        );
×
1659
    }
×
1660
};
13✔
1661

1662
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
21✔
1663
    auto& user_graph = source_node.get_parent();
21✔
1664
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
21✔
1665
    if (!block) {
21✔
1666
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1667
    }
×
1668

1669
    // Merge access nodes if they access the same container on a code node
1670
    for (auto& oedge : user_graph.out_edges(source_node)) {
21✔
1671
        if (auto* code_node = dynamic_cast<data_flow::CodeNode*>(&oedge.dst())) {
15✔
1672
            std::unordered_set<data_flow::Memlet*> iedges;
8✔
1673
            for (auto& iedge : user_graph.in_edges(*code_node)) {
10✔
1674
                iedges.insert(&iedge);
10✔
1675
            }
10✔
1676
            for (auto* iedge : iedges) {
10✔
1677
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
10✔
1678
                    continue;
×
1679
                }
×
1680
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
10✔
1681
                if (access_node == &source_node || access_node->data() != source_node.data()) {
10✔
1682
                    continue;
9✔
1683
                }
9✔
1684
                this->add_memlet(
1✔
1685
                    *block,
1✔
1686
                    source_node,
1✔
1687
                    iedge->src_conn(),
1✔
1688
                    *code_node,
1✔
1689
                    iedge->dst_conn(),
1✔
1690
                    iedge->subset(),
1✔
1691
                    iedge->base_type(),
1✔
1692
                    iedge->debug_info()
1✔
1693
                );
1✔
1694
                this->remove_memlet(*block, *iedge);
1✔
1695
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
1✔
1696
            }
1✔
1697
        }
8✔
1698
    }
15✔
1699

1700
    // Also merge "output" access nodes if they access the same container on a library node
1701
    for (auto& iedge : user_graph.in_edges(source_node)) {
21✔
1702
        if (auto* libnode = dynamic_cast<data_flow::LibraryNode*>(&iedge.src())) {
7✔
1703
            std::unordered_set<data_flow::Memlet*> oedges;
×
1704
            for (auto& oedge : user_graph.out_edges(*libnode)) {
×
1705
                oedges.insert(&oedge);
×
1706
            }
×
1707
            for (auto* oedge : oedges) {
×
1708
                auto* access_node = static_cast<data_flow::AccessNode*>(&oedge->dst());
×
1709
                if (access_node == &source_node || access_node->data() != source_node.data()) {
×
1710
                    continue;
×
1711
                }
×
1712
                this->add_memlet(
×
1713
                    *block,
×
1714
                    *libnode,
×
1715
                    oedge->src_conn(),
×
1716
                    source_node,
×
1717
                    oedge->dst_conn(),
×
1718
                    oedge->subset(),
×
1719
                    oedge->base_type(),
×
1720
                    oedge->debug_info()
×
1721
                );
×
1722
                this->remove_memlet(*block, *oedge);
×
1723
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
×
1724
            }
×
1725
        }
×
1726
    }
7✔
1727
}
21✔
1728

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

© 2026 Coveralls, Inc