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

daisytuner / sdfglib / 17697974118

13 Sep 2025 02:36PM UTC coverage: 60.51% (+1.2%) from 59.335%
17697974118

Pull #219

github

web-flow
Merge a1c5ecbc6 into 6c1992b40
Pull Request #219: stdlib Library Nodes and ConstantNodes

565 of 1799 new or added lines in 102 files covered. (31.41%)

102 existing lines in 38 files now uncovered.

9442 of 15604 relevant lines covered (60.51%)

107.02 hits per line

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

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

3
#include <cstddef>
4

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

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

16
namespace sdfg {
17
namespace builder {
18

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

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

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

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

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

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

62
    return false;
×
63
}
6✔
64

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

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

83
    return pdom;
3✔
84
}
3✔
85

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

210
            auto return_state = dynamic_cast<const control_flow::ReturnState*>(curr);
4✔
211
            assert(return_state != nullptr);
4✔
212
            this->add_return(scope, return_state->data(), return_state->unreachable(), {}, return_state->debug_info());
4✔
213
            continue;
4✔
214
        }
215

216
        // Case 2: Transition
217
        if (out_degree == 1) {
13✔
218
            auto& oedge = *out_edges.begin();
10✔
219
            if (!oedge.is_unconditional()) {
10✔
220
                throw UnstructuredControlFlowException();
×
221
            }
222
            this->add_block(scope, curr->dataflow(), oedge.assignments(), curr->debug_info());
10✔
223

224
            if (continues.find(&oedge) != continues.end()) {
10✔
225
                this->add_continue(scope, {}, oedge.debug_info());
×
226
            } else if (breaks.find(&oedge) != breaks.end()) {
10✔
227
                this->add_break(scope, {}, oedge.debug_info());
×
228
            } else {
×
229
                bool starts_loop = false;
10✔
230
                for (auto& iedge : sdfg.in_edges(oedge.dst())) {
23✔
231
                    if (continues.find(&iedge) != continues.end()) {
13✔
232
                        starts_loop = true;
×
233
                        break;
×
234
                    }
235
                }
236
                if (!starts_loop) {
10✔
237
                    queue.push_back(&oedge.dst());
10✔
238
                } else {
10✔
239
                    this->traverse_with_loop_detection(
×
240
                        sdfg, scope, &oedge.dst(), end, continues, breaks, pdom_tree, visited
×
241
                    );
242
                }
243
            }
244
            continue;
10✔
245
        }
246

247
        // Case 3: Branches
248
        if (out_degree > 1) {
3✔
249
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
3✔
250

251
            std::vector<const InterstateEdge*> out_edges_vec;
3✔
252
            for (auto& edge : out_edges) {
9✔
253
                out_edges_vec.push_back(&edge);
6✔
254
            }
255

256
            // Best-effort approach: Find end of if-else
257
            // If not found, the branches may repeat paths yielding a large SDFG
258
            const control_flow::State* local_end = this->find_end_of_if_else(sdfg, curr, out_edges_vec, pdom_tree);
3✔
259
            if (local_end == nullptr) {
3✔
260
                local_end = end;
×
261
            }
×
262

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

267
                auto& branch = this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
268
                if (!out_edge->assignments().empty()) {
6✔
269
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
270
                }
2✔
271
                if (continues.find(out_edge) != continues.end()) {
6✔
272
                    this->add_continue(branch, {}, out_edge->debug_info());
1✔
273
                } else if (breaks.find(out_edge) != breaks.end()) {
6✔
274
                    this->add_break(branch, {}, out_edge->debug_info());
1✔
275
                } else {
1✔
276
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
4✔
277
                    this->traverse_with_loop_detection(
4✔
278
                        sdfg, branch, &out_edge->dst(), local_end, continues, breaks, pdom_tree, branch_visited
4✔
279
                    );
280
                }
4✔
281
            }
6✔
282

283
            if (local_end != end) {
3✔
284
                bool starts_loop = false;
2✔
285
                for (auto& iedge : sdfg.in_edges(*local_end)) {
6✔
286
                    if (continues.find(&iedge) != continues.end()) {
4✔
287
                        starts_loop = true;
×
288
                        break;
×
289
                    }
290
                }
291
                if (!starts_loop) {
2✔
292
                    queue.push_back(local_end);
2✔
293
                } else {
2✔
294
                    this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues, breaks, pdom_tree, visited);
×
295
                }
296
            }
2✔
297
            continue;
298
        }
3✔
299
    }
300
}
8✔
301

302
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
5,764✔
303

304
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
80✔
305
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
80✔
306

307
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
517✔
308
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type)) {};
517✔
309

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

313
StructuredSDFGBuilder::StructuredSDFGBuilder(SDFG& sdfg)
4✔
314
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(sdfg.name(), sdfg.type(), sdfg.return_type())) {
4✔
315
    for (auto& entry : sdfg.structures_) {
4✔
316
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
317
    }
318

319
    for (auto& entry : sdfg.containers_) {
11✔
320
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
321
    }
322

323
    for (auto& arg : sdfg.arguments_) {
6✔
324
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
325
    }
326

327
    for (auto& ext : sdfg.externals_) {
5✔
328
        this->structured_sdfg_->externals_.push_back(ext);
1✔
329
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
1✔
330
    }
331

332
    for (auto& entry : sdfg.assumptions_) {
9✔
333
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
334
    }
335

336
    for (auto& entry : sdfg.metadata_) {
6✔
337
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
338
    }
339

340
    this->traverse(sdfg);
4✔
341
};
4✔
342

343
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
1,477✔
344

345
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
257✔
346
#ifndef NDEBUG
347
    this->structured_sdfg_->validate();
257✔
348
#endif
349

350
    return std::move(this->structured_sdfg_);
257✔
351
};
352

NEW
353
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
NEW
354
    FunctionBuilder::rename_container(old_name, new_name);
×
355

NEW
356
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
NEW
357
};
×
358

359
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
13✔
360
    auto& sdfg = this->subject();
13✔
361
    std::list<Element*> queue = {&sdfg.root()};
13✔
362
    while (!queue.empty()) {
55✔
363
        auto current = queue.front();
55✔
364
        queue.pop_front();
55✔
365

366
        if (current->element_id() == element_id) {
55✔
367
            return current;
13✔
368
        }
369

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

402
    return nullptr;
×
403
};
13✔
404

405
Sequence& StructuredSDFGBuilder::
406
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
27✔
407
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
27✔
408

409
    parent.transitions_
54✔
410
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
27✔
411
        );
412

413
    return static_cast<Sequence&>(*parent.children_.back().get());
27✔
414
};
×
415

416
Sequence& StructuredSDFGBuilder::add_sequence_before(
10✔
417
    Sequence& parent,
418
    ControlFlowNode& child,
419
    const sdfg::control_flow::Assignments& assignments,
420
    const DebugInfo& debug_info
421
) {
422
    int index = parent.index(child);
10✔
423
    if (index == -1) {
10✔
424
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
425
    }
426

427
    parent.children_.insert(
20✔
428
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
10✔
429
    );
430

431
    parent.transitions_.insert(
20✔
432
        parent.transitions_.begin() + index,
10✔
433
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
10✔
434
    );
435

436
    return static_cast<Sequence&>(*parent.children_.at(index).get());
10✔
437
};
×
438

439
Sequence& StructuredSDFGBuilder::add_sequence_after(
×
440
    Sequence& parent,
441
    ControlFlowNode& child,
442
    const sdfg::control_flow::Assignments& assignments,
443
    const DebugInfo& debug_info
444
) {
445
    int index = parent.index(child);
×
446
    if (index == -1) {
×
447
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
448
    }
449

450
    parent.children_.insert(
×
451
        parent.children_.begin() + index + 1,
×
452
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
453
    );
454

455
    parent.transitions_.insert(
×
456
        parent.transitions_.begin() + index + 1,
×
457
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
458
    );
459

460
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
461
};
×
462

463
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
464
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
465
    int index = parent.index(child);
×
466
    if (index == -1) {
×
467
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
468
    }
469

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

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

479
    auto new_entry = parent.at(index);
×
480
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
481

482
    return {new_block, new_entry.second};
×
483
};
×
484

485
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
25✔
486
    parent.children_.erase(parent.children_.begin() + index);
25✔
487
    parent.transitions_.erase(parent.transitions_.begin() + index);
25✔
488
};
25✔
489

490
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
491
    parent.children_.clear();
×
492
    parent.transitions_.clear();
×
493
};
×
494

495
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
10✔
496
    this->move_child(source, source_index, target, target.size());
10✔
497
};
10✔
498

499
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
10✔
500
    auto node_ptr = std::move(source.children_.at(source_index));
10✔
501
    auto trans_ptr = std::move(source.transitions_.at(source_index));
10✔
502
    source.children_.erase(source.children_.begin() + source_index);
10✔
503
    source.transitions_.erase(source.transitions_.begin() + source_index);
10✔
504

505
    trans_ptr->parent_ = &target;
10✔
506
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
10✔
507
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
10✔
508
};
10✔
509

510
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
23✔
511
    this->move_children(source, target, target.size());
23✔
512
};
23✔
513

514
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
23✔
515
    target.children_.insert(
46✔
516
        target.children_.begin() + target_index,
23✔
517
        std::make_move_iterator(source.children_.begin()),
23✔
518
        std::make_move_iterator(source.children_.end())
23✔
519
    );
520
    target.transitions_.insert(
46✔
521
        target.transitions_.begin() + target_index,
23✔
522
        std::make_move_iterator(source.transitions_.begin()),
23✔
523
        std::make_move_iterator(source.transitions_.end())
23✔
524
    );
525
    for (auto& trans : target.transitions_) {
52✔
526
        trans->parent_ = &target;
29✔
527
    }
528
    source.children_.clear();
23✔
529
    source.transitions_.clear();
23✔
530
};
23✔
531

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

536
    parent.transitions_
1,008✔
537
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
504✔
538
        );
539

540
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
504✔
541
    (*new_block.dataflow_).parent_ = &new_block;
504✔
542

543
    return new_block;
504✔
544
};
×
545

546
Block& StructuredSDFGBuilder::add_block(
20✔
547
    Sequence& parent,
548
    const data_flow::DataFlowGraph& data_flow_graph,
549
    const sdfg::control_flow::Assignments& assignments,
550
    const DebugInfo& debug_info
551
) {
552
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
20✔
553

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

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

561
    this->add_dataflow(data_flow_graph, new_block);
20✔
562

563
    return new_block;
20✔
564
};
×
565

566
Block& StructuredSDFGBuilder::add_block_before(
11✔
567
    Sequence& parent,
568
    ControlFlowNode& child,
569
    const sdfg::control_flow::Assignments& assignments,
570
    const DebugInfo& debug_info
571
) {
572
    int index = parent.index(child);
11✔
573
    if (index == -1) {
11✔
574
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
575
    }
576

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

580
    parent.transitions_.insert(
22✔
581
        parent.transitions_.begin() + index,
11✔
582
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
11✔
583
    );
584

585
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
11✔
586
    (*new_block.dataflow_).parent_ = &new_block;
11✔
587

588
    return new_block;
11✔
589
};
×
590

591
Block& StructuredSDFGBuilder::add_block_before(
×
592
    Sequence& parent,
593
    ControlFlowNode& child,
594
    data_flow::DataFlowGraph& data_flow_graph,
595
    const sdfg::control_flow::Assignments& assignments,
596
    const DebugInfo& debug_info
597
) {
598
    int index = parent.index(child);
×
599
    if (index == -1) {
×
600
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
601
    }
602

603
    parent.children_
×
604
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
605

606
    parent.transitions_.insert(
×
607
        parent.transitions_.begin() + index,
×
608
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
609
    );
610

611
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
612
    (*new_block.dataflow_).parent_ = &new_block;
×
613
    this->add_dataflow(data_flow_graph, new_block);
×
614

615
    return new_block;
×
616
};
×
617

618
Block& StructuredSDFGBuilder::add_block_after(
3✔
619
    Sequence& parent,
620
    ControlFlowNode& child,
621
    const sdfg::control_flow::Assignments& assignments,
622
    const DebugInfo& debug_info
623
) {
624
    int index = parent.index(child);
3✔
625
    if (index == -1) {
3✔
626
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
627
    }
628

629
    parent.children_.insert(
6✔
630
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3✔
631
    );
632

633
    parent.transitions_.insert(
6✔
634
        parent.transitions_.begin() + index + 1,
3✔
635
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3✔
636
    );
637

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

641
    return new_block;
3✔
642
};
×
643

644
Block& StructuredSDFGBuilder::add_block_after(
×
645
    Sequence& parent,
646
    ControlFlowNode& child,
647
    data_flow::DataFlowGraph& data_flow_graph,
648
    const sdfg::control_flow::Assignments& assignments,
649
    const DebugInfo& debug_info
650
) {
651
    int index = parent.index(child);
×
652
    if (index == -1) {
×
653
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
654
    }
655

656
    parent.children_.insert(
×
657
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
658
    );
659

660
    parent.transitions_.insert(
×
661
        parent.transitions_.begin() + index + 1,
×
662
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
663
    );
664

665
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
666
    (*new_block.dataflow_).parent_ = &new_block;
×
667
    this->add_dataflow(data_flow_graph, new_block);
×
668

669
    return new_block;
×
670
};
×
671

672
std::pair<Block&, Transition&> StructuredSDFGBuilder::
673
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
674
    int index = parent.index(child);
×
675
    if (index == -1) {
×
676
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
677
    }
678

679
    parent.children_
×
680
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
681

682
    parent.transitions_.insert(
×
683
        parent.transitions_.begin() + index,
×
684
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
685
    );
686

687
    auto new_entry = parent.at(index);
×
688
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
689
    (*new_block.dataflow_).parent_ = &new_block;
×
690

691
    return {new_block, new_entry.second};
×
692
};
×
693

694
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
695
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
696
) {
697
    int index = parent.index(child);
×
698
    if (index == -1) {
×
699
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
700
    }
701

702
    parent.children_
×
703
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
704

705
    parent.transitions_.insert(
×
706
        parent.transitions_.begin() + index,
×
707
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
708
    );
709

710
    auto new_entry = parent.at(index);
×
711
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
712
    (*new_block.dataflow_).parent_ = &new_block;
×
713

714
    this->add_dataflow(data_flow_graph, new_block);
×
715

716
    return {new_block, new_entry.second};
×
717
};
×
718

719
std::pair<Block&, Transition&> StructuredSDFGBuilder::
720
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
721
    int index = parent.index(child);
×
722
    if (index == -1) {
×
723
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
724
    }
725

726
    parent.children_.insert(
×
727
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
728
    );
729

730
    parent.transitions_.insert(
×
731
        parent.transitions_.begin() + index + 1,
×
732
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
733
    );
734

735
    auto new_entry = parent.at(index + 1);
×
736
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
737
    (*new_block.dataflow_).parent_ = &new_block;
×
738

739
    return {new_block, new_entry.second};
×
740
};
×
741

742
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
743
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
744
) {
745
    int index = parent.index(child);
×
746
    if (index == -1) {
×
747
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
748
    }
749

750
    parent.children_.insert(
×
751
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
752
    );
753

754
    parent.transitions_.insert(
×
755
        parent.transitions_.begin() + index + 1,
×
756
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
757
    );
758

759
    auto new_entry = parent.at(index + 1);
×
760
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
761
    (*new_block.dataflow_).parent_ = &new_block;
×
762

763
    this->add_dataflow(data_flow_graph, new_block);
×
764

765
    return {new_block, new_entry.second};
×
766
};
×
767

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

772
    parent.transitions_
82✔
773
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
41✔
774
        );
775

776
    return static_cast<IfElse&>(*parent.children_.back().get());
41✔
777
};
×
778

779
IfElse& StructuredSDFGBuilder::add_if_else_before(
1✔
780
    Sequence& parent,
781
    ControlFlowNode& child,
782
    const sdfg::control_flow::Assignments& assignments,
783
    const DebugInfo& debug_info
784
) {
785
    int index = parent.index(child);
1✔
786
    if (index == -1) {
1✔
787
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
788
    }
789

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

793
    parent.transitions_.insert(
2✔
794
        parent.transitions_.begin() + index,
1✔
795
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
1✔
796
    );
797

798
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
799
};
×
800

801
IfElse& StructuredSDFGBuilder::add_if_else_after(
×
802
    Sequence& parent,
803
    ControlFlowNode& child,
804
    const sdfg::control_flow::Assignments& assignments,
805
    const DebugInfo& debug_info
806
) {
807
    int index = parent.index(child);
×
808
    if (index == -1) {
×
809
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
810
    }
811

812
    parent.children_.insert(
×
813
        parent.children_.begin() + index + 1, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info))
×
814
    );
815

816
    parent.transitions_.insert(
×
817
        parent.transitions_.begin() + index + 1,
×
818
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
819
    );
820

821
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
822
};
×
823

824
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
825
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
826
    int index = parent.index(child);
×
827
    if (index == -1) {
×
828
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
829
    }
830

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

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

839
    auto new_entry = parent.at(index);
×
840
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
841

842
    return {new_block, new_entry.second};
×
843
};
×
844

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

848
    scope.conditions_.push_back(cond);
66✔
849
    return *scope.cases_.back();
66✔
850
};
×
851

852
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
853
    scope.cases_.erase(scope.cases_.begin() + index);
×
854
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
855
};
×
856

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

861
    // Increment element id for body node
862
    this->new_element_id();
33✔
863

864
    parent.transitions_
66✔
865
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
33✔
866
        );
867

868
    return static_cast<While&>(*parent.children_.back().get());
33✔
869
};
×
870

871
For& StructuredSDFGBuilder::add_for(
137✔
872
    Sequence& parent,
873
    const symbolic::Symbol indvar,
874
    const symbolic::Condition condition,
875
    const symbolic::Expression init,
876
    const symbolic::Expression update,
877
    const sdfg::control_flow::Assignments& assignments,
878
    const DebugInfo& debug_info
879
) {
880
    parent.children_
274✔
881
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
137✔
882

883
    // Increment element id for body node
884
    this->new_element_id();
137✔
885

886
    parent.transitions_
274✔
887
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
137✔
888
        );
889

890
    return static_cast<For&>(*parent.children_.back().get());
137✔
891
};
×
892

893
For& StructuredSDFGBuilder::add_for_before(
6✔
894
    Sequence& parent,
895
    ControlFlowNode& child,
896
    const symbolic::Symbol indvar,
897
    const symbolic::Condition condition,
898
    const symbolic::Expression init,
899
    const symbolic::Expression update,
900
    const sdfg::control_flow::Assignments& assignments,
901
    const DebugInfo& debug_info
902
) {
903
    int index = parent.index(child);
6✔
904
    if (index == -1) {
6✔
905
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
906
    }
907

908
    parent.children_.insert(
12✔
909
        parent.children_.begin() + index,
6✔
910
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
911
    );
912

913
    // Increment element id for body node
914
    this->new_element_id();
6✔
915

916
    parent.transitions_.insert(
12✔
917
        parent.transitions_.begin() + index,
6✔
918
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
919
    );
920

921
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
922
};
×
923

924
For& StructuredSDFGBuilder::add_for_after(
2✔
925
    Sequence& parent,
926
    ControlFlowNode& child,
927
    const symbolic::Symbol indvar,
928
    const symbolic::Condition condition,
929
    const symbolic::Expression init,
930
    const symbolic::Expression update,
931
    const sdfg::control_flow::Assignments& assignments,
932
    const DebugInfo& debug_info
933
) {
934
    int index = parent.index(child);
2✔
935
    if (index == -1) {
2✔
936
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
937
    }
938

939
    parent.children_.insert(
4✔
940
        parent.children_.begin() + index + 1,
2✔
941
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
2✔
942
    );
943

944
    // Increment element id for body node
945
    this->new_element_id();
2✔
946

947
    parent.transitions_.insert(
4✔
948
        parent.transitions_.begin() + index + 1,
2✔
949
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2✔
950
    );
951

952
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
953
};
×
954

955
Map& StructuredSDFGBuilder::add_map(
51✔
956
    Sequence& parent,
957
    const symbolic::Symbol indvar,
958
    const symbolic::Condition condition,
959
    const symbolic::Expression init,
960
    const symbolic::Expression update,
961
    const ScheduleType& schedule_type,
962
    const sdfg::control_flow::Assignments& assignments,
963
    const DebugInfo& debug_info
964
) {
965
    parent.children_
102✔
966
        .push_back(std::unique_ptr<
51✔
967
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
51✔
968

969
    // Increment element id for body node
970
    this->new_element_id();
51✔
971

972
    parent.transitions_
102✔
973
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
51✔
974
        );
975

976
    return static_cast<Map&>(*parent.children_.back().get());
51✔
977
};
×
978

979
Map& StructuredSDFGBuilder::add_map_before(
6✔
980
    Sequence& parent,
981
    ControlFlowNode& child,
982
    const symbolic::Symbol indvar,
983
    const symbolic::Condition condition,
984
    const symbolic::Expression init,
985
    const symbolic::Expression update,
986
    const ScheduleType& schedule_type,
987
    const sdfg::control_flow::Assignments& assignments,
988
    const DebugInfo& debug_info
989
) {
990
    int index = parent.index(child);
6✔
991
    if (index == -1) {
6✔
992
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
993
    }
994

995
    parent.children_.insert(
12✔
996
        parent.children_.begin() + index,
6✔
997
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
6✔
998
        )
999
    );
1000

1001
    // Increment element id for body node
1002
    this->new_element_id();
6✔
1003

1004
    parent.transitions_.insert(
12✔
1005
        parent.transitions_.begin() + index,
6✔
1006
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
1007
    );
1008

1009
    return static_cast<Map&>(*parent.children_.at(index).get());
6✔
1010
};
×
1011

1012
Map& StructuredSDFGBuilder::add_map_after(
12✔
1013
    Sequence& parent,
1014
    ControlFlowNode& child,
1015
    const symbolic::Symbol indvar,
1016
    const symbolic::Condition condition,
1017
    const symbolic::Expression init,
1018
    const symbolic::Expression update,
1019
    const ScheduleType& schedule_type,
1020
    const sdfg::control_flow::Assignments& assignments,
1021
    const DebugInfo& debug_info
1022
) {
1023
    int index = parent.index(child);
12✔
1024
    if (index == -1) {
12✔
1025
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1026
    }
1027

1028
    parent.children_.insert(
24✔
1029
        parent.children_.begin() + index + 1,
12✔
1030
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
12✔
1031
        )
1032
    );
1033

1034
    // Increment element id for body node
1035
    this->new_element_id();
12✔
1036

1037
    parent.transitions_.insert(
24✔
1038
        parent.transitions_.begin() + index + 1,
12✔
1039
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
12✔
1040
    );
1041

1042
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
12✔
1043
};
×
1044

1045
Continue& StructuredSDFGBuilder::
1046
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
14✔
1047
    // Check if continue is in a loop
1048
    analysis::AnalysisManager analysis_manager(this->subject());
14✔
1049
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
14✔
1050
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
14✔
1051
    bool in_loop = false;
14✔
1052
    while (current_scope != nullptr) {
24✔
1053
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
24✔
1054
            in_loop = true;
14✔
1055
            break;
14✔
1056
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
1057
            throw UnstructuredControlFlowException();
×
1058
        }
1059
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
1060
    }
1061
    if (!in_loop) {
14✔
1062
        throw UnstructuredControlFlowException();
×
1063
    }
1064

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

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

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

1074
Break& StructuredSDFGBuilder::
1075
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
15✔
1076
    // Check if break is in a loop
1077
    analysis::AnalysisManager analysis_manager(this->subject());
15✔
1078
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
15✔
1079
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
15✔
1080
    bool in_loop = false;
15✔
1081
    while (current_scope != nullptr) {
25✔
1082
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
25✔
1083
            in_loop = true;
15✔
1084
            break;
15✔
1085
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
1086
            throw UnstructuredControlFlowException();
×
1087
        }
1088
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
1089
    }
1090
    if (!in_loop) {
15✔
1091
        throw UnstructuredControlFlowException();
×
1092
    }
1093

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

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

1100
    return static_cast<Break&>(*parent.children_.back().get());
15✔
1101
};
15✔
1102

1103
Return& StructuredSDFGBuilder::add_return(
16✔
1104
    Sequence& parent,
1105
    const std::string& data,
1106
    bool unreachable,
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, unreachable)
16✔
1111
    ));
1112

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

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

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

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

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

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

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

1148
    return for_loop;
×
1149
};
×
1150

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

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

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

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

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

1180
    return map;
8✔
1181
};
×
1182

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

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

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

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

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

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

1234
/***** Section: Dataflow Graph *****/
1235

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

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

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

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

1263

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

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

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

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

1305
    return memlet;
652✔
1306
};
×
1307

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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