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

daisytuner / sdfglib / 18558780296

16 Oct 2025 10:49AM UTC coverage: 61.233% (-0.3%) from 61.523%
18558780296

push

github

web-flow
Merge pull request #279 from daisytuner/ext-prefix

Separate Dominance Analysis and Codegen for Linker with Prefixes

62 of 95 new or added lines in 26 files covered. (65.26%)

13 existing lines in 7 files now uncovered.

8981 of 14667 relevant lines covered (61.23%)

98.73 hits per line

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

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

3
#include <cstddef>
4

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

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

15
namespace sdfg {
16
namespace builder {
17

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

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

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

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

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

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

61
    return false;
×
62
}
6✔
63

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

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

82
    return pdom;
3✔
83
}
3✔
84

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

223
            continue;
4✔
224
        }
225

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

353
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
950✔
354

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

360
    return std::move(this->structured_sdfg_);
267✔
361
};
362

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

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

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

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

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

412
    return nullptr;
×
413
};
13✔
414

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

546
    parent.transitions_
740✔
547
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
370✔
548
        );
549

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

553
    return new_block;
370✔
554
};
×
555

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

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

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

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

573
    return new_block;
20✔
574
};
×
575

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

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

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

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

598
    return new_block;
11✔
599
};
×
600

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

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

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

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

625
    return new_block;
×
626
};
×
627

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

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

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

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

651
    return new_block;
3✔
652
};
×
653

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

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

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

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

679
    return new_block;
×
680
};
×
681

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1059
    parent.transitions_
28✔
1060
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
1061
        );
1062

1063
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
UNCOV
1064
};
×
1065

1066
Break& StructuredSDFGBuilder::
1067
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
15✔
1068
    parent.children_.push_back(std::unique_ptr<Break>(new Break(this->new_element_id(), debug_info)));
15✔
1069

1070
    parent.transitions_
30✔
1071
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
15✔
1072
        );
1073

1074
    return static_cast<Break&>(*parent.children_.back().get());
15✔
UNCOV
1075
};
×
1076

1077
Return& StructuredSDFGBuilder::add_return(
19✔
1078
    Sequence& parent,
1079
    const std::string& data,
1080
    const sdfg::control_flow::Assignments& assignments,
1081
    const DebugInfo& debug_info
1082
) {
1083
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
19✔
1084

1085
    parent.transitions_
38✔
1086
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
19✔
1087
        );
1088

1089
    return static_cast<Return&>(*parent.children_.back().get());
19✔
1090
};
×
1091

1092
Return& StructuredSDFGBuilder::
1093
    add_unreachable(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
×
1094
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info)));
×
1095

1096
    parent.transitions_
×
1097
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1098
        );
1099

1100
    return static_cast<Return&>(*parent.children_.back().get());
×
1101
};
×
1102

1103
Return& StructuredSDFGBuilder::add_constant_return(
1✔
1104
    Sequence& parent,
1105
    const std::string& data,
1106
    const types::IType& type,
1107
    const sdfg::control_flow::Assignments& assignments,
1108
    const DebugInfo& debug_info
1109
) {
1110
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
1✔
1111

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

1116
    return static_cast<Return&>(*parent.children_.back().get());
1✔
1117
};
×
1118

1119
For& StructuredSDFGBuilder::convert_while(
×
1120
    Sequence& parent,
1121
    While& loop,
1122
    const symbolic::Symbol indvar,
1123
    const symbolic::Condition condition,
1124
    const symbolic::Expression init,
1125
    const symbolic::Expression update
1126
) {
1127
    int index = parent.index(loop);
×
1128
    if (index == -1) {
×
1129
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1130
    }
1131

1132
    auto iter = parent.children_.begin() + index;
×
1133
    auto& new_iter = *parent.children_.insert(
×
1134
        iter + 1,
×
1135
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1136
    );
1137

1138
    // Increment element id for body node
1139
    this->new_element_id();
×
1140

1141
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1142
    this->move_children(loop.root(), for_loop.root());
×
1143

1144
    // Remove while loop
1145
    parent.children_.erase(parent.children_.begin() + index);
×
1146

1147
    return for_loop;
×
1148
};
×
1149

1150
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
8✔
1151
    int index = parent.index(loop);
8✔
1152
    if (index == -1) {
8✔
1153
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1154
    }
1155

1156
    auto iter = parent.children_.begin() + index;
8✔
1157
    auto& new_iter = *parent.children_.insert(
16✔
1158
        iter + 1,
8✔
1159
        std::unique_ptr<Map>(new Map(
16✔
1160
            this->new_element_id(),
8✔
1161
            loop.debug_info(),
8✔
1162
            loop.indvar(),
8✔
1163
            loop.init(),
8✔
1164
            loop.update(),
8✔
1165
            loop.condition(),
8✔
1166
            ScheduleType_Sequential::create()
8✔
1167
        ))
1168
    );
1169

1170
    // Increment element id for body node
1171
    this->new_element_id();
8✔
1172

1173
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1174
    this->move_children(loop.root(), map.root());
8✔
1175

1176
    // Remove for loop
1177
    parent.children_.erase(parent.children_.begin() + index);
8✔
1178

1179
    return map;
8✔
1180
};
×
1181

1182
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1183
    if (index >= if_else.conditions_.size()) {
×
1184
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1185
    }
1186
    if_else.conditions_.at(index) = condition;
×
1187
};
×
1188

1189
void StructuredSDFGBuilder::update_loop(
18✔
1190
    StructuredLoop& loop,
1191
    const symbolic::Symbol indvar,
1192
    const symbolic::Condition condition,
1193
    const symbolic::Expression init,
1194
    const symbolic::Expression update
1195
) {
1196
    loop.indvar_ = indvar;
18✔
1197
    loop.condition_ = condition;
18✔
1198
    loop.init_ = init;
18✔
1199
    loop.update_ = update;
18✔
1200
};
18✔
1201

1202
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1203
    map.schedule_type_ = schedule_type;
4✔
1204
}
4✔
1205

1206
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1207
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1208
    while (!queue.empty()) {
2✔
1209
        auto current = queue.front();
2✔
1210
        queue.pop_front();
2✔
1211

1212
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1213
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1214
                if (&sequence_stmt->at(i).first == &node) {
2✔
1215
                    return *sequence_stmt;
2✔
1216
                }
1217
                queue.push_back(&sequence_stmt->at(i).first);
×
1218
            }
×
1219
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1220
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1221
                queue.push_back(&if_else_stmt->at(i).first);
×
1222
            }
×
1223
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1224
            queue.push_back(&while_stmt->root());
×
1225
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1226
            queue.push_back(&loop_stmt->root());
×
1227
        }
×
1228
    }
1229

1230
    return this->structured_sdfg_->root();
×
1231
};
2✔
1232

1233
/***** Section: Dataflow Graph *****/
1234

1235
data_flow::AccessNode& StructuredSDFGBuilder::
1236
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
498✔
1237
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
498✔
1238
    auto res = block.dataflow_->nodes_.insert(
996✔
1239
        {vertex,
498✔
1240
         std::unique_ptr<data_flow::AccessNode>(
498✔
1241
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
498✔
1242
         )}
1243
    );
1244

1245
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
498✔
1246
};
×
1247

1248
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
68✔
1249
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1250
) {
1251
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
68✔
1252
    auto res = block.dataflow_->nodes_.insert(
136✔
1253
        {vertex,
68✔
1254
         std::unique_ptr<data_flow::ConstantNode>(
68✔
1255
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
68✔
1256
         )}
1257
    );
1258

1259
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
68✔
1260
};
×
1261

1262

1263
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
221✔
1264
    structured_control_flow::Block& block,
1265
    const data_flow::TaskletCode code,
1266
    const std::string& output,
1267
    const std::vector<std::string>& inputs,
1268
    const DebugInfo& debug_info
1269
) {
1270
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
221✔
1271
    auto res = block.dataflow_->nodes_.insert(
442✔
1272
        {vertex,
221✔
1273
         std::unique_ptr<data_flow::Tasklet>(
221✔
1274
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
221✔
1275
         )}
1276
    );
1277

1278
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
221✔
1279
};
×
1280

1281
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
557✔
1282
    structured_control_flow::Block& block,
1283
    data_flow::DataFlowNode& src,
1284
    const std::string& src_conn,
1285
    data_flow::DataFlowNode& dst,
1286
    const std::string& dst_conn,
1287
    const data_flow::Subset& subset,
1288
    const types::IType& base_type,
1289
    const DebugInfo& debug_info
1290
) {
1291
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
557✔
1292
    auto res = block.dataflow_->edges_.insert(
1,114✔
1293
        {edge.first,
1,114✔
1294
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,114✔
1295
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
557✔
1296
         ))}
1297
    );
1298

1299
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
557✔
1300
#ifndef NDEBUG
1301
    memlet.validate(*this->structured_sdfg_);
557✔
1302
#endif
1303

1304
    return memlet;
557✔
1305
};
×
1306

1307
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
89✔
1308
    structured_control_flow::Block& block,
1309
    data_flow::AccessNode& src,
1310
    data_flow::Tasklet& dst,
1311
    const std::string& dst_conn,
1312
    const data_flow::Subset& subset,
1313
    const types::IType& base_type,
1314
    const DebugInfo& debug_info
1315
) {
1316
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
89✔
1317
};
×
1318

1319
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
84✔
1320
    structured_control_flow::Block& block,
1321
    data_flow::Tasklet& src,
1322
    const std::string& src_conn,
1323
    data_flow::AccessNode& dst,
1324
    const data_flow::Subset& subset,
1325
    const types::IType& base_type,
1326
    const DebugInfo& debug_info
1327
) {
1328
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
84✔
1329
};
×
1330

1331
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
156✔
1332
    structured_control_flow::Block& block,
1333
    data_flow::AccessNode& src,
1334
    data_flow::Tasklet& dst,
1335
    const std::string& dst_conn,
1336
    const data_flow::Subset& subset,
1337
    const DebugInfo& debug_info
1338
) {
1339
    const types::IType* src_type = nullptr;
156✔
1340
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
156✔
1341
        src_type = &cnode->type();
58✔
1342
    } else {
58✔
1343
        src_type = &this->structured_sdfg_->type(src.data());
98✔
1344
    }
1345
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
156✔
1346
    if (base_type.type_id() != types::TypeID::Scalar) {
156✔
1347
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1348
    }
1349
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
156✔
1350
};
×
1351

1352
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
115✔
1353
    structured_control_flow::Block& block,
1354
    data_flow::Tasklet& src,
1355
    const std::string& src_conn,
1356
    data_flow::AccessNode& dst,
1357
    const data_flow::Subset& subset,
1358
    const DebugInfo& debug_info
1359
) {
1360
    auto& dst_type = this->structured_sdfg_->type(dst.data());
115✔
1361
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
115✔
1362
    if (base_type.type_id() != types::TypeID::Scalar) {
115✔
1363
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1364
    }
1365
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
115✔
1366
};
×
1367

1368
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
9✔
1369
    structured_control_flow::Block& block,
1370
    data_flow::AccessNode& src,
1371
    data_flow::LibraryNode& dst,
1372
    const std::string& dst_conn,
1373
    const data_flow::Subset& subset,
1374
    const types::IType& base_type,
1375
    const DebugInfo& debug_info
1376
) {
1377
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
9✔
1378
};
×
1379

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

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

1403
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
12✔
1404
    structured_control_flow::Block& block,
1405
    data_flow::AccessNode& src,
1406
    data_flow::AccessNode& dst,
1407
    bool derefs_src,
1408
    const types::IType& base_type,
1409
    const DebugInfo& debug_info
1410
) {
1411
    if (derefs_src) {
12✔
1412
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
6✔
1413
    } else {
1414
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
6✔
1415
    }
1416
};
12✔
1417

1418
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
9✔
1419
    auto& graph = block.dataflow();
9✔
1420
    auto e = edge.edge();
9✔
1421
    boost::remove_edge(e, graph.graph_);
9✔
1422
    graph.edges_.erase(e);
9✔
1423
};
9✔
1424

1425
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
11✔
1426
    auto& graph = block.dataflow();
11✔
1427
    auto v = node.vertex();
11✔
1428
    boost::remove_vertex(v, graph.graph_);
11✔
1429
    graph.nodes_.erase(v);
11✔
1430
};
11✔
1431

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

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

1437
    // Delete incoming
1438
    std::list<const data_flow::Memlet*> iedges;
9✔
1439
    for (auto& iedge : graph.in_edges(node)) {
24✔
1440
        iedges.push_back(&iedge);
15✔
1441
    }
1442
    for (auto iedge : iedges) {
24✔
1443
        auto& src = iedge->src();
15✔
1444
        to_delete.insert(&src);
15✔
1445

1446
        auto edge = iedge->edge();
15✔
1447
        graph.edges_.erase(edge);
15✔
1448
        boost::remove_edge(edge, graph.graph_);
15✔
1449
    }
1450

1451
    // Delete outgoing
1452
    std::list<const data_flow::Memlet*> oedges;
9✔
1453
    for (auto& oedge : graph.out_edges(node)) {
18✔
1454
        oedges.push_back(&oedge);
9✔
1455
    }
1456
    for (auto oedge : oedges) {
18✔
1457
        auto& dst = oedge->dst();
9✔
1458
        to_delete.insert(&dst);
9✔
1459

1460
        auto edge = oedge->edge();
9✔
1461
        graph.edges_.erase(edge);
9✔
1462
        boost::remove_edge(edge, graph.graph_);
9✔
1463
    }
1464

1465
    // Delete nodes
1466
    for (auto obsolete_node : to_delete) {
42✔
1467
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
33✔
1468
            auto vertex = obsolete_node->vertex();
33✔
1469
            graph.nodes_.erase(vertex);
33✔
1470
            boost::remove_vertex(vertex, graph.graph_);
33✔
1471
        }
33✔
1472
    }
1473
};
9✔
1474

1475
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
×
1476
    auto& graph = block.dataflow();
×
1477
    if (graph.out_degree(node) != 0) {
×
1478
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1479
    }
1480

1481
    std::list<const data_flow::Memlet*> tmp;
×
1482
    std::list<const data_flow::DataFlowNode*> queue = {&node};
×
1483
    while (!queue.empty()) {
×
1484
        auto current = queue.front();
×
1485
        queue.pop_front();
×
1486
        if (current != &node) {
×
1487
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
×
1488
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1489
                    continue;
×
1490
                }
1491
            }
×
1492
        }
×
1493

1494
        tmp.clear();
×
1495
        for (auto& iedge : graph.in_edges(*current)) {
×
1496
            tmp.push_back(&iedge);
×
1497
        }
1498
        for (auto iedge : tmp) {
×
1499
            auto& src = iedge->src();
×
1500
            queue.push_back(&src);
×
1501

1502
            auto edge = iedge->edge();
×
1503
            graph.edges_.erase(edge);
×
1504
            boost::remove_edge(edge, graph.graph_);
×
1505
        }
1506

1507
        auto vertex = current->vertex();
×
1508
        graph.nodes_.erase(vertex);
×
1509
        boost::remove_vertex(vertex, graph.graph_);
×
1510
    }
1511
};
×
1512

1513
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
20✔
1514
    auto& to_dataflow = to.dataflow();
20✔
1515

1516
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
20✔
1517
    for (auto& entry : from.nodes_) {
21✔
1518
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1519
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1520
        node_mapping.insert({entry.first, vertex});
1✔
1521
    }
1522

1523
    for (auto& entry : from.edges_) {
20✔
1524
        auto src = node_mapping[entry.second->src().vertex()];
×
1525
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1526

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

1529
        to_dataflow.edges_.insert(
×
1530
            {edge.first,
×
1531
             entry.second->clone(
×
1532
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1533
             )}
1534
        );
1535
    }
1536
};
20✔
1537

1538
} // namespace builder
1539
} // 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