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

daisytuner / sdfglib / 17979947011

24 Sep 2025 02:28PM UTC coverage: 61.235% (-0.03%) from 61.26%
17979947011

Pull #245

github

web-flow
Merge 1406be24f into 96cc2db74
Pull Request #245: Lib node offloading

2 of 8 new or added lines in 3 files covered. (25.0%)

1 existing line in 1 file now uncovered.

9560 of 15612 relevant lines covered (61.23%)

111.42 hits per line

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

64.85
/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✔
215
                this->add_unreachable(scope, {}, return_state->debug_info());
×
216
            } else if (return_state->is_constant()) {
×
217
                this->add_constant_return(
×
218
                    scope, return_state->data(), return_state->type(), {}, return_state->debug_info()
×
219
                );
220
            } else {
×
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_); };
6,266✔
314

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

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

321
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
7✔
322
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type, return_type)) {};
7✔
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
    for (auto& func : sdfg.offloaded_functions_) {
4✔
UNCOV
352
        this->structured_sdfg_->offloaded_functions_.insert(func);
×
353
    }
354

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

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

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

365
    return std::move(this->structured_sdfg_);
266✔
366
};
367

368
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
369
    FunctionBuilder::rename_container(old_name, new_name);
×
370

371
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
372
};
×
373

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

381
        if (current->element_id() == element_id) {
55✔
382
            return current;
13✔
383
        }
384

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

417
    return nullptr;
×
418
};
13✔
419

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

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

428
    return static_cast<Sequence&>(*parent.children_.back().get());
28✔
429
};
×
430

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

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

446
    parent.transitions_.insert(
20✔
447
        parent.transitions_.begin() + index,
10✔
448
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
10✔
449
    );
450

451
    return static_cast<Sequence&>(*parent.children_.at(index).get());
10✔
452
};
×
453

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

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

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

475
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
476
};
×
477

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

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

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

494
    auto new_entry = parent.at(index);
×
495
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
496

497
    return {new_block, new_entry.second};
×
498
};
×
499

500
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
28✔
501
    parent.children_.erase(parent.children_.begin() + index);
28✔
502
    parent.transitions_.erase(parent.transitions_.begin() + index);
28✔
503
};
28✔
504

505
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
506
    parent.children_.clear();
×
507
    parent.transitions_.clear();
×
508
};
×
509

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

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

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

525
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
23✔
526
    this->move_children(source, target, target.size());
23✔
527
};
23✔
528

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

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

551
    parent.transitions_
1,054✔
552
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
527✔
553
        );
554

555
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
527✔
556
    (*new_block.dataflow_).parent_ = &new_block;
527✔
557

558
    return new_block;
527✔
559
};
×
560

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

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

573
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
20✔
574
    (*new_block.dataflow_).parent_ = &new_block;
20✔
575

576
    this->add_dataflow(data_flow_graph, new_block);
20✔
577

578
    return new_block;
20✔
579
};
×
580

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

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

595
    parent.transitions_.insert(
22✔
596
        parent.transitions_.begin() + index,
11✔
597
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
11✔
598
    );
599

600
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
11✔
601
    (*new_block.dataflow_).parent_ = &new_block;
11✔
602

603
    return new_block;
11✔
604
};
×
605

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

618
    parent.children_
×
619
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
620

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

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

630
    return new_block;
×
631
};
×
632

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

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

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

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

656
    return new_block;
3✔
657
};
×
658

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

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

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

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

684
    return new_block;
×
685
};
×
686

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

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

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

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

706
    return {new_block, new_entry.second};
×
707
};
×
708

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

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

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

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

729
    this->add_dataflow(data_flow_graph, new_block);
×
730

731
    return {new_block, new_entry.second};
×
732
};
×
733

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

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

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

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

754
    return {new_block, new_entry.second};
×
755
};
×
756

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

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

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

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

778
    this->add_dataflow(data_flow_graph, new_block);
×
779

780
    return {new_block, new_entry.second};
×
781
};
×
782

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

787
    parent.transitions_
82✔
788
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
41✔
789
        );
790

791
    return static_cast<IfElse&>(*parent.children_.back().get());
41✔
792
};
×
793

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

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

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

813
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
814
};
×
815

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

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

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

836
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
837
};
×
838

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

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

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

854
    auto new_entry = parent.at(index);
×
855
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
856

857
    return {new_block, new_entry.second};
×
858
};
×
859

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

863
    scope.conditions_.push_back(cond);
66✔
864
    return *scope.cases_.back();
66✔
865
};
×
866

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

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

876
    // Increment element id for body node
877
    this->new_element_id();
33✔
878

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

883
    return static_cast<While&>(*parent.children_.back().get());
33✔
884
};
×
885

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

898
    // Increment element id for body node
899
    this->new_element_id();
161✔
900

901
    parent.transitions_
322✔
902
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
161✔
903
        );
904

905
    return static_cast<For&>(*parent.children_.back().get());
161✔
906
};
×
907

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

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

928
    // Increment element id for body node
929
    this->new_element_id();
6✔
930

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

936
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
937
};
×
938

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

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

959
    // Increment element id for body node
960
    this->new_element_id();
2✔
961

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

967
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
968
};
×
969

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

984
    // Increment element id for body node
985
    this->new_element_id();
57✔
986

987
    parent.transitions_
114✔
988
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
57✔
989
        );
990

991
    return static_cast<Map&>(*parent.children_.back().get());
57✔
992
};
×
993

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

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

1016
    // Increment element id for body node
1017
    this->new_element_id();
6✔
1018

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

1024
    return static_cast<Map&>(*parent.children_.at(index).get());
6✔
1025
};
×
1026

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

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

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

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

1057
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
12✔
1058
};
×
1059

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

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

1082
    parent.transitions_
28✔
1083
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
1084
        );
1085

1086
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
1087
};
14✔
1088

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

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

1111
    parent.transitions_
30✔
1112
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
15✔
1113
        );
1114

1115
    return static_cast<Break&>(*parent.children_.back().get());
15✔
1116
};
15✔
1117

1118
Return& StructuredSDFGBuilder::add_return(
19✔
1119
    Sequence& parent,
1120
    const std::string& data,
1121
    const sdfg::control_flow::Assignments& assignments,
1122
    const DebugInfo& debug_info
1123
) {
1124
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
19✔
1125

1126
    parent.transitions_
38✔
1127
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
19✔
1128
        );
1129

1130
    return static_cast<Return&>(*parent.children_.back().get());
19✔
1131
};
×
1132

1133
Return& StructuredSDFGBuilder::
1134
    add_unreachable(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
×
1135
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info)));
×
1136

1137
    parent.transitions_
×
1138
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1139
        );
1140

1141
    return static_cast<Return&>(*parent.children_.back().get());
×
1142
};
×
1143

1144
Return& StructuredSDFGBuilder::add_constant_return(
1✔
1145
    Sequence& parent,
1146
    const std::string& data,
1147
    const types::IType& type,
1148
    const sdfg::control_flow::Assignments& assignments,
1149
    const DebugInfo& debug_info
1150
) {
1151
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
1✔
1152

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

1157
    return static_cast<Return&>(*parent.children_.back().get());
1✔
1158
};
×
1159

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

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

1179
    // Increment element id for body node
1180
    this->new_element_id();
×
1181

1182
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1183
    this->move_children(loop.root(), for_loop.root());
×
1184

1185
    // Remove while loop
1186
    parent.children_.erase(parent.children_.begin() + index);
×
1187

1188
    return for_loop;
×
1189
};
×
1190

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

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

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

1214
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1215
    this->move_children(loop.root(), map.root());
8✔
1216

1217
    // Remove for loop
1218
    parent.children_.erase(parent.children_.begin() + index);
8✔
1219

1220
    return map;
8✔
1221
};
×
1222

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

1230
void StructuredSDFGBuilder::update_loop(
18✔
1231
    StructuredLoop& loop,
1232
    const symbolic::Symbol indvar,
1233
    const symbolic::Condition condition,
1234
    const symbolic::Expression init,
1235
    const symbolic::Expression update
1236
) {
1237
    loop.indvar_ = indvar;
18✔
1238
    loop.condition_ = condition;
18✔
1239
    loop.init_ = init;
18✔
1240
    loop.update_ = update;
18✔
1241
};
18✔
1242

1243
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1244
    map.schedule_type_ = schedule_type;
4✔
1245
}
4✔
1246

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

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

1271
    return this->structured_sdfg_->root();
×
1272
};
2✔
1273

1274
/***** Section: Dataflow Graph *****/
1275

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

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

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

1300
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
54✔
1301
};
×
1302

1303

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

1319
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
385✔
1320
};
×
1321

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

1340
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
729✔
1341
#ifndef NDEBUG
1342
    memlet.validate(*this->structured_sdfg_);
729✔
1343
#endif
1344

1345
    return memlet;
729✔
1346
};
×
1347

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

1360
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
91✔
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 types::IType& base_type,
1367
    const DebugInfo& debug_info
1368
) {
1369
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
91✔
1370
};
×
1371

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

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

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

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

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

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

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

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

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

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

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

1487
        auto edge = iedge->edge();
15✔
1488
        graph.edges_.erase(edge);
15✔
1489
        boost::remove_edge(edge, graph.graph_);
15✔
1490
    }
1491

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

1501
        auto edge = oedge->edge();
9✔
1502
        graph.edges_.erase(edge);
9✔
1503
        boost::remove_edge(edge, graph.graph_);
9✔
1504
    }
1505

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

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

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

1535
        tmp.clear();
×
1536
        for (auto& iedge : graph.in_edges(*current)) {
×
1537
            tmp.push_back(&iedge);
×
1538
        }
1539
        for (auto iedge : tmp) {
×
1540
            auto& src = iedge->src();
×
1541
            queue.push_back(&src);
×
1542

1543
            auto edge = iedge->edge();
×
1544
            graph.edges_.erase(edge);
×
1545
            boost::remove_edge(edge, graph.graph_);
×
1546
        }
1547

1548
        auto vertex = current->vertex();
×
1549
        graph.nodes_.erase(vertex);
×
1550
        boost::remove_vertex(vertex, graph.graph_);
×
1551
    }
1552
};
×
1553

1554
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
20✔
1555
    auto& to_dataflow = to.dataflow();
20✔
1556

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

1564
    for (auto& entry : from.edges_) {
20✔
1565
        auto src = node_mapping[entry.second->src().vertex()];
×
1566
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1567

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

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

1579
} // namespace builder
1580
} // 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