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

daisytuner / sdfglib / 20824915644

08 Jan 2026 05:00PM UTC coverage: 62.44% (+0.4%) from 61.994%
20824915644

Pull #440

github

web-flow
Merge b4c1b5335 into acf0f021d
Pull Request #440: Faster block sorting

104 of 153 new or added lines in 2 files covered. (67.97%)

74 existing lines in 5 files now uncovered.

15068 of 24132 relevant lines covered (62.44%)

88.89 hits per line

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

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

3
#include <cstddef>
4

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

12
#define TRAVERSE_CUTOFF 30
100✔
13

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

17
namespace sdfg {
18
namespace builder {
19

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

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

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

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

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

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

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

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

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

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

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

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

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

129
    return false;
6✔
130
}
9✔
131

132

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

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

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

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

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

168

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

294
            break;
17✔
295
        }
17✔
296

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

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

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

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

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

338

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

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

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

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

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

384
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
13,438✔
385

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

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

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

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

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

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

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

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

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

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

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

429
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
1,808✔
430

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

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

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

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

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

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

456
        if (current->element_id() == element_id) {
68✔
457
            return current;
18✔
458
        }
18✔
459

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

492
    return nullptr;
×
493
};
18✔
494

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

626
Block& StructuredSDFGBuilder::
627
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
932✔
628
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
932✔
629

630
    parent.transitions_
932✔
631
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
932✔
632
        );
932✔
633

634
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
932✔
635
    (*new_block.dataflow_).parent_ = &new_block;
932✔
636

637
    return new_block;
932✔
638
};
932✔
639

640
Block& StructuredSDFGBuilder::add_block(
641
    Sequence& parent,
642
    const data_flow::DataFlowGraph& data_flow_graph,
643
    const sdfg::control_flow::Assignments& assignments,
644
    const DebugInfo& debug_info
645
) {
13✔
646
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
13✔
647

648
    parent.transitions_
13✔
649
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
13✔
650
        );
13✔
651

652
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
13✔
653
    (*new_block.dataflow_).parent_ = &new_block;
13✔
654

655
    this->add_dataflow(data_flow_graph, new_block);
13✔
656

657
    return new_block;
13✔
658
};
13✔
659

660
Block& StructuredSDFGBuilder::add_block_before(
661
    Sequence& parent,
662
    ControlFlowNode& child,
663
    const sdfg::control_flow::Assignments& assignments,
664
    const DebugInfo& debug_info
665
) {
57✔
666
    int index = parent.index(child);
57✔
667
    if (index == -1) {
57✔
668
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
669
    }
×
670

671
    parent.children_
57✔
672
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
57✔
673

674
    parent.transitions_.insert(
57✔
675
        parent.transitions_.begin() + index,
57✔
676
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
57✔
677
    );
57✔
678

679
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
57✔
680
    (*new_block.dataflow_).parent_ = &new_block;
57✔
681

682
    return new_block;
57✔
683
};
57✔
684

685
Block& StructuredSDFGBuilder::add_block_before(
686
    Sequence& parent,
687
    ControlFlowNode& child,
688
    data_flow::DataFlowGraph& data_flow_graph,
689
    const sdfg::control_flow::Assignments& assignments,
690
    const DebugInfo& debug_info
691
) {
×
692
    int index = parent.index(child);
×
693
    if (index == -1) {
×
694
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
695
    }
×
696

697
    parent.children_
×
698
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
699

700
    parent.transitions_.insert(
×
701
        parent.transitions_.begin() + index,
×
702
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
703
    );
×
704

705
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
706
    (*new_block.dataflow_).parent_ = &new_block;
×
707
    this->add_dataflow(data_flow_graph, new_block);
×
708

709
    return new_block;
×
710
};
×
711

712
Block& StructuredSDFGBuilder::add_block_after(
713
    Sequence& parent,
714
    ControlFlowNode& child,
715
    const sdfg::control_flow::Assignments& assignments,
716
    const DebugInfo& debug_info
717
) {
21✔
718
    int index = parent.index(child);
21✔
719
    if (index == -1) {
21✔
720
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
721
    }
×
722

723
    parent.children_.insert(
21✔
724
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
21✔
725
    );
21✔
726

727
    parent.transitions_.insert(
21✔
728
        parent.transitions_.begin() + index + 1,
21✔
729
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
21✔
730
    );
21✔
731

732
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
21✔
733
    (*new_block.dataflow_).parent_ = &new_block;
21✔
734

735
    return new_block;
21✔
736
};
21✔
737

738
Block& StructuredSDFGBuilder::add_block_after(
739
    Sequence& parent,
740
    ControlFlowNode& child,
741
    data_flow::DataFlowGraph& data_flow_graph,
742
    const sdfg::control_flow::Assignments& assignments,
743
    const DebugInfo& debug_info
744
) {
×
745
    int index = parent.index(child);
×
746
    if (index == -1) {
×
747
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
748
    }
×
749

750
    parent.children_.insert(
×
751
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
752
    );
×
753

754
    parent.transitions_.insert(
×
755
        parent.transitions_.begin() + index + 1,
×
756
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
757
    );
×
758

759
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
760
    (*new_block.dataflow_).parent_ = &new_block;
×
761
    this->add_dataflow(data_flow_graph, new_block);
×
762

763
    return new_block;
×
764
};
×
765

766
std::pair<Block&, Transition&> StructuredSDFGBuilder::
767
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
768
    int index = parent.index(child);
×
769
    if (index == -1) {
×
770
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
771
    }
×
772

773
    parent.children_
×
774
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
775

776
    parent.transitions_.insert(
×
777
        parent.transitions_.begin() + index,
×
778
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
779
    );
×
780

781
    auto new_entry = parent.at(index);
×
782
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
783
    (*new_block.dataflow_).parent_ = &new_block;
×
784

785
    return {new_block, new_entry.second};
×
786
};
×
787

788
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
789
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
790
) {
×
791
    int index = parent.index(child);
×
792
    if (index == -1) {
×
793
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
794
    }
×
795

796
    parent.children_
×
797
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
798

799
    parent.transitions_.insert(
×
800
        parent.transitions_.begin() + index,
×
801
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
802
    );
×
803

804
    auto new_entry = parent.at(index);
×
805
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
806
    (*new_block.dataflow_).parent_ = &new_block;
×
807

808
    this->add_dataflow(data_flow_graph, new_block);
×
809

810
    return {new_block, new_entry.second};
×
811
};
×
812

813
std::pair<Block&, Transition&> StructuredSDFGBuilder::
814
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
815
    int index = parent.index(child);
×
816
    if (index == -1) {
×
817
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
818
    }
×
819

820
    parent.children_.insert(
×
821
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
822
    );
×
823

824
    parent.transitions_.insert(
×
825
        parent.transitions_.begin() + index + 1,
×
826
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
827
    );
×
828

829
    auto new_entry = parent.at(index + 1);
×
830
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
831
    (*new_block.dataflow_).parent_ = &new_block;
×
832

833
    return {new_block, new_entry.second};
×
834
};
×
835

836
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
837
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
838
) {
×
839
    int index = parent.index(child);
×
840
    if (index == -1) {
×
841
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
842
    }
×
843

844
    parent.children_.insert(
×
845
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
846
    );
×
847

848
    parent.transitions_.insert(
×
849
        parent.transitions_.begin() + index + 1,
×
850
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
851
    );
×
852

853
    auto new_entry = parent.at(index + 1);
×
854
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
855
    (*new_block.dataflow_).parent_ = &new_block;
×
856

857
    this->add_dataflow(data_flow_graph, new_block);
×
858

859
    return {new_block, new_entry.second};
×
860
};
×
861

862
IfElse& StructuredSDFGBuilder::
863
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
90✔
864
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
90✔
865

866
    parent.transitions_
90✔
867
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
90✔
868
        );
90✔
869

870
    return static_cast<IfElse&>(*parent.children_.back().get());
90✔
871
};
90✔
872

873
IfElse& StructuredSDFGBuilder::add_if_else_before(
874
    Sequence& parent,
875
    ControlFlowNode& child,
876
    const sdfg::control_flow::Assignments& assignments,
877
    const DebugInfo& debug_info
878
) {
1✔
879
    int index = parent.index(child);
1✔
880
    if (index == -1) {
1✔
881
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
882
    }
×
883

884
    parent.children_
1✔
885
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
1✔
886

887
    parent.transitions_.insert(
1✔
888
        parent.transitions_.begin() + index,
1✔
889
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
1✔
890
    );
1✔
891

892
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
893
};
1✔
894

895
IfElse& StructuredSDFGBuilder::add_if_else_after(
896
    Sequence& parent,
897
    ControlFlowNode& child,
898
    const sdfg::control_flow::Assignments& assignments,
899
    const DebugInfo& debug_info
900
) {
×
901
    int index = parent.index(child);
×
902
    if (index == -1) {
×
903
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
904
    }
×
905

906
    parent.children_.insert(
×
907
        parent.children_.begin() + index + 1, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info))
×
908
    );
×
909

910
    parent.transitions_.insert(
×
911
        parent.transitions_.begin() + index + 1,
×
912
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
913
    );
×
914

915
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
916
};
×
917

918
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
919
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
920
    int index = parent.index(child);
×
921
    if (index == -1) {
×
922
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
923
    }
×
924

925
    parent.children_
×
926
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
×
927

928
    parent.transitions_.insert(
×
929
        parent.transitions_.begin() + index,
×
930
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
931
    );
×
932

933
    auto new_entry = parent.at(index);
×
934
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
935

936
    return {new_block, new_entry.second};
×
937
};
×
938

939
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
162✔
940
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
162✔
941

942
    scope.conditions_.push_back(cond);
162✔
943
    return *scope.cases_.back();
162✔
944
};
162✔
945

946
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
947
    scope.cases_.erase(scope.cases_.begin() + index);
×
948
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
949
};
×
950

951
While& StructuredSDFGBuilder::
952
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
49✔
953
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
49✔
954

955
    // Increment element id for body node
956
    this->new_element_id();
49✔
957

958
    parent.transitions_
49✔
959
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
49✔
960
        );
49✔
961

962
    return static_cast<While&>(*parent.children_.back().get());
49✔
963
};
49✔
964

965
For& StructuredSDFGBuilder::add_for(
966
    Sequence& parent,
967
    const symbolic::Symbol indvar,
968
    const symbolic::Condition condition,
969
    const symbolic::Expression init,
970
    const symbolic::Expression update,
971
    const sdfg::control_flow::Assignments& assignments,
972
    const DebugInfo& debug_info
973
) {
214✔
974
    parent.children_
214✔
975
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
214✔
976

977
    // Increment element id for body node
978
    this->new_element_id();
214✔
979

980
    parent.transitions_
214✔
981
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
214✔
982
        );
214✔
983

984
    return static_cast<For&>(*parent.children_.back().get());
214✔
985
};
214✔
986

987
For& StructuredSDFGBuilder::add_for_before(
988
    Sequence& parent,
989
    ControlFlowNode& child,
990
    const symbolic::Symbol indvar,
991
    const symbolic::Condition condition,
992
    const symbolic::Expression init,
993
    const symbolic::Expression update,
994
    const sdfg::control_flow::Assignments& assignments,
995
    const DebugInfo& debug_info
996
) {
7✔
997
    int index = parent.index(child);
7✔
998
    if (index == -1) {
7✔
999
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1000
    }
×
1001

1002
    parent.children_.insert(
7✔
1003
        parent.children_.begin() + index,
7✔
1004
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
7✔
1005
    );
7✔
1006

1007
    // Increment element id for body node
1008
    this->new_element_id();
7✔
1009

1010
    parent.transitions_.insert(
7✔
1011
        parent.transitions_.begin() + index,
7✔
1012
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
7✔
1013
    );
7✔
1014

1015
    return static_cast<For&>(*parent.children_.at(index).get());
7✔
1016
};
7✔
1017

1018
For& StructuredSDFGBuilder::add_for_after(
1019
    Sequence& parent,
1020
    ControlFlowNode& child,
1021
    const symbolic::Symbol indvar,
1022
    const symbolic::Condition condition,
1023
    const symbolic::Expression init,
1024
    const symbolic::Expression update,
1025
    const sdfg::control_flow::Assignments& assignments,
1026
    const DebugInfo& debug_info
1027
) {
2✔
1028
    int index = parent.index(child);
2✔
1029
    if (index == -1) {
2✔
1030
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1031
    }
×
1032

1033
    parent.children_.insert(
2✔
1034
        parent.children_.begin() + index + 1,
2✔
1035
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
2✔
1036
    );
2✔
1037

1038
    // Increment element id for body node
1039
    this->new_element_id();
2✔
1040

1041
    parent.transitions_.insert(
2✔
1042
        parent.transitions_.begin() + index + 1,
2✔
1043
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2✔
1044
    );
2✔
1045

1046
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
1047
};
2✔
1048

1049
Map& StructuredSDFGBuilder::add_map(
1050
    Sequence& parent,
1051
    const symbolic::Symbol indvar,
1052
    const symbolic::Condition condition,
1053
    const symbolic::Expression init,
1054
    const symbolic::Expression update,
1055
    const ScheduleType& schedule_type,
1056
    const sdfg::control_flow::Assignments& assignments,
1057
    const DebugInfo& debug_info
1058
) {
303✔
1059
    parent.children_
303✔
1060
        .push_back(std::unique_ptr<
303✔
1061
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
303✔
1062

1063
    // Increment element id for body node
1064
    this->new_element_id();
303✔
1065

1066
    parent.transitions_
303✔
1067
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
303✔
1068
        );
303✔
1069

1070
    return static_cast<Map&>(*parent.children_.back().get());
303✔
1071
};
303✔
1072

1073
Map& StructuredSDFGBuilder::add_map_before(
1074
    Sequence& parent,
1075
    ControlFlowNode& child,
1076
    const symbolic::Symbol indvar,
1077
    const symbolic::Condition condition,
1078
    const symbolic::Expression init,
1079
    const symbolic::Expression update,
1080
    const ScheduleType& schedule_type,
1081
    const sdfg::control_flow::Assignments& assignments,
1082
    const DebugInfo& debug_info
1083
) {
7✔
1084
    int index = parent.index(child);
7✔
1085
    if (index == -1) {
7✔
1086
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1087
    }
×
1088

1089
    parent.children_.insert(
7✔
1090
        parent.children_.begin() + index,
7✔
1091
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
7✔
1092
        )
7✔
1093
    );
7✔
1094

1095
    // Increment element id for body node
1096
    this->new_element_id();
7✔
1097

1098
    parent.transitions_.insert(
7✔
1099
        parent.transitions_.begin() + index,
7✔
1100
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
7✔
1101
    );
7✔
1102

1103
    return static_cast<Map&>(*parent.children_.at(index).get());
7✔
1104
};
7✔
1105

1106
Map& StructuredSDFGBuilder::add_map_after(
1107
    Sequence& parent,
1108
    ControlFlowNode& child,
1109
    const symbolic::Symbol indvar,
1110
    const symbolic::Condition condition,
1111
    const symbolic::Expression init,
1112
    const symbolic::Expression update,
1113
    const ScheduleType& schedule_type,
1114
    const sdfg::control_flow::Assignments& assignments,
1115
    const DebugInfo& debug_info
1116
) {
14✔
1117
    int index = parent.index(child);
14✔
1118
    if (index == -1) {
14✔
1119
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1120
    }
×
1121

1122
    parent.children_.insert(
14✔
1123
        parent.children_.begin() + index + 1,
14✔
1124
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
14✔
1125
        )
14✔
1126
    );
14✔
1127

1128
    // Increment element id for body node
1129
    this->new_element_id();
14✔
1130

1131
    parent.transitions_.insert(
14✔
1132
        parent.transitions_.begin() + index + 1,
14✔
1133
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
1134
    );
14✔
1135

1136
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
14✔
1137
};
14✔
1138

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

1143
    parent.transitions_
27✔
1144
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
27✔
1145
        );
27✔
1146

1147
    return static_cast<Continue&>(*parent.children_.back().get());
27✔
1148
};
27✔
1149

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

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

1158
    return static_cast<Break&>(*parent.children_.back().get());
28✔
1159
};
28✔
1160

1161
Return& StructuredSDFGBuilder::add_return(
1162
    Sequence& parent,
1163
    const std::string& data,
1164
    const sdfg::control_flow::Assignments& assignments,
1165
    const DebugInfo& debug_info
1166
) {
44✔
1167
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
44✔
1168

1169
    parent.transitions_
44✔
1170
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
44✔
1171
        );
44✔
1172

1173
    return static_cast<Return&>(*parent.children_.back().get());
44✔
1174
};
44✔
1175

1176
Return& StructuredSDFGBuilder::add_constant_return(
1177
    Sequence& parent,
1178
    const std::string& data,
1179
    const types::IType& type,
1180
    const sdfg::control_flow::Assignments& assignments,
1181
    const DebugInfo& debug_info
1182
) {
×
1183
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1184

1185
    parent.transitions_
×
1186
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1187
        );
×
1188

1189
    return static_cast<Return&>(*parent.children_.back().get());
×
1190
};
×
1191

1192
For& StructuredSDFGBuilder::convert_while(
1193
    Sequence& parent,
1194
    While& loop,
1195
    const symbolic::Symbol indvar,
1196
    const symbolic::Condition condition,
1197
    const symbolic::Expression init,
1198
    const symbolic::Expression update
1199
) {
×
1200
    int index = parent.index(loop);
×
1201
    if (index == -1) {
×
1202
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1203
    }
×
1204

1205
    auto iter = parent.children_.begin() + index;
×
1206
    auto& new_iter = *parent.children_.insert(
×
1207
        iter + 1,
×
1208
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1209
    );
×
1210

1211
    // Increment element id for body node
1212
    this->new_element_id();
×
1213

1214
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1215
    this->move_children(loop.root(), for_loop.root());
×
1216

1217
    // Remove while loop
1218
    parent.children_.erase(parent.children_.begin() + index);
×
1219

1220
    return for_loop;
×
1221
};
×
1222

1223
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
9✔
1224
    int index = parent.index(loop);
9✔
1225
    if (index == -1) {
9✔
1226
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1227
    }
×
1228

1229
    auto iter = parent.children_.begin() + index;
9✔
1230
    auto& new_iter = *parent.children_.insert(
9✔
1231
        iter + 1,
9✔
1232
        std::unique_ptr<Map>(new Map(
9✔
1233
            this->new_element_id(),
9✔
1234
            loop.debug_info(),
9✔
1235
            loop.indvar(),
9✔
1236
            loop.init(),
9✔
1237
            loop.update(),
9✔
1238
            loop.condition(),
9✔
1239
            ScheduleType_Sequential::create()
9✔
1240
        ))
9✔
1241
    );
9✔
1242

1243
    // Increment element id for body node
1244
    this->new_element_id();
9✔
1245

1246
    auto& map = dynamic_cast<Map&>(*new_iter);
9✔
1247
    this->move_children(loop.root(), map.root());
9✔
1248

1249
    // Remove for loop
1250
    parent.children_.erase(parent.children_.begin() + index);
9✔
1251

1252
    return map;
9✔
1253
};
9✔
1254

1255
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1256
    if (index >= if_else.conditions_.size()) {
×
1257
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1258
    }
×
1259
    if_else.conditions_.at(index) = condition;
×
1260
};
×
1261

1262
void StructuredSDFGBuilder::update_loop(
1263
    StructuredLoop& loop,
1264
    const symbolic::Symbol indvar,
1265
    const symbolic::Condition condition,
1266
    const symbolic::Expression init,
1267
    const symbolic::Expression update
1268
) {
20✔
1269
    loop.indvar_ = indvar;
20✔
1270
    loop.condition_ = condition;
20✔
1271
    loop.init_ = init;
20✔
1272
    loop.update_ = update;
20✔
1273
};
20✔
1274

1275
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
5✔
1276
    map.schedule_type_ = schedule_type;
5✔
1277
}
5✔
1278

UNCOV
1279
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
×
UNCOV
1280
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
×
UNCOV
1281
    while (!queue.empty()) {
×
UNCOV
1282
        auto current = queue.front();
×
UNCOV
1283
        queue.pop_front();
×
1284

UNCOV
1285
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
×
UNCOV
1286
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
×
UNCOV
1287
                if (&sequence_stmt->at(i).first == &node) {
×
UNCOV
1288
                    return *sequence_stmt;
×
UNCOV
1289
                }
×
1290
                queue.push_back(&sequence_stmt->at(i).first);
×
1291
            }
×
UNCOV
1292
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1293
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1294
                queue.push_back(&if_else_stmt->at(i).first);
×
1295
            }
×
1296
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1297
            queue.push_back(&while_stmt->root());
×
1298
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1299
            queue.push_back(&loop_stmt->root());
×
1300
        }
×
UNCOV
1301
    }
×
1302

1303
    return this->structured_sdfg_->root();
×
UNCOV
1304
};
×
1305

1306
/***** Section: Dataflow Graph *****/
1307

1308
data_flow::AccessNode& StructuredSDFGBuilder::
1309
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
1,597✔
1310
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
1,597✔
1311
    auto res = block.dataflow_->nodes_.insert(
1,597✔
1312
        {vertex,
1,597✔
1313
         std::unique_ptr<data_flow::AccessNode>(
1,597✔
1314
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
1,597✔
1315
         )}
1,597✔
1316
    );
1,597✔
1317

1318
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
1,597✔
1319
};
1,597✔
1320

1321
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
1322
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1323
) {
132✔
1324
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
132✔
1325
    auto res = block.dataflow_->nodes_.insert(
132✔
1326
        {vertex,
132✔
1327
         std::unique_ptr<data_flow::ConstantNode>(
132✔
1328
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
132✔
1329
         )}
132✔
1330
    );
132✔
1331

1332
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
132✔
1333
};
132✔
1334

1335

1336
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
1337
    structured_control_flow::Block& block,
1338
    const data_flow::TaskletCode code,
1339
    const std::string& output,
1340
    const std::vector<std::string>& inputs,
1341
    const DebugInfo& debug_info
1342
) {
433✔
1343
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
433✔
1344
    auto res = block.dataflow_->nodes_.insert(
433✔
1345
        {vertex,
433✔
1346
         std::unique_ptr<data_flow::Tasklet>(
433✔
1347
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
433✔
1348
         )}
433✔
1349
    );
433✔
1350

1351
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
433✔
1352
};
433✔
1353

1354
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
1355
    structured_control_flow::Block& block,
1356
    data_flow::DataFlowNode& src,
1357
    const std::string& src_conn,
1358
    data_flow::DataFlowNode& dst,
1359
    const std::string& dst_conn,
1360
    const data_flow::Subset& subset,
1361
    const types::IType& base_type,
1362
    const DebugInfo& debug_info
1363
) {
1,737✔
1364
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
1,737✔
1365
    auto res = block.dataflow_->edges_.insert(
1,737✔
1366
        {edge.first,
1,737✔
1367
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,737✔
1368
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
1,737✔
1369
         ))}
1,737✔
1370
    );
1,737✔
1371

1372
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
1,737✔
1373
#ifndef NDEBUG
1,737✔
1374
    memlet.validate(*this->structured_sdfg_);
1,737✔
1375
#endif
1,737✔
1376

1377
    return memlet;
1,737✔
1378
};
1,737✔
1379

1380
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1381
    structured_control_flow::Block& block,
1382
    data_flow::AccessNode& src,
1383
    data_flow::Tasklet& dst,
1384
    const std::string& dst_conn,
1385
    const data_flow::Subset& subset,
1386
    const types::IType& base_type,
1387
    const DebugInfo& debug_info
1388
) {
266✔
1389
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
266✔
1390
};
266✔
1391

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

1404
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1405
    structured_control_flow::Block& block,
1406
    data_flow::AccessNode& src,
1407
    data_flow::Tasklet& dst,
1408
    const std::string& dst_conn,
1409
    const data_flow::Subset& subset,
1410
    const DebugInfo& debug_info
1411
) {
295✔
1412
    const types::IType* src_type = nullptr;
295✔
1413
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
295✔
1414
        src_type = &cnode->type();
83✔
1415
    } else {
212✔
1416
        src_type = &this->structured_sdfg_->type(src.data());
212✔
1417
    }
212✔
1418
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
295✔
1419
    if (base_type.type_id() != types::TypeID::Scalar) {
295✔
1420
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1421
    }
×
1422
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
295✔
1423
};
295✔
1424

1425
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1426
    structured_control_flow::Block& block,
1427
    data_flow::Tasklet& src,
1428
    const std::string& src_conn,
1429
    data_flow::AccessNode& dst,
1430
    const data_flow::Subset& subset,
1431
    const DebugInfo& debug_info
1432
) {
184✔
1433
    auto& dst_type = this->structured_sdfg_->type(dst.data());
184✔
1434
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
184✔
1435
    if (base_type.type_id() != types::TypeID::Scalar) {
184✔
1436
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1437
    }
×
1438
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
184✔
1439
};
184✔
1440

1441
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1442
    structured_control_flow::Block& block,
1443
    data_flow::AccessNode& src,
1444
    data_flow::LibraryNode& dst,
1445
    const std::string& dst_conn,
1446
    const data_flow::Subset& subset,
1447
    const types::IType& base_type,
1448
    const DebugInfo& debug_info
1449
) {
347✔
1450
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
347✔
1451
};
347✔
1452

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

1465
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
1466
    structured_control_flow::Block& block,
1467
    data_flow::AccessNode& src,
1468
    data_flow::AccessNode& dst,
1469
    const data_flow::Subset& subset,
1470
    const types::IType& base_type,
1471
    const DebugInfo& debug_info
1472
) {
47✔
1473
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
47✔
1474
};
47✔
1475

1476
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
1477
    structured_control_flow::Block& block,
1478
    data_flow::AccessNode& src,
1479
    data_flow::AccessNode& dst,
1480
    bool derefs_src,
1481
    const types::IType& base_type,
1482
    const DebugInfo& debug_info
1483
) {
20✔
1484
    if (derefs_src) {
20✔
1485
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
13✔
1486
    } else {
13✔
1487
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
7✔
1488
    }
7✔
1489
};
20✔
1490

1491
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
283✔
1492
    auto& graph = block.dataflow();
283✔
1493
    auto e = edge.edge();
283✔
1494
    boost::remove_edge(e, graph.graph_);
283✔
1495
    graph.edges_.erase(e);
283✔
1496
};
283✔
1497

1498
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
392✔
1499
    auto& graph = block.dataflow();
392✔
1500
    auto v = node.vertex();
392✔
1501
    boost::remove_vertex(v, graph.graph_);
392✔
1502
    graph.nodes_.erase(v);
392✔
1503
};
392✔
1504

1505
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
28✔
1506
    auto& graph = block.dataflow();
28✔
1507

1508
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
28✔
1509

1510
    // Delete incoming
1511
    std::list<const data_flow::Memlet*> iedges;
28✔
1512
    for (auto& iedge : graph.in_edges(node)) {
48✔
1513
        iedges.push_back(&iedge);
48✔
1514
    }
48✔
1515
    for (auto iedge : iedges) {
48✔
1516
        auto& src = iedge->src();
48✔
1517
        to_delete.insert(&src);
48✔
1518

1519
        auto edge = iedge->edge();
48✔
1520
        graph.edges_.erase(edge);
48✔
1521
        boost::remove_edge(edge, graph.graph_);
48✔
1522
    }
48✔
1523

1524
    // Delete outgoing
1525
    std::list<const data_flow::Memlet*> oedges;
28✔
1526
    for (auto& oedge : graph.out_edges(node)) {
28✔
1527
        oedges.push_back(&oedge);
28✔
1528
    }
28✔
1529
    for (auto oedge : oedges) {
28✔
1530
        auto& dst = oedge->dst();
28✔
1531
        to_delete.insert(&dst);
28✔
1532

1533
        auto edge = oedge->edge();
28✔
1534
        graph.edges_.erase(edge);
28✔
1535
        boost::remove_edge(edge, graph.graph_);
28✔
1536
    }
28✔
1537

1538
    // Delete nodes
1539
    for (auto obsolete_node : to_delete) {
104✔
1540
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
104✔
1541
            auto vertex = obsolete_node->vertex();
104✔
1542
            graph.nodes_.erase(vertex);
104✔
1543
            boost::remove_vertex(vertex, graph.graph_);
104✔
1544
        }
104✔
1545
    }
104✔
1546
};
28✔
1547

1548
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
9✔
1549
    auto& graph = block.dataflow();
9✔
1550

1551
    std::list<const data_flow::Memlet*> tmp;
9✔
1552
    std::list<const data_flow::DataFlowNode*> queue = {&node};
9✔
1553
    while (!queue.empty()) {
33✔
1554
        auto current = queue.front();
24✔
1555
        queue.pop_front();
24✔
1556
        if (current != &node) {
24✔
1557
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
15✔
1558
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
6✔
1559
                    continue;
×
1560
                }
×
1561
            }
6✔
1562
        }
15✔
1563

1564
        tmp.clear();
24✔
1565
        for (auto& iedge : graph.in_edges(*current)) {
24✔
1566
            tmp.push_back(&iedge);
15✔
1567
        }
15✔
1568
        for (auto iedge : tmp) {
24✔
1569
            auto& src = iedge->src();
15✔
1570
            queue.push_back(&src);
15✔
1571

1572
            auto edge = iedge->edge();
15✔
1573
            graph.edges_.erase(edge);
15✔
1574
            boost::remove_edge(edge, graph.graph_);
15✔
1575
        }
15✔
1576

1577
        if (current != &node || graph.out_degree(*current) == 0) {
24✔
1578
            auto vertex = current->vertex();
23✔
1579
            graph.nodes_.erase(vertex);
23✔
1580
            boost::remove_vertex(vertex, graph.graph_);
23✔
1581
        }
23✔
1582
    }
24✔
1583
};
9✔
1584

1585
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
13✔
1586
    auto& to_dataflow = to.dataflow();
13✔
1587

1588
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
13✔
1589
    for (auto& entry : from.nodes_) {
13✔
1590
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1591
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1592
        node_mapping.insert({entry.first, vertex});
1✔
1593
    }
1✔
1594

1595
    for (auto& entry : from.edges_) {
13✔
1596
        auto src = node_mapping[entry.second->src().vertex()];
×
1597
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1598

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

1601
        to_dataflow.edges_.insert(
×
1602
            {edge.first,
×
1603
             entry.second->clone(
×
1604
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1605
             )}
×
1606
        );
×
1607
    }
×
1608
};
13✔
1609

1610
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
20✔
1611
    auto& user_graph = source_node.get_parent();
20✔
1612
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
20✔
1613
    if (!block) {
20✔
1614
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1615
    }
×
1616

1617
    // Merge access nodes if they access the same container on a tasklet
1618
    for (auto& oedge : user_graph.out_edges(source_node)) {
20✔
1619
        if (auto* tasklet = dynamic_cast<data_flow::Tasklet*>(&oedge.dst())) {
14✔
1620
            std::unordered_set<data_flow::Memlet*> iedges;
7✔
1621
            for (auto& iedge : user_graph.in_edges(*tasklet)) {
9✔
1622
                iedges.insert(&iedge);
9✔
1623
            }
9✔
1624
            for (auto* iedge : iedges) {
9✔
1625
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
9✔
1626
                    continue;
×
1627
                }
×
1628
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
9✔
1629
                if (access_node == &source_node || access_node->data() != source_node.data()) {
9✔
1630
                    continue;
8✔
1631
                }
8✔
1632
                this->add_memlet(
1✔
1633
                    *block,
1✔
1634
                    source_node,
1✔
1635
                    iedge->src_conn(),
1✔
1636
                    *tasklet,
1✔
1637
                    iedge->dst_conn(),
1✔
1638
                    iedge->subset(),
1✔
1639
                    iedge->base_type(),
1✔
1640
                    iedge->debug_info()
1✔
1641
                );
1✔
1642
                this->remove_memlet(*block, *iedge);
1✔
1643
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
1✔
1644
            }
1✔
1645
        }
7✔
1646
    }
14✔
1647
}
20✔
1648

1649
} // namespace builder
1650
} // 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