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

daisytuner / sdfglib / 17907460602

22 Sep 2025 07:08AM UTC coverage: 60.192% (-0.5%) from 60.653%
17907460602

Pull #233

github

web-flow
Merge 07c7b1d2f into c3f4f7063
Pull Request #233: adds constant returns with type and extends API

60 of 184 new or added lines in 10 files covered. (32.61%)

19 existing lines in 5 files now uncovered.

9514 of 15806 relevant lines covered (60.19%)

105.75 hits per line

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

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

3
#include <cstddef>
4

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

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

16
namespace sdfg {
17
namespace builder {
18

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

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

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

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

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

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

62
    return false;
×
63
}
6✔
64

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

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

83
    return pdom;
3✔
84
}
3✔
85

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

224
            continue;
4✔
225
        }
226

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

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

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

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

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

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

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

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

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

315
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
80✔
316
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
80✔
317

318
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
520✔
319
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type)) {};
520✔
320

321
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
5✔
322
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type, return_type)) {};
5✔
323

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

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

334
    for (auto& arg : sdfg.arguments_) {
6✔
335
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
336
    }
337

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

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

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

351
    this->traverse(sdfg);
4✔
352
};
4✔
353

354
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
1,480✔
355

356
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
260✔
357
#ifndef NDEBUG
358
    this->structured_sdfg_->validate();
260✔
359
#endif
360

361
    return std::move(this->structured_sdfg_);
260✔
362
};
363

364
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
365
    FunctionBuilder::rename_container(old_name, new_name);
×
366

367
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
368
};
×
369

370
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
13✔
371
    auto& sdfg = this->subject();
13✔
372
    std::list<Element*> queue = {&sdfg.root()};
13✔
373
    while (!queue.empty()) {
55✔
374
        auto current = queue.front();
55✔
375
        queue.pop_front();
55✔
376

377
        if (current->element_id() == element_id) {
55✔
378
            return current;
13✔
379
        }
380

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

413
    return nullptr;
×
414
};
13✔
415

416
Sequence& StructuredSDFGBuilder::
417
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
27✔
418
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
27✔
419

420
    parent.transitions_
54✔
421
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
27✔
422
        );
423

424
    return static_cast<Sequence&>(*parent.children_.back().get());
27✔
425
};
×
426

427
Sequence& StructuredSDFGBuilder::add_sequence_before(
10✔
428
    Sequence& parent,
429
    ControlFlowNode& child,
430
    const sdfg::control_flow::Assignments& assignments,
431
    const DebugInfo& debug_info
432
) {
433
    int index = parent.index(child);
10✔
434
    if (index == -1) {
10✔
435
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
436
    }
437

438
    parent.children_.insert(
20✔
439
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
10✔
440
    );
441

442
    parent.transitions_.insert(
20✔
443
        parent.transitions_.begin() + index,
10✔
444
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
10✔
445
    );
446

447
    return static_cast<Sequence&>(*parent.children_.at(index).get());
10✔
448
};
×
449

450
Sequence& StructuredSDFGBuilder::add_sequence_after(
×
451
    Sequence& parent,
452
    ControlFlowNode& child,
453
    const sdfg::control_flow::Assignments& assignments,
454
    const DebugInfo& debug_info
455
) {
456
    int index = parent.index(child);
×
457
    if (index == -1) {
×
458
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
459
    }
460

461
    parent.children_.insert(
×
462
        parent.children_.begin() + index + 1,
×
463
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
464
    );
465

466
    parent.transitions_.insert(
×
467
        parent.transitions_.begin() + index + 1,
×
468
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
469
    );
470

471
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
472
};
×
473

474
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
475
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
476
    int index = parent.index(child);
×
477
    if (index == -1) {
×
478
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
479
    }
480

481
    parent.children_.insert(
×
482
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
483
    );
484

485
    parent.transitions_.insert(
×
486
        parent.transitions_.begin() + index,
×
487
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
488
    );
489

490
    auto new_entry = parent.at(index);
×
491
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
492

493
    return {new_block, new_entry.second};
×
494
};
×
495

496
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
25✔
497
    parent.children_.erase(parent.children_.begin() + index);
25✔
498
    parent.transitions_.erase(parent.transitions_.begin() + index);
25✔
499
};
25✔
500

501
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
502
    parent.children_.clear();
×
503
    parent.transitions_.clear();
×
504
};
×
505

506
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
10✔
507
    this->move_child(source, source_index, target, target.size());
10✔
508
};
10✔
509

510
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
10✔
511
    auto node_ptr = std::move(source.children_.at(source_index));
10✔
512
    auto trans_ptr = std::move(source.transitions_.at(source_index));
10✔
513
    source.children_.erase(source.children_.begin() + source_index);
10✔
514
    source.transitions_.erase(source.transitions_.begin() + source_index);
10✔
515

516
    trans_ptr->parent_ = &target;
10✔
517
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
10✔
518
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
10✔
519
};
10✔
520

521
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
23✔
522
    this->move_children(source, target, target.size());
23✔
523
};
23✔
524

525
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
23✔
526
    target.children_.insert(
46✔
527
        target.children_.begin() + target_index,
23✔
528
        std::make_move_iterator(source.children_.begin()),
23✔
529
        std::make_move_iterator(source.children_.end())
23✔
530
    );
531
    target.transitions_.insert(
46✔
532
        target.transitions_.begin() + target_index,
23✔
533
        std::make_move_iterator(source.transitions_.begin()),
23✔
534
        std::make_move_iterator(source.transitions_.end())
23✔
535
    );
536
    for (auto& trans : target.transitions_) {
52✔
537
        trans->parent_ = &target;
29✔
538
    }
539
    source.children_.clear();
23✔
540
    source.transitions_.clear();
23✔
541
};
23✔
542

543
Block& StructuredSDFGBuilder::
544
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
504✔
545
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
504✔
546

547
    parent.transitions_
1,008✔
548
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
504✔
549
        );
550

551
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
504✔
552
    (*new_block.dataflow_).parent_ = &new_block;
504✔
553

554
    return new_block;
504✔
555
};
×
556

557
Block& StructuredSDFGBuilder::add_block(
20✔
558
    Sequence& parent,
559
    const data_flow::DataFlowGraph& data_flow_graph,
560
    const sdfg::control_flow::Assignments& assignments,
561
    const DebugInfo& debug_info
562
) {
563
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
20✔
564

565
    parent.transitions_
40✔
566
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
20✔
567
        );
568

569
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
20✔
570
    (*new_block.dataflow_).parent_ = &new_block;
20✔
571

572
    this->add_dataflow(data_flow_graph, new_block);
20✔
573

574
    return new_block;
20✔
575
};
×
576

577
Block& StructuredSDFGBuilder::add_block_before(
11✔
578
    Sequence& parent,
579
    ControlFlowNode& child,
580
    const sdfg::control_flow::Assignments& assignments,
581
    const DebugInfo& debug_info
582
) {
583
    int index = parent.index(child);
11✔
584
    if (index == -1) {
11✔
585
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
586
    }
587

588
    parent.children_
22✔
589
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
11✔
590

591
    parent.transitions_.insert(
22✔
592
        parent.transitions_.begin() + index,
11✔
593
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
11✔
594
    );
595

596
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
11✔
597
    (*new_block.dataflow_).parent_ = &new_block;
11✔
598

599
    return new_block;
11✔
600
};
×
601

602
Block& StructuredSDFGBuilder::add_block_before(
×
603
    Sequence& parent,
604
    ControlFlowNode& child,
605
    data_flow::DataFlowGraph& data_flow_graph,
606
    const sdfg::control_flow::Assignments& assignments,
607
    const DebugInfo& debug_info
608
) {
609
    int index = parent.index(child);
×
610
    if (index == -1) {
×
611
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
612
    }
613

614
    parent.children_
×
615
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
616

617
    parent.transitions_.insert(
×
618
        parent.transitions_.begin() + index,
×
619
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
620
    );
621

622
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
623
    (*new_block.dataflow_).parent_ = &new_block;
×
624
    this->add_dataflow(data_flow_graph, new_block);
×
625

626
    return new_block;
×
627
};
×
628

629
Block& StructuredSDFGBuilder::add_block_after(
3✔
630
    Sequence& parent,
631
    ControlFlowNode& child,
632
    const sdfg::control_flow::Assignments& assignments,
633
    const DebugInfo& debug_info
634
) {
635
    int index = parent.index(child);
3✔
636
    if (index == -1) {
3✔
637
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
638
    }
639

640
    parent.children_.insert(
6✔
641
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3✔
642
    );
643

644
    parent.transitions_.insert(
6✔
645
        parent.transitions_.begin() + index + 1,
3✔
646
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3✔
647
    );
648

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

652
    return new_block;
3✔
653
};
×
654

655
Block& StructuredSDFGBuilder::add_block_after(
×
656
    Sequence& parent,
657
    ControlFlowNode& child,
658
    data_flow::DataFlowGraph& data_flow_graph,
659
    const sdfg::control_flow::Assignments& assignments,
660
    const DebugInfo& debug_info
661
) {
662
    int index = parent.index(child);
×
663
    if (index == -1) {
×
664
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
665
    }
666

667
    parent.children_.insert(
×
668
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
669
    );
670

671
    parent.transitions_.insert(
×
672
        parent.transitions_.begin() + index + 1,
×
673
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
674
    );
675

676
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
677
    (*new_block.dataflow_).parent_ = &new_block;
×
678
    this->add_dataflow(data_flow_graph, new_block);
×
679

680
    return new_block;
×
681
};
×
682

683
std::pair<Block&, Transition&> StructuredSDFGBuilder::
684
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
685
    int index = parent.index(child);
×
686
    if (index == -1) {
×
687
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
688
    }
689

690
    parent.children_
×
691
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
692

693
    parent.transitions_.insert(
×
694
        parent.transitions_.begin() + index,
×
695
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
696
    );
697

698
    auto new_entry = parent.at(index);
×
699
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
700
    (*new_block.dataflow_).parent_ = &new_block;
×
701

702
    return {new_block, new_entry.second};
×
703
};
×
704

705
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
706
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
707
) {
708
    int index = parent.index(child);
×
709
    if (index == -1) {
×
710
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
711
    }
712

713
    parent.children_
×
714
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
715

716
    parent.transitions_.insert(
×
717
        parent.transitions_.begin() + index,
×
718
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
719
    );
720

721
    auto new_entry = parent.at(index);
×
722
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
723
    (*new_block.dataflow_).parent_ = &new_block;
×
724

725
    this->add_dataflow(data_flow_graph, new_block);
×
726

727
    return {new_block, new_entry.second};
×
728
};
×
729

730
std::pair<Block&, Transition&> StructuredSDFGBuilder::
731
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
732
    int index = parent.index(child);
×
733
    if (index == -1) {
×
734
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
735
    }
736

737
    parent.children_.insert(
×
738
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
739
    );
740

741
    parent.transitions_.insert(
×
742
        parent.transitions_.begin() + index + 1,
×
743
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
744
    );
745

746
    auto new_entry = parent.at(index + 1);
×
747
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
748
    (*new_block.dataflow_).parent_ = &new_block;
×
749

750
    return {new_block, new_entry.second};
×
751
};
×
752

753
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
754
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
755
) {
756
    int index = parent.index(child);
×
757
    if (index == -1) {
×
758
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
759
    }
760

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

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

770
    auto new_entry = parent.at(index + 1);
×
771
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
772
    (*new_block.dataflow_).parent_ = &new_block;
×
773

774
    this->add_dataflow(data_flow_graph, new_block);
×
775

776
    return {new_block, new_entry.second};
×
777
};
×
778

779
IfElse& StructuredSDFGBuilder::
780
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
41✔
781
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
41✔
782

783
    parent.transitions_
82✔
784
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
41✔
785
        );
786

787
    return static_cast<IfElse&>(*parent.children_.back().get());
41✔
788
};
×
789

790
IfElse& StructuredSDFGBuilder::add_if_else_before(
1✔
791
    Sequence& parent,
792
    ControlFlowNode& child,
793
    const sdfg::control_flow::Assignments& assignments,
794
    const DebugInfo& debug_info
795
) {
796
    int index = parent.index(child);
1✔
797
    if (index == -1) {
1✔
798
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
799
    }
800

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

804
    parent.transitions_.insert(
2✔
805
        parent.transitions_.begin() + index,
1✔
806
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
1✔
807
    );
808

809
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
810
};
×
811

812
IfElse& StructuredSDFGBuilder::add_if_else_after(
×
813
    Sequence& parent,
814
    ControlFlowNode& child,
815
    const sdfg::control_flow::Assignments& assignments,
816
    const DebugInfo& debug_info
817
) {
818
    int index = parent.index(child);
×
819
    if (index == -1) {
×
820
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
821
    }
822

823
    parent.children_.insert(
×
824
        parent.children_.begin() + index + 1, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info))
×
825
    );
826

827
    parent.transitions_.insert(
×
828
        parent.transitions_.begin() + index + 1,
×
829
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
830
    );
831

832
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
833
};
×
834

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

842
    parent.children_
×
843
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
×
844

845
    parent.transitions_.insert(
×
846
        parent.transitions_.begin() + index,
×
847
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
848
    );
849

850
    auto new_entry = parent.at(index);
×
851
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
852

853
    return {new_block, new_entry.second};
×
854
};
×
855

856
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
66✔
857
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
66✔
858

859
    scope.conditions_.push_back(cond);
66✔
860
    return *scope.cases_.back();
66✔
861
};
×
862

863
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
864
    scope.cases_.erase(scope.cases_.begin() + index);
×
865
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
866
};
×
867

868
While& StructuredSDFGBuilder::
869
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
33✔
870
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
33✔
871

872
    // Increment element id for body node
873
    this->new_element_id();
33✔
874

875
    parent.transitions_
66✔
876
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
33✔
877
        );
878

879
    return static_cast<While&>(*parent.children_.back().get());
33✔
880
};
×
881

882
For& StructuredSDFGBuilder::add_for(
137✔
883
    Sequence& parent,
884
    const symbolic::Symbol indvar,
885
    const symbolic::Condition condition,
886
    const symbolic::Expression init,
887
    const symbolic::Expression update,
888
    const sdfg::control_flow::Assignments& assignments,
889
    const DebugInfo& debug_info
890
) {
891
    parent.children_
274✔
892
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
137✔
893

894
    // Increment element id for body node
895
    this->new_element_id();
137✔
896

897
    parent.transitions_
274✔
898
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
137✔
899
        );
900

901
    return static_cast<For&>(*parent.children_.back().get());
137✔
902
};
×
903

904
For& StructuredSDFGBuilder::add_for_before(
6✔
905
    Sequence& parent,
906
    ControlFlowNode& child,
907
    const symbolic::Symbol indvar,
908
    const symbolic::Condition condition,
909
    const symbolic::Expression init,
910
    const symbolic::Expression update,
911
    const sdfg::control_flow::Assignments& assignments,
912
    const DebugInfo& debug_info
913
) {
914
    int index = parent.index(child);
6✔
915
    if (index == -1) {
6✔
916
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
917
    }
918

919
    parent.children_.insert(
12✔
920
        parent.children_.begin() + index,
6✔
921
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
922
    );
923

924
    // Increment element id for body node
925
    this->new_element_id();
6✔
926

927
    parent.transitions_.insert(
12✔
928
        parent.transitions_.begin() + index,
6✔
929
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
930
    );
931

932
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
933
};
×
934

935
For& StructuredSDFGBuilder::add_for_after(
2✔
936
    Sequence& parent,
937
    ControlFlowNode& child,
938
    const symbolic::Symbol indvar,
939
    const symbolic::Condition condition,
940
    const symbolic::Expression init,
941
    const symbolic::Expression update,
942
    const sdfg::control_flow::Assignments& assignments,
943
    const DebugInfo& debug_info
944
) {
945
    int index = parent.index(child);
2✔
946
    if (index == -1) {
2✔
947
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
948
    }
949

950
    parent.children_.insert(
4✔
951
        parent.children_.begin() + index + 1,
2✔
952
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
2✔
953
    );
954

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

958
    parent.transitions_.insert(
4✔
959
        parent.transitions_.begin() + index + 1,
2✔
960
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2✔
961
    );
962

963
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
964
};
×
965

966
Map& StructuredSDFGBuilder::add_map(
54✔
967
    Sequence& parent,
968
    const symbolic::Symbol indvar,
969
    const symbolic::Condition condition,
970
    const symbolic::Expression init,
971
    const symbolic::Expression update,
972
    const ScheduleType& schedule_type,
973
    const sdfg::control_flow::Assignments& assignments,
974
    const DebugInfo& debug_info
975
) {
976
    parent.children_
108✔
977
        .push_back(std::unique_ptr<
54✔
978
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
54✔
979

980
    // Increment element id for body node
981
    this->new_element_id();
54✔
982

983
    parent.transitions_
108✔
984
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
54✔
985
        );
986

987
    return static_cast<Map&>(*parent.children_.back().get());
54✔
988
};
×
989

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

1006
    parent.children_.insert(
12✔
1007
        parent.children_.begin() + index,
6✔
1008
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
6✔
1009
        )
1010
    );
1011

1012
    // Increment element id for body node
1013
    this->new_element_id();
6✔
1014

1015
    parent.transitions_.insert(
12✔
1016
        parent.transitions_.begin() + index,
6✔
1017
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
1018
    );
1019

1020
    return static_cast<Map&>(*parent.children_.at(index).get());
6✔
1021
};
×
1022

1023
Map& StructuredSDFGBuilder::add_map_after(
12✔
1024
    Sequence& parent,
1025
    ControlFlowNode& child,
1026
    const symbolic::Symbol indvar,
1027
    const symbolic::Condition condition,
1028
    const symbolic::Expression init,
1029
    const symbolic::Expression update,
1030
    const ScheduleType& schedule_type,
1031
    const sdfg::control_flow::Assignments& assignments,
1032
    const DebugInfo& debug_info
1033
) {
1034
    int index = parent.index(child);
12✔
1035
    if (index == -1) {
12✔
1036
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1037
    }
1038

1039
    parent.children_.insert(
24✔
1040
        parent.children_.begin() + index + 1,
12✔
1041
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
12✔
1042
        )
1043
    );
1044

1045
    // Increment element id for body node
1046
    this->new_element_id();
12✔
1047

1048
    parent.transitions_.insert(
24✔
1049
        parent.transitions_.begin() + index + 1,
12✔
1050
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
12✔
1051
    );
1052

1053
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
12✔
1054
};
×
1055

1056
Continue& StructuredSDFGBuilder::
1057
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
14✔
1058
    // Check if continue is in a loop
1059
    analysis::AnalysisManager analysis_manager(this->subject());
14✔
1060
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
14✔
1061
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
14✔
1062
    bool in_loop = false;
14✔
1063
    while (current_scope != nullptr) {
24✔
1064
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
24✔
1065
            in_loop = true;
14✔
1066
            break;
14✔
1067
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
1068
            throw UnstructuredControlFlowException();
×
1069
        }
1070
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
1071
    }
1072
    if (!in_loop) {
14✔
1073
        throw UnstructuredControlFlowException();
×
1074
    }
1075

1076
    parent.children_.push_back(std::unique_ptr<Continue>(new Continue(this->new_element_id(), debug_info)));
14✔
1077

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

1082
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
1083
};
14✔
1084

1085
Break& StructuredSDFGBuilder::
1086
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
15✔
1087
    // Check if break is in a loop
1088
    analysis::AnalysisManager analysis_manager(this->subject());
15✔
1089
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
15✔
1090
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
15✔
1091
    bool in_loop = false;
15✔
1092
    while (current_scope != nullptr) {
25✔
1093
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
25✔
1094
            in_loop = true;
15✔
1095
            break;
15✔
1096
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
1097
            throw UnstructuredControlFlowException();
×
1098
        }
1099
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
1100
    }
1101
    if (!in_loop) {
15✔
1102
        throw UnstructuredControlFlowException();
×
1103
    }
1104

1105
    parent.children_.push_back(std::unique_ptr<Break>(new Break(this->new_element_id(), debug_info)));
15✔
1106

1107
    parent.transitions_
30✔
1108
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
15✔
1109
        );
1110

1111
    return static_cast<Break&>(*parent.children_.back().get());
15✔
1112
};
15✔
1113

1114
Return& StructuredSDFGBuilder::add_return(
16✔
1115
    Sequence& parent,
1116
    const std::string& data,
1117
    const sdfg::control_flow::Assignments& assignments,
1118
    const DebugInfo& debug_info
1119
) {
1120
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
16✔
1121

1122
    parent.transitions_
32✔
1123
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
16✔
1124
        );
1125

1126
    return static_cast<Return&>(*parent.children_.back().get());
16✔
NEW
1127
};
×
1128

1129
Return& StructuredSDFGBuilder::
NEW
1130
    add_unreachable(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
×
NEW
1131
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info)));
×
1132

NEW
1133
    parent.transitions_
×
NEW
1134
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1135
        );
1136

NEW
1137
    return static_cast<Return&>(*parent.children_.back().get());
×
NEW
1138
};
×
1139

NEW
1140
Return& StructuredSDFGBuilder::add_constant_return(
×
1141
    Sequence& parent,
1142
    const std::string& data,
1143
    const types::IType& type,
1144
    const sdfg::control_flow::Assignments& assignments,
1145
    const DebugInfo& debug_info
1146
) {
NEW
1147
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1148

UNCOV
1149
    parent.transitions_
×
UNCOV
1150
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1151
        );
1152

UNCOV
1153
    return static_cast<Return&>(*parent.children_.back().get());
×
1154
};
×
1155

1156
For& StructuredSDFGBuilder::convert_while(
×
1157
    Sequence& parent,
1158
    While& loop,
1159
    const symbolic::Symbol indvar,
1160
    const symbolic::Condition condition,
1161
    const symbolic::Expression init,
1162
    const symbolic::Expression update
1163
) {
1164
    int index = parent.index(loop);
×
1165
    if (index == -1) {
×
1166
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1167
    }
1168

1169
    auto iter = parent.children_.begin() + index;
×
1170
    auto& new_iter = *parent.children_.insert(
×
1171
        iter + 1,
×
1172
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1173
    );
1174

1175
    // Increment element id for body node
1176
    this->new_element_id();
×
1177

1178
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1179
    this->move_children(loop.root(), for_loop.root());
×
1180

1181
    // Remove while loop
1182
    parent.children_.erase(parent.children_.begin() + index);
×
1183

1184
    return for_loop;
×
1185
};
×
1186

1187
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
8✔
1188
    int index = parent.index(loop);
8✔
1189
    if (index == -1) {
8✔
1190
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1191
    }
1192

1193
    auto iter = parent.children_.begin() + index;
8✔
1194
    auto& new_iter = *parent.children_.insert(
16✔
1195
        iter + 1,
8✔
1196
        std::unique_ptr<Map>(new Map(
16✔
1197
            this->new_element_id(),
8✔
1198
            loop.debug_info(),
8✔
1199
            loop.indvar(),
8✔
1200
            loop.init(),
8✔
1201
            loop.update(),
8✔
1202
            loop.condition(),
8✔
1203
            ScheduleType_Sequential::create()
8✔
1204
        ))
1205
    );
1206

1207
    // Increment element id for body node
1208
    this->new_element_id();
8✔
1209

1210
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1211
    this->move_children(loop.root(), map.root());
8✔
1212

1213
    // Remove for loop
1214
    parent.children_.erase(parent.children_.begin() + index);
8✔
1215

1216
    return map;
8✔
1217
};
×
1218

1219
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1220
    if (index >= if_else.conditions_.size()) {
×
1221
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1222
    }
1223
    if_else.conditions_.at(index) = condition;
×
1224
};
×
1225

1226
void StructuredSDFGBuilder::update_loop(
16✔
1227
    StructuredLoop& loop,
1228
    const symbolic::Symbol indvar,
1229
    const symbolic::Condition condition,
1230
    const symbolic::Expression init,
1231
    const symbolic::Expression update
1232
) {
1233
    loop.indvar_ = indvar;
16✔
1234
    loop.condition_ = condition;
16✔
1235
    loop.init_ = init;
16✔
1236
    loop.update_ = update;
16✔
1237
};
16✔
1238

1239
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1240
    map.schedule_type_ = schedule_type;
4✔
1241
}
4✔
1242

1243
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1244
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1245
    while (!queue.empty()) {
2✔
1246
        auto current = queue.front();
2✔
1247
        queue.pop_front();
2✔
1248

1249
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1250
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1251
                if (&sequence_stmt->at(i).first == &node) {
2✔
1252
                    return *sequence_stmt;
2✔
1253
                }
1254
                queue.push_back(&sequence_stmt->at(i).first);
×
1255
            }
×
1256
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1257
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1258
                queue.push_back(&if_else_stmt->at(i).first);
×
1259
            }
×
1260
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1261
            queue.push_back(&while_stmt->root());
×
1262
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1263
            queue.push_back(&loop_stmt->root());
×
1264
        }
×
1265
    }
1266

1267
    return this->structured_sdfg_->root();
×
1268
};
2✔
1269

1270
/***** Section: Dataflow Graph *****/
1271

1272
data_flow::AccessNode& StructuredSDFGBuilder::
1273
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
605✔
1274
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
605✔
1275
    auto res = block.dataflow_->nodes_.insert(
1,210✔
1276
        {vertex,
605✔
1277
         std::unique_ptr<data_flow::AccessNode>(
605✔
1278
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
605✔
1279
         )}
1280
    );
1281

1282
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
605✔
1283
};
×
1284

1285
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
52✔
1286
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1287
) {
1288
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
52✔
1289
    auto res = block.dataflow_->nodes_.insert(
104✔
1290
        {vertex,
52✔
1291
         std::unique_ptr<data_flow::ConstantNode>(
52✔
1292
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
52✔
1293
         )}
1294
    );
1295

1296
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
52✔
1297
};
×
1298

1299

1300
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
360✔
1301
    structured_control_flow::Block& block,
1302
    const data_flow::TaskletCode code,
1303
    const std::string& output,
1304
    const std::vector<std::string>& inputs,
1305
    const DebugInfo& debug_info
1306
) {
1307
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
360✔
1308
    auto res = block.dataflow_->nodes_.insert(
720✔
1309
        {vertex,
360✔
1310
         std::unique_ptr<data_flow::Tasklet>(
360✔
1311
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
360✔
1312
         )}
1313
    );
1314

1315
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
360✔
1316
};
×
1317

1318
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
652✔
1319
    structured_control_flow::Block& block,
1320
    data_flow::DataFlowNode& src,
1321
    const std::string& src_conn,
1322
    data_flow::DataFlowNode& dst,
1323
    const std::string& dst_conn,
1324
    const data_flow::Subset& subset,
1325
    const types::IType& base_type,
1326
    const DebugInfo& debug_info
1327
) {
1328
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
652✔
1329
    auto res = block.dataflow_->edges_.insert(
1,304✔
1330
        {edge.first,
1,304✔
1331
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,304✔
1332
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
652✔
1333
         ))}
1334
    );
1335

1336
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
652✔
1337
#ifndef NDEBUG
1338
    memlet.validate(*this->structured_sdfg_);
652✔
1339
#endif
1340

1341
    return memlet;
652✔
1342
};
×
1343

1344
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
101✔
1345
    structured_control_flow::Block& block,
1346
    data_flow::AccessNode& src,
1347
    data_flow::Tasklet& dst,
1348
    const std::string& dst_conn,
1349
    const data_flow::Subset& subset,
1350
    const types::IType& base_type,
1351
    const DebugInfo& debug_info
1352
) {
1353
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
101✔
1354
};
×
1355

1356
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
87✔
1357
    structured_control_flow::Block& block,
1358
    data_flow::Tasklet& src,
1359
    const std::string& src_conn,
1360
    data_flow::AccessNode& dst,
1361
    const data_flow::Subset& subset,
1362
    const types::IType& base_type,
1363
    const DebugInfo& debug_info
1364
) {
1365
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
87✔
1366
};
×
1367

1368
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
131✔
1369
    structured_control_flow::Block& block,
1370
    data_flow::AccessNode& src,
1371
    data_flow::Tasklet& dst,
1372
    const std::string& dst_conn,
1373
    const data_flow::Subset& subset,
1374
    const DebugInfo& debug_info
1375
) {
1376
    const types::IType* src_type = nullptr;
131✔
1377
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
131✔
1378
        src_type = &cnode->type();
40✔
1379
    } else {
40✔
1380
        src_type = &this->structured_sdfg_->type(src.data());
91✔
1381
    }
1382
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
131✔
1383
    if (base_type.type_id() != types::TypeID::Scalar) {
131✔
1384
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1385
    }
1386
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
131✔
1387
};
×
1388

1389
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
267✔
1390
    structured_control_flow::Block& block,
1391
    data_flow::Tasklet& src,
1392
    const std::string& src_conn,
1393
    data_flow::AccessNode& dst,
1394
    const data_flow::Subset& subset,
1395
    const DebugInfo& debug_info
1396
) {
1397
    auto& dst_type = this->structured_sdfg_->type(dst.data());
267✔
1398
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
267✔
1399
    if (base_type.type_id() != types::TypeID::Scalar) {
267✔
1400
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1401
    }
1402
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
267✔
1403
};
×
1404

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

1417
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
9✔
1418
    structured_control_flow::Block& block,
1419
    data_flow::LibraryNode& src,
1420
    const std::string& src_conn,
1421
    data_flow::AccessNode& dst,
1422
    const data_flow::Subset& subset,
1423
    const types::IType& base_type,
1424
    const DebugInfo& debug_info
1425
) {
1426
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
9✔
1427
};
×
1428

1429
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
8✔
1430
    structured_control_flow::Block& block,
1431
    data_flow::AccessNode& src,
1432
    data_flow::AccessNode& dst,
1433
    const data_flow::Subset& subset,
1434
    const types::IType& base_type,
1435
    const DebugInfo& debug_info
1436
) {
1437
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
8✔
1438
};
×
1439

1440
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
11✔
1441
    structured_control_flow::Block& block,
1442
    data_flow::AccessNode& src,
1443
    data_flow::AccessNode& dst,
1444
    bool derefs_src,
1445
    const types::IType& base_type,
1446
    const DebugInfo& debug_info
1447
) {
1448
    if (derefs_src) {
11✔
1449
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
6✔
1450
    } else {
1451
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
5✔
1452
    }
1453
};
11✔
1454

1455
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
21✔
1456
    auto& graph = block.dataflow();
21✔
1457
    auto e = edge.edge();
21✔
1458
    boost::remove_edge(e, graph.graph_);
21✔
1459
    graph.edges_.erase(e);
21✔
1460
};
21✔
1461

1462
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
20✔
1463
    auto& graph = block.dataflow();
20✔
1464
    auto v = node.vertex();
20✔
1465
    boost::remove_vertex(v, graph.graph_);
20✔
1466
    graph.nodes_.erase(v);
20✔
1467
};
20✔
1468

1469
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
9✔
1470
    auto& graph = block.dataflow();
9✔
1471

1472
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
9✔
1473

1474
    // Delete incoming
1475
    std::list<const data_flow::Memlet*> iedges;
9✔
1476
    for (auto& iedge : graph.in_edges(node)) {
24✔
1477
        iedges.push_back(&iedge);
15✔
1478
    }
1479
    for (auto iedge : iedges) {
24✔
1480
        auto& src = iedge->src();
15✔
1481
        to_delete.insert(&src);
15✔
1482

1483
        auto edge = iedge->edge();
15✔
1484
        graph.edges_.erase(edge);
15✔
1485
        boost::remove_edge(edge, graph.graph_);
15✔
1486
    }
1487

1488
    // Delete outgoing
1489
    std::list<const data_flow::Memlet*> oedges;
9✔
1490
    for (auto& oedge : graph.out_edges(node)) {
18✔
1491
        oedges.push_back(&oedge);
9✔
1492
    }
1493
    for (auto oedge : oedges) {
18✔
1494
        auto& dst = oedge->dst();
9✔
1495
        to_delete.insert(&dst);
9✔
1496

1497
        auto edge = oedge->edge();
9✔
1498
        graph.edges_.erase(edge);
9✔
1499
        boost::remove_edge(edge, graph.graph_);
9✔
1500
    }
1501

1502
    // Delete nodes
1503
    for (auto obsolete_node : to_delete) {
42✔
1504
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
33✔
1505
            auto vertex = obsolete_node->vertex();
33✔
1506
            graph.nodes_.erase(vertex);
33✔
1507
            boost::remove_vertex(vertex, graph.graph_);
33✔
1508
        }
33✔
1509
    }
1510
};
9✔
1511

1512
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
×
1513
    auto& graph = block.dataflow();
×
1514
    if (graph.out_degree(node) != 0) {
×
1515
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1516
    }
1517

1518
    std::list<const data_flow::Memlet*> tmp;
×
1519
    std::list<const data_flow::DataFlowNode*> queue = {&node};
×
1520
    while (!queue.empty()) {
×
1521
        auto current = queue.front();
×
1522
        queue.pop_front();
×
1523
        if (current != &node) {
×
1524
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
×
1525
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1526
                    continue;
×
1527
                }
1528
            }
×
1529
        }
×
1530

1531
        tmp.clear();
×
1532
        for (auto& iedge : graph.in_edges(*current)) {
×
1533
            tmp.push_back(&iedge);
×
1534
        }
1535
        for (auto iedge : tmp) {
×
1536
            auto& src = iedge->src();
×
1537
            queue.push_back(&src);
×
1538

1539
            auto edge = iedge->edge();
×
1540
            graph.edges_.erase(edge);
×
1541
            boost::remove_edge(edge, graph.graph_);
×
1542
        }
1543

1544
        auto vertex = current->vertex();
×
1545
        graph.nodes_.erase(vertex);
×
1546
        boost::remove_vertex(vertex, graph.graph_);
×
1547
    }
1548
};
×
1549

1550
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
20✔
1551
    auto& to_dataflow = to.dataflow();
20✔
1552

1553
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
20✔
1554
    for (auto& entry : from.nodes_) {
21✔
1555
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1556
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1557
        node_mapping.insert({entry.first, vertex});
1✔
1558
    }
1559

1560
    for (auto& entry : from.edges_) {
20✔
1561
        auto src = node_mapping[entry.second->src().vertex()];
×
1562
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1563

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

1566
        to_dataflow.edges_.insert(
×
1567
            {edge.first,
×
1568
             entry.second->clone(
×
1569
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1570
             )}
1571
        );
1572
    }
1573
};
20✔
1574

1575
} // namespace builder
1576
} // 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