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

daisytuner / sdfglib / 19143519527

06 Nov 2025 05:01PM UTC coverage: 61.911% (-0.2%) from 62.068%
19143519527

push

github

web-flow
Merge pull request #324 from daisytuner/stable-sdfg-registry

Stable sdfg registry

7 of 53 new or added lines in 3 files covered. (13.21%)

1 existing line in 1 file now uncovered.

10271 of 16590 relevant lines covered (61.91%)

101.5 hits per line

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

66.51
/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
using namespace sdfg::control_flow;
13
using namespace sdfg::structured_control_flow;
14

15
namespace sdfg {
16
namespace builder {
17

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

31
        nodes.insert(curr);
3✔
32
        if (curr == &end) {
3✔
33
            continue;
1✔
34
        }
35

36
        for (auto& iedge : sdfg.in_edges(*curr)) {
4✔
37
            queue.push_back(&iedge.src());
2✔
38
        }
39
    }
40

41
    return nodes;
1✔
42
};
1✔
43

44
bool post_dominates(
6✔
45
    const State* pdom,
46
    const State* node,
47
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree
48
) {
49
    if (pdom == node) {
6✔
50
        return true;
1✔
51
    }
52

53
    auto current = pdom_tree.at(node);
5✔
54
    while (current != nullptr) {
9✔
55
        if (current == pdom) {
9✔
56
            return true;
5✔
57
        }
58
        current = pdom_tree.at(current);
4✔
59
    }
60

61
    return false;
×
62
}
6✔
63

64
const control_flow::State* StructuredSDFGBuilder::find_end_of_if_else(
3✔
65
    SDFG& sdfg,
66
    const State* current,
67
    std::vector<const InterstateEdge*>& out_edges,
68
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree
69
) {
70
    // Best-effort approach: Check if post-dominator of current dominates all out edges
71
    auto pdom = pdom_tree.at(current);
3✔
72
    if (pdom == nullptr) {
3✔
73
        return nullptr;
×
74
    }
75

76
    for (auto& edge : out_edges) {
9✔
77
        if (!post_dominates(pdom, &edge->dst(), pdom_tree)) {
6✔
78
            return nullptr;
×
79
        }
80
    }
81

82
    return pdom;
3✔
83
}
3✔
84

85
void StructuredSDFGBuilder::traverse(SDFG& sdfg) {
4✔
86
    // Start of SDFGS
87
    Sequence& root = *structured_sdfg_->root_;
4✔
88
    const State* start_state = &sdfg.start_state();
4✔
89

90
    auto pdom_tree = sdfg.post_dominator_tree();
4✔
91

92
    std::unordered_set<const InterstateEdge*> breaks;
4✔
93
    std::unordered_set<const InterstateEdge*> continues;
4✔
94
    for (auto& edge : sdfg.back_edges()) {
5✔
95
        continues.insert(edge);
1✔
96
    }
97

98
    std::unordered_set<const control_flow::State*> visited;
4✔
99
    this->traverse_with_loop_detection(sdfg, root, start_state, nullptr, continues, breaks, pdom_tree, visited);
4✔
100
};
4✔
101

102
void StructuredSDFGBuilder::traverse_with_loop_detection(
9✔
103
    SDFG& sdfg,
104
    Sequence& scope,
105
    const State* current,
106
    const State* end,
107
    const std::unordered_set<const InterstateEdge*>& continues,
108
    const std::unordered_set<const InterstateEdge*>& breaks,
109
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
110
    std::unordered_set<const control_flow::State*>& visited
111
) {
112
    if (current == end) {
9✔
113
        return;
1✔
114
    }
115

116
    auto in_edges = sdfg.in_edges(*current);
8✔
117

118
    // Loop detection
119
    std::unordered_set<const InterstateEdge*> loop_edges;
8✔
120
    for (auto& iedge : in_edges) {
13✔
121
        if (continues.find(&iedge) != continues.end()) {
5✔
122
            loop_edges.insert(&iedge);
1✔
123
        }
1✔
124
    }
125
    if (!loop_edges.empty()) {
8✔
126
        // 1. Determine nodes of loop body
127
        std::unordered_set<const control_flow::State*> body;
1✔
128
        for (auto back_edge : loop_edges) {
2✔
129
            auto loop_nodes = this->determine_loop_nodes(sdfg, back_edge->src(), back_edge->dst());
1✔
130
            body.insert(loop_nodes.begin(), loop_nodes.end());
1✔
131
        }
1✔
132

133
        // 2. Determine exit states and exit edges
134
        std::unordered_set<const control_flow::State*> exit_states;
1✔
135
        std::unordered_set<const control_flow::InterstateEdge*> exit_edges;
1✔
136
        for (auto node : body) {
4✔
137
            for (auto& edge : sdfg.out_edges(*node)) {
7✔
138
                if (body.find(&edge.dst()) == body.end()) {
4✔
139
                    exit_edges.insert(&edge);
1✔
140
                    exit_states.insert(&edge.dst());
1✔
141
                }
1✔
142
            }
143
        }
144
        if (exit_states.size() != 1) {
1✔
145
            throw UnstructuredControlFlowException();
×
146
        }
147
        const control_flow::State* exit_state = *exit_states.begin();
1✔
148

149
        for (auto& edge : breaks) {
1✔
150
            exit_edges.insert(edge);
×
151
        }
152

153
        // Collect debug information (could be removed when this is computed dynamically)
154
        DebugInfo dbg_info = current->debug_info();
1✔
155
        for (auto& edge : in_edges) {
3✔
156
            dbg_info = DebugInfo::merge(dbg_info, edge.debug_info());
2✔
157
        }
158
        for (auto node : body) {
4✔
159
            dbg_info = DebugInfo::merge(dbg_info, node->debug_info());
3✔
160
        }
161
        for (auto edge : exit_edges) {
2✔
162
            dbg_info = DebugInfo::merge(dbg_info, edge->debug_info());
1✔
163
        }
164

165
        // 3. Add while loop
166
        While& loop = this->add_while(scope, {}, dbg_info);
1✔
167

168
        std::unordered_set<const control_flow::State*> loop_visited(visited);
1✔
169
        this->traverse_without_loop_detection(
1✔
170
            sdfg, loop.root(), current, exit_state, continues, exit_edges, pdom_tree, loop_visited
1✔
171
        );
172

173
        this->traverse_with_loop_detection(sdfg, scope, exit_state, end, continues, breaks, pdom_tree, visited);
1✔
174
    } else {
1✔
175
        this->traverse_without_loop_detection(sdfg, scope, current, end, continues, breaks, pdom_tree, visited);
7✔
176
    }
177
};
9✔
178

179
void StructuredSDFGBuilder::traverse_without_loop_detection(
8✔
180
    SDFG& sdfg,
181
    Sequence& scope,
182
    const State* current,
183
    const State* end,
184
    const std::unordered_set<const InterstateEdge*>& continues,
185
    const std::unordered_set<const InterstateEdge*>& breaks,
186
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
187
    std::unordered_set<const control_flow::State*>& visited
188
) {
189
    std::list<const State*> queue = {current};
8✔
190
    while (!queue.empty()) {
28✔
191
        auto curr = queue.front();
20✔
192
        queue.pop_front();
20✔
193
        if (curr == end) {
20✔
194
            continue;
3✔
195
        }
196

197
        if (visited.find(curr) != visited.end()) {
17✔
198
            throw UnstructuredControlFlowException();
×
199
        }
200
        visited.insert(curr);
17✔
201

202
        auto out_edges = sdfg.out_edges(*curr);
17✔
203
        auto out_degree = sdfg.out_degree(*curr);
17✔
204

205
        // Case 1: Sink node
206
        if (out_degree == 0) {
17✔
207
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
4✔
208

209
            auto return_state = dynamic_cast<const control_flow::ReturnState*>(curr);
4✔
210
            assert(return_state != nullptr);
4✔
211
            if (return_state->is_data()) {
4✔
212
                this->add_return(scope, return_state->data(), {}, return_state->debug_info());
4✔
213
            } else if (return_state->is_unreachable()) {
4✔
214
                this->add_unreachable(scope, {}, return_state->debug_info());
×
215
            } else if (return_state->is_constant()) {
×
216
                this->add_constant_return(
×
217
                    scope, return_state->data(), return_state->type(), {}, return_state->debug_info()
×
218
                );
219
            } else {
×
220
                assert(false && "Unknown return state type");
×
221
            }
222

223
            continue;
4✔
224
        }
225

226
        // Case 2: Transition
227
        if (out_degree == 1) {
13✔
228
            auto& oedge = *out_edges.begin();
10✔
229
            if (!oedge.is_unconditional()) {
10✔
230
                throw UnstructuredControlFlowException();
×
231
            }
232
            this->add_block(scope, curr->dataflow(), oedge.assignments(), curr->debug_info());
10✔
233

234
            if (continues.find(&oedge) != continues.end()) {
10✔
235
                this->add_continue(scope, {}, oedge.debug_info());
×
236
            } else if (breaks.find(&oedge) != breaks.end()) {
10✔
237
                this->add_break(scope, {}, oedge.debug_info());
×
238
            } else {
×
239
                bool starts_loop = false;
10✔
240
                for (auto& iedge : sdfg.in_edges(oedge.dst())) {
23✔
241
                    if (continues.find(&iedge) != continues.end()) {
13✔
242
                        starts_loop = true;
×
243
                        break;
×
244
                    }
245
                }
246
                if (!starts_loop) {
10✔
247
                    queue.push_back(&oedge.dst());
10✔
248
                } else {
10✔
249
                    this->traverse_with_loop_detection(
×
250
                        sdfg, scope, &oedge.dst(), end, continues, breaks, pdom_tree, visited
×
251
                    );
252
                }
253
            }
254
            continue;
10✔
255
        }
256

257
        // Case 3: Branches
258
        if (out_degree > 1) {
3✔
259
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
3✔
260

261
            std::vector<const InterstateEdge*> out_edges_vec;
3✔
262
            for (auto& edge : out_edges) {
9✔
263
                out_edges_vec.push_back(&edge);
6✔
264
            }
265

266
            // Best-effort approach: Find end of if-else
267
            // If not found, the branches may repeat paths yielding a large SDFG
268
            const control_flow::State* local_end = this->find_end_of_if_else(sdfg, curr, out_edges_vec, pdom_tree);
3✔
269
            if (local_end == nullptr) {
3✔
270
                local_end = end;
×
271
            }
×
272

273
            auto& if_else = this->add_if_else(scope, {}, curr->debug_info());
3✔
274
            for (size_t i = 0; i < out_degree; i++) {
9✔
275
                auto& out_edge = out_edges_vec[i];
6✔
276

277
                auto& branch = this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
278
                if (!out_edge->assignments().empty()) {
6✔
279
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
280
                }
2✔
281
                if (continues.find(out_edge) != continues.end()) {
6✔
282
                    this->add_continue(branch, {}, out_edge->debug_info());
1✔
283
                } else if (breaks.find(out_edge) != breaks.end()) {
6✔
284
                    this->add_break(branch, {}, out_edge->debug_info());
1✔
285
                } else {
1✔
286
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
4✔
287
                    this->traverse_with_loop_detection(
4✔
288
                        sdfg, branch, &out_edge->dst(), local_end, continues, breaks, pdom_tree, branch_visited
4✔
289
                    );
290
                }
4✔
291
            }
6✔
292

293
            if (local_end != end) {
3✔
294
                bool starts_loop = false;
2✔
295
                for (auto& iedge : sdfg.in_edges(*local_end)) {
6✔
296
                    if (continues.find(&iedge) != continues.end()) {
4✔
297
                        starts_loop = true;
×
298
                        break;
×
299
                    }
300
                }
301
                if (!starts_loop) {
2✔
302
                    queue.push_back(local_end);
2✔
303
                } else {
2✔
304
                    this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues, breaks, pdom_tree, visited);
×
305
                }
306
            }
2✔
307
            continue;
308
        }
3✔
309
    }
310
}
8✔
311

312
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
5,689✔
313

NEW
314
StructuredSDFGBuilder::StructuredSDFGBuilder(StructuredSDFG& sdfg)
×
NEW
315
    : FunctionBuilder(), structured_sdfg_(&sdfg, owned(false)) {};
×
316

317
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
89✔
318
    : FunctionBuilder(), structured_sdfg_(sdfg.release(), owned(true)) {};
89✔
319

320
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
416✔
321
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type), owned(true)) {};
416✔
322

323
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
7✔
324
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type, return_type), owned(true)) {};
7✔
325

326
StructuredSDFGBuilder::StructuredSDFGBuilder(SDFG& sdfg)
4✔
327
    : FunctionBuilder(),
4✔
328
      structured_sdfg_(new StructuredSDFG(sdfg.name(), sdfg.type(), sdfg.return_type()), owned(true)) {
4✔
329
    for (auto& entry : sdfg.structures_) {
4✔
330
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
331
    }
332

333
    for (auto& entry : sdfg.containers_) {
11✔
334
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
335
    }
336

337
    for (auto& arg : sdfg.arguments_) {
6✔
338
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
339
    }
340

341
    for (auto& ext : sdfg.externals_) {
5✔
342
        this->structured_sdfg_->externals_.push_back(ext);
1✔
343
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
1✔
344
    }
345

346
    for (auto& entry : sdfg.assumptions_) {
9✔
347
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
348
    }
349

350
    for (auto& entry : sdfg.metadata_) {
6✔
351
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
352
    }
353

354
    this->traverse(sdfg);
4✔
355
};
4✔
356

357
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
1,067✔
358

359
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
277✔
360
#ifndef NDEBUG
361
    this->structured_sdfg_->validate();
277✔
362
#endif
363

364
    if (!structured_sdfg_.get_deleter().should_delete_) {
277✔
NEW
365
        throw InvalidSDFGException("StructuredSDFGBuilder: Cannot move a non-owned SDFG");
×
366
    }
367

368
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
277✔
UNCOV
369
};
×
370

371
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
372
    FunctionBuilder::rename_container(old_name, new_name);
×
373

374
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
375
};
×
376

377
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
13✔
378
    auto& sdfg = this->subject();
13✔
379
    std::list<Element*> queue = {&sdfg.root()};
13✔
380
    while (!queue.empty()) {
55✔
381
        auto current = queue.front();
55✔
382
        queue.pop_front();
55✔
383

384
        if (current->element_id() == element_id) {
55✔
385
            return current;
13✔
386
        }
387

388
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
42✔
389
            auto& dataflow = block_stmt->dataflow();
×
390
            for (auto& node : dataflow.nodes()) {
×
391
                queue.push_back(&node);
×
392
            }
393
            for (auto& edge : dataflow.edges()) {
×
394
                queue.push_back(&edge);
×
395
            }
396
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
42✔
397
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
44✔
398
                queue.push_back(&sequence_stmt->at(i).first);
22✔
399
                queue.push_back(&sequence_stmt->at(i).second);
22✔
400
            }
22✔
401
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
42✔
402
            // Do nothing
403
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
20✔
404
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
405
                queue.push_back(&if_else_stmt->at(i).first);
×
406
            }
×
407
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
20✔
408
            queue.push_back(&for_stmt->root());
×
409
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
20✔
410
            queue.push_back(&while_stmt->root());
×
411
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
20✔
412
            // Do nothing
413
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
20✔
414
            // Do nothing
415
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
20✔
416
            queue.push_back(&map_stmt->root());
10✔
417
        }
10✔
418
    }
419

420
    return nullptr;
×
421
};
13✔
422

423
Sequence& StructuredSDFGBuilder::
424
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
28✔
425
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
28✔
426

427
    parent.transitions_
56✔
428
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
28✔
429
        );
430

431
    return static_cast<Sequence&>(*parent.children_.back().get());
28✔
432
};
×
433

434
Sequence& StructuredSDFGBuilder::add_sequence_before(
5✔
435
    Sequence& parent,
436
    ControlFlowNode& child,
437
    const sdfg::control_flow::Assignments& assignments,
438
    const DebugInfo& debug_info
439
) {
440
    int index = parent.index(child);
5✔
441
    if (index == -1) {
5✔
442
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
443
    }
444

445
    parent.children_.insert(
10✔
446
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
5✔
447
    );
448

449
    parent.transitions_.insert(
10✔
450
        parent.transitions_.begin() + index,
5✔
451
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
5✔
452
    );
453

454
    return static_cast<Sequence&>(*parent.children_.at(index).get());
5✔
455
};
×
456

457
Sequence& StructuredSDFGBuilder::add_sequence_after(
×
458
    Sequence& parent,
459
    ControlFlowNode& child,
460
    const sdfg::control_flow::Assignments& assignments,
461
    const DebugInfo& debug_info
462
) {
463
    int index = parent.index(child);
×
464
    if (index == -1) {
×
465
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
466
    }
467

468
    parent.children_.insert(
×
469
        parent.children_.begin() + index + 1,
×
470
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
471
    );
472

473
    parent.transitions_.insert(
×
474
        parent.transitions_.begin() + index + 1,
×
475
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
476
    );
477

478
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
479
};
×
480

481
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
482
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
483
    int index = parent.index(child);
×
484
    if (index == -1) {
×
485
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
486
    }
487

488
    parent.children_.insert(
×
489
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
490
    );
491

492
    parent.transitions_.insert(
×
493
        parent.transitions_.begin() + index,
×
494
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
495
    );
496

497
    auto new_entry = parent.at(index);
×
498
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
499

500
    return {new_block, new_entry.second};
×
501
};
×
502

503
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
23✔
504
    parent.children_.erase(parent.children_.begin() + index);
23✔
505
    parent.transitions_.erase(parent.transitions_.begin() + index);
23✔
506
};
23✔
507

508
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
509
    parent.children_.clear();
×
510
    parent.transitions_.clear();
×
511
};
×
512

513
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
10✔
514
    this->move_child(source, source_index, target, target.size());
10✔
515
};
10✔
516

517
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
10✔
518
    auto node_ptr = std::move(source.children_.at(source_index));
10✔
519
    auto trans_ptr = std::move(source.transitions_.at(source_index));
10✔
520
    source.children_.erase(source.children_.begin() + source_index);
10✔
521
    source.transitions_.erase(source.transitions_.begin() + source_index);
10✔
522

523
    trans_ptr->parent_ = &target;
10✔
524
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
10✔
525
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
10✔
526
};
10✔
527

528
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
23✔
529
    this->move_children(source, target, target.size());
23✔
530
};
23✔
531

532
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
23✔
533
    target.children_.insert(
46✔
534
        target.children_.begin() + target_index,
23✔
535
        std::make_move_iterator(source.children_.begin()),
23✔
536
        std::make_move_iterator(source.children_.end())
23✔
537
    );
538
    target.transitions_.insert(
46✔
539
        target.transitions_.begin() + target_index,
23✔
540
        std::make_move_iterator(source.transitions_.begin()),
23✔
541
        std::make_move_iterator(source.transitions_.end())
23✔
542
    );
543
    for (auto& trans : target.transitions_) {
52✔
544
        trans->parent_ = &target;
29✔
545
    }
546
    source.children_.clear();
23✔
547
    source.transitions_.clear();
23✔
548
};
23✔
549

550
Block& StructuredSDFGBuilder::
551
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
425✔
552
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
425✔
553

554
    parent.transitions_
850✔
555
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
425✔
556
        );
557

558
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
425✔
559
    (*new_block.dataflow_).parent_ = &new_block;
425✔
560

561
    return new_block;
425✔
562
};
×
563

564
Block& StructuredSDFGBuilder::add_block(
20✔
565
    Sequence& parent,
566
    const data_flow::DataFlowGraph& data_flow_graph,
567
    const sdfg::control_flow::Assignments& assignments,
568
    const DebugInfo& debug_info
569
) {
570
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
20✔
571

572
    parent.transitions_
40✔
573
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
20✔
574
        );
575

576
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
20✔
577
    (*new_block.dataflow_).parent_ = &new_block;
20✔
578

579
    this->add_dataflow(data_flow_graph, new_block);
20✔
580

581
    return new_block;
20✔
582
};
×
583

584
Block& StructuredSDFGBuilder::add_block_before(
12✔
585
    Sequence& parent,
586
    ControlFlowNode& child,
587
    const sdfg::control_flow::Assignments& assignments,
588
    const DebugInfo& debug_info
589
) {
590
    int index = parent.index(child);
12✔
591
    if (index == -1) {
12✔
592
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
593
    }
594

595
    parent.children_
24✔
596
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
12✔
597

598
    parent.transitions_.insert(
24✔
599
        parent.transitions_.begin() + index,
12✔
600
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
12✔
601
    );
602

603
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
12✔
604
    (*new_block.dataflow_).parent_ = &new_block;
12✔
605

606
    return new_block;
12✔
607
};
×
608

609
Block& StructuredSDFGBuilder::add_block_before(
×
610
    Sequence& parent,
611
    ControlFlowNode& child,
612
    data_flow::DataFlowGraph& data_flow_graph,
613
    const sdfg::control_flow::Assignments& assignments,
614
    const DebugInfo& debug_info
615
) {
616
    int index = parent.index(child);
×
617
    if (index == -1) {
×
618
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
619
    }
620

621
    parent.children_
×
622
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
623

624
    parent.transitions_.insert(
×
625
        parent.transitions_.begin() + index,
×
626
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
627
    );
628

629
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
630
    (*new_block.dataflow_).parent_ = &new_block;
×
631
    this->add_dataflow(data_flow_graph, new_block);
×
632

633
    return new_block;
×
634
};
×
635

636
Block& StructuredSDFGBuilder::add_block_after(
3✔
637
    Sequence& parent,
638
    ControlFlowNode& child,
639
    const sdfg::control_flow::Assignments& assignments,
640
    const DebugInfo& debug_info
641
) {
642
    int index = parent.index(child);
3✔
643
    if (index == -1) {
3✔
644
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
645
    }
646

647
    parent.children_.insert(
6✔
648
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3✔
649
    );
650

651
    parent.transitions_.insert(
6✔
652
        parent.transitions_.begin() + index + 1,
3✔
653
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3✔
654
    );
655

656
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
3✔
657
    (*new_block.dataflow_).parent_ = &new_block;
3✔
658

659
    return new_block;
3✔
660
};
×
661

662
Block& StructuredSDFGBuilder::add_block_after(
×
663
    Sequence& parent,
664
    ControlFlowNode& child,
665
    data_flow::DataFlowGraph& data_flow_graph,
666
    const sdfg::control_flow::Assignments& assignments,
667
    const DebugInfo& debug_info
668
) {
669
    int index = parent.index(child);
×
670
    if (index == -1) {
×
671
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
672
    }
673

674
    parent.children_.insert(
×
675
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
676
    );
677

678
    parent.transitions_.insert(
×
679
        parent.transitions_.begin() + index + 1,
×
680
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
681
    );
682

683
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
684
    (*new_block.dataflow_).parent_ = &new_block;
×
685
    this->add_dataflow(data_flow_graph, new_block);
×
686

687
    return new_block;
×
688
};
×
689

690
std::pair<Block&, Transition&> StructuredSDFGBuilder::
691
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
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))
×
703
    );
704

705
    auto new_entry = parent.at(index);
×
706
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
707
    (*new_block.dataflow_).parent_ = &new_block;
×
708

709
    return {new_block, new_entry.second};
×
710
};
×
711

712
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
713
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
714
) {
715
    int index = parent.index(child);
×
716
    if (index == -1) {
×
717
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
718
    }
719

720
    parent.children_
×
721
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
722

723
    parent.transitions_.insert(
×
724
        parent.transitions_.begin() + index,
×
725
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
726
    );
727

728
    auto new_entry = parent.at(index);
×
729
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
730
    (*new_block.dataflow_).parent_ = &new_block;
×
731

732
    this->add_dataflow(data_flow_graph, new_block);
×
733

734
    return {new_block, new_entry.second};
×
735
};
×
736

737
std::pair<Block&, Transition&> StructuredSDFGBuilder::
738
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
739
    int index = parent.index(child);
×
740
    if (index == -1) {
×
741
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
742
    }
743

744
    parent.children_.insert(
×
745
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
746
    );
747

748
    parent.transitions_.insert(
×
749
        parent.transitions_.begin() + index + 1,
×
750
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
751
    );
752

753
    auto new_entry = parent.at(index + 1);
×
754
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
755
    (*new_block.dataflow_).parent_ = &new_block;
×
756

757
    return {new_block, new_entry.second};
×
758
};
×
759

760
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
761
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
762
) {
763
    int index = parent.index(child);
×
764
    if (index == -1) {
×
765
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
766
    }
767

768
    parent.children_.insert(
×
769
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
770
    );
771

772
    parent.transitions_.insert(
×
773
        parent.transitions_.begin() + index + 1,
×
774
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
775
    );
776

777
    auto new_entry = parent.at(index + 1);
×
778
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
779
    (*new_block.dataflow_).parent_ = &new_block;
×
780

781
    this->add_dataflow(data_flow_graph, new_block);
×
782

783
    return {new_block, new_entry.second};
×
784
};
×
785

786
IfElse& StructuredSDFGBuilder::
787
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
40✔
788
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
40✔
789

790
    parent.transitions_
80✔
791
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
40✔
792
        );
793

794
    return static_cast<IfElse&>(*parent.children_.back().get());
40✔
795
};
×
796

797
IfElse& StructuredSDFGBuilder::add_if_else_before(
1✔
798
    Sequence& parent,
799
    ControlFlowNode& child,
800
    const sdfg::control_flow::Assignments& assignments,
801
    const DebugInfo& debug_info
802
) {
803
    int index = parent.index(child);
1✔
804
    if (index == -1) {
1✔
805
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
806
    }
807

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

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

816
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
817
};
×
818

819
IfElse& StructuredSDFGBuilder::add_if_else_after(
×
820
    Sequence& parent,
821
    ControlFlowNode& child,
822
    const sdfg::control_flow::Assignments& assignments,
823
    const DebugInfo& debug_info
824
) {
825
    int index = parent.index(child);
×
826
    if (index == -1) {
×
827
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
828
    }
829

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

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

839
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
840
};
×
841

842
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
843
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
844
    int index = parent.index(child);
×
845
    if (index == -1) {
×
846
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
847
    }
848

849
    parent.children_
×
850
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
×
851

852
    parent.transitions_.insert(
×
853
        parent.transitions_.begin() + index,
×
854
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
855
    );
856

857
    auto new_entry = parent.at(index);
×
858
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
859

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

863
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
67✔
864
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
67✔
865

866
    scope.conditions_.push_back(cond);
67✔
867
    return *scope.cases_.back();
67✔
868
};
×
869

870
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
871
    scope.cases_.erase(scope.cases_.begin() + index);
×
872
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
873
};
×
874

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

879
    // Increment element id for body node
880
    this->new_element_id();
35✔
881

882
    parent.transitions_
70✔
883
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
35✔
884
        );
885

886
    return static_cast<While&>(*parent.children_.back().get());
35✔
887
};
×
888

889
For& StructuredSDFGBuilder::add_for(
170✔
890
    Sequence& parent,
891
    const symbolic::Symbol indvar,
892
    const symbolic::Condition condition,
893
    const symbolic::Expression init,
894
    const symbolic::Expression update,
895
    const sdfg::control_flow::Assignments& assignments,
896
    const DebugInfo& debug_info
897
) {
898
    parent.children_
340✔
899
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
170✔
900

901
    // Increment element id for body node
902
    this->new_element_id();
170✔
903

904
    parent.transitions_
340✔
905
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
170✔
906
        );
907

908
    return static_cast<For&>(*parent.children_.back().get());
170✔
909
};
×
910

911
For& StructuredSDFGBuilder::add_for_before(
6✔
912
    Sequence& parent,
913
    ControlFlowNode& child,
914
    const symbolic::Symbol indvar,
915
    const symbolic::Condition condition,
916
    const symbolic::Expression init,
917
    const symbolic::Expression update,
918
    const sdfg::control_flow::Assignments& assignments,
919
    const DebugInfo& debug_info
920
) {
921
    int index = parent.index(child);
6✔
922
    if (index == -1) {
6✔
923
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
924
    }
925

926
    parent.children_.insert(
12✔
927
        parent.children_.begin() + index,
6✔
928
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
929
    );
930

931
    // Increment element id for body node
932
    this->new_element_id();
6✔
933

934
    parent.transitions_.insert(
12✔
935
        parent.transitions_.begin() + index,
6✔
936
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
937
    );
938

939
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
940
};
×
941

942
For& StructuredSDFGBuilder::add_for_after(
2✔
943
    Sequence& parent,
944
    ControlFlowNode& child,
945
    const symbolic::Symbol indvar,
946
    const symbolic::Condition condition,
947
    const symbolic::Expression init,
948
    const symbolic::Expression update,
949
    const sdfg::control_flow::Assignments& assignments,
950
    const DebugInfo& debug_info
951
) {
952
    int index = parent.index(child);
2✔
953
    if (index == -1) {
2✔
954
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
955
    }
956

957
    parent.children_.insert(
4✔
958
        parent.children_.begin() + index + 1,
2✔
959
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
2✔
960
    );
961

962
    // Increment element id for body node
963
    this->new_element_id();
2✔
964

965
    parent.transitions_.insert(
4✔
966
        parent.transitions_.begin() + index + 1,
2✔
967
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2✔
968
    );
969

970
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
971
};
×
972

973
Map& StructuredSDFGBuilder::add_map(
41✔
974
    Sequence& parent,
975
    const symbolic::Symbol indvar,
976
    const symbolic::Condition condition,
977
    const symbolic::Expression init,
978
    const symbolic::Expression update,
979
    const ScheduleType& schedule_type,
980
    const sdfg::control_flow::Assignments& assignments,
981
    const DebugInfo& debug_info
982
) {
983
    parent.children_
82✔
984
        .push_back(std::unique_ptr<
41✔
985
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
41✔
986

987
    // Increment element id for body node
988
    this->new_element_id();
41✔
989

990
    parent.transitions_
82✔
991
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
41✔
992
        );
993

994
    return static_cast<Map&>(*parent.children_.back().get());
41✔
995
};
×
996

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

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

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

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

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

1030
Map& StructuredSDFGBuilder::add_map_after(
12✔
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 ScheduleType& schedule_type,
1038
    const sdfg::control_flow::Assignments& assignments,
1039
    const DebugInfo& debug_info
1040
) {
1041
    int index = parent.index(child);
12✔
1042
    if (index == -1) {
12✔
1043
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1044
    }
1045

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

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

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

1060
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
12✔
1061
};
×
1062

1063
Continue& StructuredSDFGBuilder::
1064
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
14✔
1065
    parent.children_.push_back(std::unique_ptr<Continue>(new Continue(this->new_element_id(), debug_info)));
14✔
1066

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

1071
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
1072
};
×
1073

1074
Break& StructuredSDFGBuilder::
1075
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
16✔
1076
    parent.children_.push_back(std::unique_ptr<Break>(new Break(this->new_element_id(), debug_info)));
16✔
1077

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

1082
    return static_cast<Break&>(*parent.children_.back().get());
16✔
1083
};
×
1084

1085
Return& StructuredSDFGBuilder::add_return(
19✔
1086
    Sequence& parent,
1087
    const std::string& data,
1088
    const sdfg::control_flow::Assignments& assignments,
1089
    const DebugInfo& debug_info
1090
) {
1091
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
19✔
1092

1093
    parent.transitions_
38✔
1094
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
19✔
1095
        );
1096

1097
    return static_cast<Return&>(*parent.children_.back().get());
19✔
1098
};
×
1099

1100
Return& StructuredSDFGBuilder::
1101
    add_unreachable(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
×
1102
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info)));
×
1103

1104
    parent.transitions_
×
1105
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1106
        );
1107

1108
    return static_cast<Return&>(*parent.children_.back().get());
×
1109
};
×
1110

1111
Return& StructuredSDFGBuilder::add_constant_return(
1✔
1112
    Sequence& parent,
1113
    const std::string& data,
1114
    const types::IType& type,
1115
    const sdfg::control_flow::Assignments& assignments,
1116
    const DebugInfo& debug_info
1117
) {
1118
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
1✔
1119

1120
    parent.transitions_
2✔
1121
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
1✔
1122
        );
1123

1124
    return static_cast<Return&>(*parent.children_.back().get());
1✔
1125
};
×
1126

1127
For& StructuredSDFGBuilder::convert_while(
×
1128
    Sequence& parent,
1129
    While& loop,
1130
    const symbolic::Symbol indvar,
1131
    const symbolic::Condition condition,
1132
    const symbolic::Expression init,
1133
    const symbolic::Expression update
1134
) {
1135
    int index = parent.index(loop);
×
1136
    if (index == -1) {
×
1137
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1138
    }
1139

1140
    auto iter = parent.children_.begin() + index;
×
1141
    auto& new_iter = *parent.children_.insert(
×
1142
        iter + 1,
×
1143
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1144
    );
1145

1146
    // Increment element id for body node
1147
    this->new_element_id();
×
1148

1149
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1150
    this->move_children(loop.root(), for_loop.root());
×
1151

1152
    // Remove while loop
1153
    parent.children_.erase(parent.children_.begin() + index);
×
1154

1155
    return for_loop;
×
1156
};
×
1157

1158
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
8✔
1159
    int index = parent.index(loop);
8✔
1160
    if (index == -1) {
8✔
1161
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1162
    }
1163

1164
    auto iter = parent.children_.begin() + index;
8✔
1165
    auto& new_iter = *parent.children_.insert(
16✔
1166
        iter + 1,
8✔
1167
        std::unique_ptr<Map>(new Map(
16✔
1168
            this->new_element_id(),
8✔
1169
            loop.debug_info(),
8✔
1170
            loop.indvar(),
8✔
1171
            loop.init(),
8✔
1172
            loop.update(),
8✔
1173
            loop.condition(),
8✔
1174
            ScheduleType_Sequential::create()
8✔
1175
        ))
1176
    );
1177

1178
    // Increment element id for body node
1179
    this->new_element_id();
8✔
1180

1181
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1182
    this->move_children(loop.root(), map.root());
8✔
1183

1184
    // Remove for loop
1185
    parent.children_.erase(parent.children_.begin() + index);
8✔
1186

1187
    return map;
8✔
1188
};
×
1189

1190
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1191
    if (index >= if_else.conditions_.size()) {
×
1192
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1193
    }
1194
    if_else.conditions_.at(index) = condition;
×
1195
};
×
1196

1197
void StructuredSDFGBuilder::update_loop(
17✔
1198
    StructuredLoop& loop,
1199
    const symbolic::Symbol indvar,
1200
    const symbolic::Condition condition,
1201
    const symbolic::Expression init,
1202
    const symbolic::Expression update
1203
) {
1204
    loop.indvar_ = indvar;
17✔
1205
    loop.condition_ = condition;
17✔
1206
    loop.init_ = init;
17✔
1207
    loop.update_ = update;
17✔
1208
};
17✔
1209

1210
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1211
    map.schedule_type_ = schedule_type;
4✔
1212
}
4✔
1213

1214
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1215
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1216
    while (!queue.empty()) {
2✔
1217
        auto current = queue.front();
2✔
1218
        queue.pop_front();
2✔
1219

1220
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1221
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1222
                if (&sequence_stmt->at(i).first == &node) {
2✔
1223
                    return *sequence_stmt;
2✔
1224
                }
1225
                queue.push_back(&sequence_stmt->at(i).first);
×
1226
            }
×
1227
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1228
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1229
                queue.push_back(&if_else_stmt->at(i).first);
×
1230
            }
×
1231
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1232
            queue.push_back(&while_stmt->root());
×
1233
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1234
            queue.push_back(&loop_stmt->root());
×
1235
        }
×
1236
    }
1237

1238
    return this->structured_sdfg_->root();
×
1239
};
2✔
1240

1241
/***** Section: Dataflow Graph *****/
1242

1243
data_flow::AccessNode& StructuredSDFGBuilder::
1244
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
617✔
1245
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
617✔
1246
    auto res = block.dataflow_->nodes_.insert(
1,234✔
1247
        {vertex,
617✔
1248
         std::unique_ptr<data_flow::AccessNode>(
617✔
1249
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
617✔
1250
         )}
1251
    );
1252

1253
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
617✔
1254
};
×
1255

1256
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
74✔
1257
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1258
) {
1259
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
74✔
1260
    auto res = block.dataflow_->nodes_.insert(
148✔
1261
        {vertex,
74✔
1262
         std::unique_ptr<data_flow::ConstantNode>(
74✔
1263
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
74✔
1264
         )}
1265
    );
1266

1267
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
74✔
1268
};
×
1269

1270

1271
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
262✔
1272
    structured_control_flow::Block& block,
1273
    const data_flow::TaskletCode code,
1274
    const std::string& output,
1275
    const std::vector<std::string>& inputs,
1276
    const DebugInfo& debug_info
1277
) {
1278
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
262✔
1279
    auto res = block.dataflow_->nodes_.insert(
524✔
1280
        {vertex,
262✔
1281
         std::unique_ptr<data_flow::Tasklet>(
262✔
1282
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
262✔
1283
         )}
1284
    );
1285

1286
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
262✔
1287
};
×
1288

1289
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
695✔
1290
    structured_control_flow::Block& block,
1291
    data_flow::DataFlowNode& src,
1292
    const std::string& src_conn,
1293
    data_flow::DataFlowNode& dst,
1294
    const std::string& dst_conn,
1295
    const data_flow::Subset& subset,
1296
    const types::IType& base_type,
1297
    const DebugInfo& debug_info
1298
) {
1299
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
695✔
1300
    auto res = block.dataflow_->edges_.insert(
1,390✔
1301
        {edge.first,
1,390✔
1302
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,390✔
1303
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
695✔
1304
         ))}
1305
    );
1306

1307
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
695✔
1308
#ifndef NDEBUG
1309
    memlet.validate(*this->structured_sdfg_);
695✔
1310
#endif
1311

1312
    return memlet;
695✔
1313
};
×
1314

1315
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
89✔
1316
    structured_control_flow::Block& block,
1317
    data_flow::AccessNode& src,
1318
    data_flow::Tasklet& dst,
1319
    const std::string& dst_conn,
1320
    const data_flow::Subset& subset,
1321
    const types::IType& base_type,
1322
    const DebugInfo& debug_info
1323
) {
1324
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
89✔
1325
};
×
1326

1327
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
84✔
1328
    structured_control_flow::Block& block,
1329
    data_flow::Tasklet& src,
1330
    const std::string& src_conn,
1331
    data_flow::AccessNode& dst,
1332
    const data_flow::Subset& subset,
1333
    const types::IType& base_type,
1334
    const DebugInfo& debug_info
1335
) {
1336
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
84✔
1337
};
×
1338

1339
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
229✔
1340
    structured_control_flow::Block& block,
1341
    data_flow::AccessNode& src,
1342
    data_flow::Tasklet& dst,
1343
    const std::string& dst_conn,
1344
    const data_flow::Subset& subset,
1345
    const DebugInfo& debug_info
1346
) {
1347
    const types::IType* src_type = nullptr;
229✔
1348
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
229✔
1349
        src_type = &cnode->type();
64✔
1350
    } else {
64✔
1351
        src_type = &this->structured_sdfg_->type(src.data());
165✔
1352
    }
1353
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
229✔
1354
    if (base_type.type_id() != types::TypeID::Scalar) {
229✔
1355
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1356
    }
1357
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
229✔
1358
};
×
1359

1360
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
156✔
1361
    structured_control_flow::Block& block,
1362
    data_flow::Tasklet& src,
1363
    const std::string& src_conn,
1364
    data_flow::AccessNode& dst,
1365
    const data_flow::Subset& subset,
1366
    const DebugInfo& debug_info
1367
) {
1368
    auto& dst_type = this->structured_sdfg_->type(dst.data());
156✔
1369
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
156✔
1370
    if (base_type.type_id() != types::TypeID::Scalar) {
156✔
1371
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1372
    }
1373
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
156✔
1374
};
×
1375

1376
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
13✔
1377
    structured_control_flow::Block& block,
1378
    data_flow::AccessNode& src,
1379
    data_flow::LibraryNode& dst,
1380
    const std::string& dst_conn,
1381
    const data_flow::Subset& subset,
1382
    const types::IType& base_type,
1383
    const DebugInfo& debug_info
1384
) {
1385
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
13✔
1386
};
×
1387

1388
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
11✔
1389
    structured_control_flow::Block& block,
1390
    data_flow::LibraryNode& src,
1391
    const std::string& src_conn,
1392
    data_flow::AccessNode& dst,
1393
    const data_flow::Subset& subset,
1394
    const types::IType& base_type,
1395
    const DebugInfo& debug_info
1396
) {
1397
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
11✔
1398
};
×
1399

1400
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
20✔
1401
    structured_control_flow::Block& block,
1402
    data_flow::AccessNode& src,
1403
    data_flow::AccessNode& dst,
1404
    const data_flow::Subset& subset,
1405
    const types::IType& base_type,
1406
    const DebugInfo& debug_info
1407
) {
1408
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
20✔
1409
};
×
1410

1411
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
13✔
1412
    structured_control_flow::Block& block,
1413
    data_flow::AccessNode& src,
1414
    data_flow::AccessNode& dst,
1415
    bool derefs_src,
1416
    const types::IType& base_type,
1417
    const DebugInfo& debug_info
1418
) {
1419
    if (derefs_src) {
13✔
1420
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
6✔
1421
    } else {
1422
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
7✔
1423
    }
1424
};
13✔
1425

1426
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
26✔
1427
    auto& graph = block.dataflow();
26✔
1428
    auto e = edge.edge();
26✔
1429
    boost::remove_edge(e, graph.graph_);
26✔
1430
    graph.edges_.erase(e);
26✔
1431
};
26✔
1432

1433
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
22✔
1434
    auto& graph = block.dataflow();
22✔
1435
    auto v = node.vertex();
22✔
1436
    boost::remove_vertex(v, graph.graph_);
22✔
1437
    graph.nodes_.erase(v);
22✔
1438
};
22✔
1439

1440
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
10✔
1441
    auto& graph = block.dataflow();
10✔
1442

1443
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
10✔
1444

1445
    // Delete incoming
1446
    std::list<const data_flow::Memlet*> iedges;
10✔
1447
    for (auto& iedge : graph.in_edges(node)) {
27✔
1448
        iedges.push_back(&iedge);
17✔
1449
    }
1450
    for (auto iedge : iedges) {
27✔
1451
        auto& src = iedge->src();
17✔
1452
        to_delete.insert(&src);
17✔
1453

1454
        auto edge = iedge->edge();
17✔
1455
        graph.edges_.erase(edge);
17✔
1456
        boost::remove_edge(edge, graph.graph_);
17✔
1457
    }
1458

1459
    // Delete outgoing
1460
    std::list<const data_flow::Memlet*> oedges;
10✔
1461
    for (auto& oedge : graph.out_edges(node)) {
20✔
1462
        oedges.push_back(&oedge);
10✔
1463
    }
1464
    for (auto oedge : oedges) {
20✔
1465
        auto& dst = oedge->dst();
10✔
1466
        to_delete.insert(&dst);
10✔
1467

1468
        auto edge = oedge->edge();
10✔
1469
        graph.edges_.erase(edge);
10✔
1470
        boost::remove_edge(edge, graph.graph_);
10✔
1471
    }
1472

1473
    // Delete nodes
1474
    for (auto obsolete_node : to_delete) {
47✔
1475
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
37✔
1476
            auto vertex = obsolete_node->vertex();
37✔
1477
            graph.nodes_.erase(vertex);
37✔
1478
            boost::remove_vertex(vertex, graph.graph_);
37✔
1479
        }
37✔
1480
    }
1481
};
10✔
1482

1483
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
5✔
1484
    auto& graph = block.dataflow();
5✔
1485
    if (graph.out_degree(node) != 0) {
5✔
1486
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1487
    }
1488

1489
    std::list<const data_flow::Memlet*> tmp;
5✔
1490
    std::list<const data_flow::DataFlowNode*> queue = {&node};
5✔
1491
    while (!queue.empty()) {
17✔
1492
        auto current = queue.front();
12✔
1493
        queue.pop_front();
12✔
1494
        if (current != &node) {
12✔
1495
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
7✔
1496
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
2✔
1497
                    continue;
×
1498
                }
1499
            }
2✔
1500
        }
7✔
1501

1502
        tmp.clear();
12✔
1503
        for (auto& iedge : graph.in_edges(*current)) {
19✔
1504
            tmp.push_back(&iedge);
7✔
1505
        }
1506
        for (auto iedge : tmp) {
19✔
1507
            auto& src = iedge->src();
7✔
1508
            queue.push_back(&src);
7✔
1509

1510
            auto edge = iedge->edge();
7✔
1511
            graph.edges_.erase(edge);
7✔
1512
            boost::remove_edge(edge, graph.graph_);
7✔
1513
        }
1514

1515
        auto vertex = current->vertex();
12✔
1516
        graph.nodes_.erase(vertex);
12✔
1517
        boost::remove_vertex(vertex, graph.graph_);
12✔
1518
    }
1519
};
5✔
1520

1521
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
20✔
1522
    auto& to_dataflow = to.dataflow();
20✔
1523

1524
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
20✔
1525
    for (auto& entry : from.nodes_) {
21✔
1526
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1527
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1528
        node_mapping.insert({entry.first, vertex});
1✔
1529
    }
1530

1531
    for (auto& entry : from.edges_) {
20✔
1532
        auto src = node_mapping[entry.second->src().vertex()];
×
1533
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1534

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

1537
        to_dataflow.edges_.insert(
×
1538
            {edge.first,
×
1539
             entry.second->clone(
×
1540
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1541
             )}
1542
        );
1543
    }
1544
};
20✔
1545

1546
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
9✔
1547
    auto& user_graph = source_node.get_parent();
9✔
1548
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
9✔
1549
    if (!block) {
9✔
1550
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1551
    }
1552

1553
    // Merge access nodes if they access the same container on a tasklet
1554
    for (auto& oedge : user_graph.out_edges(source_node)) {
15✔
1555
        if (auto* tasklet = dynamic_cast<data_flow::Tasklet*>(&oedge.dst())) {
6✔
1556
            std::unordered_set<data_flow::Memlet*> iedges;
2✔
1557
            for (auto& iedge : user_graph.in_edges(*tasklet)) {
4✔
1558
                iedges.insert(&iedge);
2✔
1559
            }
1560
            for (auto* iedge : iedges) {
4✔
1561
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
2✔
1562
                    continue;
×
1563
                }
1564
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
2✔
1565
                if (access_node == &source_node || access_node->data() != source_node.data()) {
2✔
1566
                    continue;
2✔
1567
                }
1568
                this->add_memlet(
×
1569
                    *block,
×
1570
                    source_node,
×
1571
                    iedge->src_conn(),
×
1572
                    *tasklet,
×
1573
                    iedge->dst_conn(),
×
1574
                    iedge->subset(),
×
1575
                    iedge->base_type(),
×
1576
                    iedge->debug_info()
×
1577
                );
1578
                this->remove_memlet(*block, *iedge);
×
1579
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
×
1580
            }
1581
        }
2✔
1582
    }
1583
}
9✔
1584

1585
} // namespace builder
1586
} // 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

© 2025 Coveralls, Inc