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

daisytuner / sdfglib / 19192861975

08 Nov 2025 12:14PM UTC coverage: 61.281% (-0.1%) from 61.415%
19192861975

push

github

web-flow
Merge pull request #329 from daisytuner/trap-nodes

Trap nodes and unreachable return

17 of 101 new or added lines in 7 files covered. (16.83%)

6 existing lines in 2 files now uncovered.

10264 of 16749 relevant lines covered (61.28%)

100.39 hits per line

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

66.55
/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_constant()) {
4✔
214
                this->add_constant_return(
×
215
                    scope, return_state->data(), return_state->type(), {}, return_state->debug_info()
×
216
                );
217
            } else {
×
218
                assert(false && "Unknown return state type");
×
219
            }
220

221
            continue;
4✔
222
        }
223

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

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

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

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

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

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

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

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

310
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
5,669✔
311

312
StructuredSDFGBuilder::StructuredSDFGBuilder(StructuredSDFG& sdfg)
×
313
    : FunctionBuilder(), structured_sdfg_(&sdfg, owned(false)) {};
×
314

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

318
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
414✔
319
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type), owned(true)) {};
414✔
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), owned(true)) {};
7✔
323

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

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

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

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

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

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

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

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

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

362
    if (!structured_sdfg_.get_deleter().should_delete_) {
273✔
363
        throw InvalidSDFGException("StructuredSDFGBuilder: Cannot move a non-owned SDFG");
×
364
    }
365

366
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
273✔
367
};
×
368

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

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

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

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

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

418
    return nullptr;
×
419
};
13✔
420

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

552
    parent.transitions_
860✔
553
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
430✔
554
        );
555

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

559
    return new_block;
430✔
560
};
×
561

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

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

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

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

579
    return new_block;
20✔
580
};
×
581

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

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

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

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

604
    return new_block;
12✔
605
};
×
606

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

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

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

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

631
    return new_block;
×
632
};
×
633

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

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

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

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

657
    return new_block;
3✔
658
};
×
659

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

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

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

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

685
    return new_block;
×
686
};
×
687

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1091
    parent.transitions_
36✔
1092
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
18✔
1093
        );
1094

1095
    return static_cast<Return&>(*parent.children_.back().get());
18✔
1096
};
×
1097

UNCOV
1098
Return& StructuredSDFGBuilder::add_constant_return(
×
1099
    Sequence& parent,
1100
    const std::string& data,
1101
    const types::IType& type,
1102
    const sdfg::control_flow::Assignments& assignments,
1103
    const DebugInfo& debug_info
1104
) {
UNCOV
1105
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1106

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

UNCOV
1111
    return static_cast<Return&>(*parent.children_.back().get());
×
1112
};
×
1113

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

1127
    auto iter = parent.children_.begin() + index;
×
1128
    auto& new_iter = *parent.children_.insert(
×
1129
        iter + 1,
×
1130
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1131
    );
1132

1133
    // Increment element id for body node
1134
    this->new_element_id();
×
1135

1136
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1137
    this->move_children(loop.root(), for_loop.root());
×
1138

1139
    // Remove while loop
1140
    parent.children_.erase(parent.children_.begin() + index);
×
1141

1142
    return for_loop;
×
1143
};
×
1144

1145
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
8✔
1146
    int index = parent.index(loop);
8✔
1147
    if (index == -1) {
8✔
1148
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1149
    }
1150

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

1165
    // Increment element id for body node
1166
    this->new_element_id();
8✔
1167

1168
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1169
    this->move_children(loop.root(), map.root());
8✔
1170

1171
    // Remove for loop
1172
    parent.children_.erase(parent.children_.begin() + index);
8✔
1173

1174
    return map;
8✔
1175
};
×
1176

1177
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1178
    if (index >= if_else.conditions_.size()) {
×
1179
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1180
    }
1181
    if_else.conditions_.at(index) = condition;
×
1182
};
×
1183

1184
void StructuredSDFGBuilder::update_loop(
17✔
1185
    StructuredLoop& loop,
1186
    const symbolic::Symbol indvar,
1187
    const symbolic::Condition condition,
1188
    const symbolic::Expression init,
1189
    const symbolic::Expression update
1190
) {
1191
    loop.indvar_ = indvar;
17✔
1192
    loop.condition_ = condition;
17✔
1193
    loop.init_ = init;
17✔
1194
    loop.update_ = update;
17✔
1195
};
17✔
1196

1197
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1198
    map.schedule_type_ = schedule_type;
4✔
1199
}
4✔
1200

1201
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1202
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1203
    while (!queue.empty()) {
2✔
1204
        auto current = queue.front();
2✔
1205
        queue.pop_front();
2✔
1206

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

1225
    return this->structured_sdfg_->root();
×
1226
};
2✔
1227

1228
/***** Section: Dataflow Graph *****/
1229

1230
data_flow::AccessNode& StructuredSDFGBuilder::
1231
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
614✔
1232
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
614✔
1233
    auto res = block.dataflow_->nodes_.insert(
1,228✔
1234
        {vertex,
614✔
1235
         std::unique_ptr<data_flow::AccessNode>(
614✔
1236
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
614✔
1237
         )}
1238
    );
1239

1240
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
614✔
1241
};
×
1242

1243
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
73✔
1244
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1245
) {
1246
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
73✔
1247
    auto res = block.dataflow_->nodes_.insert(
146✔
1248
        {vertex,
73✔
1249
         std::unique_ptr<data_flow::ConstantNode>(
73✔
1250
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
73✔
1251
         )}
1252
    );
1253

1254
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
73✔
1255
};
×
1256

1257

1258
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
260✔
1259
    structured_control_flow::Block& block,
1260
    const data_flow::TaskletCode code,
1261
    const std::string& output,
1262
    const std::vector<std::string>& inputs,
1263
    const DebugInfo& debug_info
1264
) {
1265
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
260✔
1266
    auto res = block.dataflow_->nodes_.insert(
520✔
1267
        {vertex,
260✔
1268
         std::unique_ptr<data_flow::Tasklet>(
260✔
1269
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
260✔
1270
         )}
1271
    );
1272

1273
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
260✔
1274
};
×
1275

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

1294
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
691✔
1295
#ifndef NDEBUG
1296
    memlet.validate(*this->structured_sdfg_);
691✔
1297
#endif
1298

1299
    return memlet;
691✔
1300
};
×
1301

1302
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
87✔
1303
    structured_control_flow::Block& block,
1304
    data_flow::AccessNode& src,
1305
    data_flow::Tasklet& dst,
1306
    const std::string& dst_conn,
1307
    const data_flow::Subset& subset,
1308
    const types::IType& base_type,
1309
    const DebugInfo& debug_info
1310
) {
1311
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
87✔
1312
};
×
1313

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

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

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

1363
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
13✔
1364
    structured_control_flow::Block& block,
1365
    data_flow::AccessNode& src,
1366
    data_flow::LibraryNode& dst,
1367
    const std::string& dst_conn,
1368
    const data_flow::Subset& subset,
1369
    const types::IType& base_type,
1370
    const DebugInfo& debug_info
1371
) {
1372
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
13✔
1373
};
×
1374

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

1387
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
20✔
1388
    structured_control_flow::Block& block,
1389
    data_flow::AccessNode& src,
1390
    data_flow::AccessNode& dst,
1391
    const data_flow::Subset& subset,
1392
    const types::IType& base_type,
1393
    const DebugInfo& debug_info
1394
) {
1395
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
20✔
1396
};
×
1397

1398
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
13✔
1399
    structured_control_flow::Block& block,
1400
    data_flow::AccessNode& src,
1401
    data_flow::AccessNode& dst,
1402
    bool derefs_src,
1403
    const types::IType& base_type,
1404
    const DebugInfo& debug_info
1405
) {
1406
    if (derefs_src) {
13✔
1407
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
6✔
1408
    } else {
1409
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
7✔
1410
    }
1411
};
13✔
1412

1413
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
26✔
1414
    auto& graph = block.dataflow();
26✔
1415
    auto e = edge.edge();
26✔
1416
    boost::remove_edge(e, graph.graph_);
26✔
1417
    graph.edges_.erase(e);
26✔
1418
};
26✔
1419

1420
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
22✔
1421
    auto& graph = block.dataflow();
22✔
1422
    auto v = node.vertex();
22✔
1423
    boost::remove_vertex(v, graph.graph_);
22✔
1424
    graph.nodes_.erase(v);
22✔
1425
};
22✔
1426

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

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

1432
    // Delete incoming
1433
    std::list<const data_flow::Memlet*> iedges;
10✔
1434
    for (auto& iedge : graph.in_edges(node)) {
27✔
1435
        iedges.push_back(&iedge);
17✔
1436
    }
1437
    for (auto iedge : iedges) {
27✔
1438
        auto& src = iedge->src();
17✔
1439
        to_delete.insert(&src);
17✔
1440

1441
        auto edge = iedge->edge();
17✔
1442
        graph.edges_.erase(edge);
17✔
1443
        boost::remove_edge(edge, graph.graph_);
17✔
1444
    }
1445

1446
    // Delete outgoing
1447
    std::list<const data_flow::Memlet*> oedges;
10✔
1448
    for (auto& oedge : graph.out_edges(node)) {
20✔
1449
        oedges.push_back(&oedge);
10✔
1450
    }
1451
    for (auto oedge : oedges) {
20✔
1452
        auto& dst = oedge->dst();
10✔
1453
        to_delete.insert(&dst);
10✔
1454

1455
        auto edge = oedge->edge();
10✔
1456
        graph.edges_.erase(edge);
10✔
1457
        boost::remove_edge(edge, graph.graph_);
10✔
1458
    }
1459

1460
    // Delete nodes
1461
    for (auto obsolete_node : to_delete) {
47✔
1462
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
37✔
1463
            auto vertex = obsolete_node->vertex();
37✔
1464
            graph.nodes_.erase(vertex);
37✔
1465
            boost::remove_vertex(vertex, graph.graph_);
37✔
1466
        }
37✔
1467
    }
1468
};
10✔
1469

1470
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
5✔
1471
    auto& graph = block.dataflow();
5✔
1472
    if (graph.out_degree(node) != 0) {
5✔
1473
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1474
    }
1475

1476
    std::list<const data_flow::Memlet*> tmp;
5✔
1477
    std::list<const data_flow::DataFlowNode*> queue = {&node};
5✔
1478
    while (!queue.empty()) {
17✔
1479
        auto current = queue.front();
12✔
1480
        queue.pop_front();
12✔
1481
        if (current != &node) {
12✔
1482
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
7✔
1483
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
2✔
1484
                    continue;
×
1485
                }
1486
            }
2✔
1487
        }
7✔
1488

1489
        tmp.clear();
12✔
1490
        for (auto& iedge : graph.in_edges(*current)) {
19✔
1491
            tmp.push_back(&iedge);
7✔
1492
        }
1493
        for (auto iedge : tmp) {
19✔
1494
            auto& src = iedge->src();
7✔
1495
            queue.push_back(&src);
7✔
1496

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

1502
        auto vertex = current->vertex();
12✔
1503
        graph.nodes_.erase(vertex);
12✔
1504
        boost::remove_vertex(vertex, graph.graph_);
12✔
1505
    }
1506
};
5✔
1507

1508
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
20✔
1509
    auto& to_dataflow = to.dataflow();
20✔
1510

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

1518
    for (auto& entry : from.edges_) {
20✔
1519
        auto src = node_mapping[entry.second->src().vertex()];
×
1520
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1521

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

1524
        to_dataflow.edges_.insert(
×
1525
            {edge.first,
×
1526
             entry.second->clone(
×
1527
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1528
             )}
1529
        );
1530
    }
1531
};
20✔
1532

1533
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
9✔
1534
    auto& user_graph = source_node.get_parent();
9✔
1535
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
9✔
1536
    if (!block) {
9✔
1537
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1538
    }
1539

1540
    // Merge access nodes if they access the same container on a tasklet
1541
    for (auto& oedge : user_graph.out_edges(source_node)) {
15✔
1542
        if (auto* tasklet = dynamic_cast<data_flow::Tasklet*>(&oedge.dst())) {
6✔
1543
            std::unordered_set<data_flow::Memlet*> iedges;
2✔
1544
            for (auto& iedge : user_graph.in_edges(*tasklet)) {
4✔
1545
                iedges.insert(&iedge);
2✔
1546
            }
1547
            for (auto* iedge : iedges) {
4✔
1548
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
2✔
1549
                    continue;
×
1550
                }
1551
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
2✔
1552
                if (access_node == &source_node || access_node->data() != source_node.data()) {
2✔
1553
                    continue;
2✔
1554
                }
1555
                this->add_memlet(
×
1556
                    *block,
×
1557
                    source_node,
×
1558
                    iedge->src_conn(),
×
1559
                    *tasklet,
×
1560
                    iedge->dst_conn(),
×
1561
                    iedge->subset(),
×
1562
                    iedge->base_type(),
×
1563
                    iedge->debug_info()
×
1564
                );
1565
                this->remove_memlet(*block, *iedge);
×
1566
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
×
1567
            }
1568
        }
2✔
1569
    }
1570
}
9✔
1571

1572
} // namespace builder
1573
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc