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

daisytuner / sdfglib / 17368505925

01 Sep 2025 05:29AM UTC coverage: 58.982% (-0.8%) from 59.781%
17368505925

push

github

web-flow
Merge pull request #216 from daisytuner/transitions-bug

Updates API for Sequence transitions to prevent leakage of assignments

239 of 547 new or added lines in 25 files covered. (43.69%)

75 existing lines in 12 files now uncovered.

9190 of 15581 relevant lines covered (58.98%)

115.89 hits per line

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

68.86
/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(const 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
    const 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
    for (auto& edge : out_edges) {
9✔
74
        if (!post_dominates(pdom, &edge->dst(), pdom_tree)) {
6✔
75
            return nullptr;
×
76
        }
77
    }
78

79
    return pdom;
3✔
80
}
3✔
81

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

87
    auto pdom_tree = sdfg.post_dominator_tree();
4✔
88

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

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

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

113
    auto in_edges = sdfg.in_edges(*current);
8✔
114

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

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

146
        for (auto& edge : breaks) {
1✔
147
            exit_edges.insert(edge);
×
148
        }
149

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

162
        // 3. Add while loop
163
        While& loop = this->add_while(scope, {}, dbg_info);
1✔
164

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

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

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

194
        if (visited.find(curr) != visited.end()) {
15✔
195
            throw UnstructuredControlFlowException();
×
196
        }
197
        visited.insert(curr);
15✔
198

199
        auto out_edges = sdfg.out_edges(*curr);
15✔
200
        auto out_degree = sdfg.out_degree(*curr);
15✔
201

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

209
        // Case 2: Transition
210
        if (out_degree == 1) {
11✔
211
            auto& oedge = *out_edges.begin();
8✔
212
            if (!oedge.is_unconditional()) {
8✔
213
                throw UnstructuredControlFlowException();
×
214
            }
215
            this->add_block(scope, curr->dataflow(), oedge.assignments(), curr->debug_info());
8✔
216

217
            if (continues.find(&oedge) != continues.end()) {
8✔
NEW
218
                this->add_continue(scope, {}, oedge.debug_info());
×
219
            } else if (breaks.find(&oedge) != breaks.end()) {
8✔
NEW
220
                this->add_break(scope, {}, oedge.debug_info());
×
221
            } else {
×
222
                bool starts_loop = false;
8✔
223
                for (auto& iedge : sdfg.in_edges(oedge.dst())) {
19✔
224
                    if (continues.find(&iedge) != continues.end()) {
11✔
225
                        starts_loop = true;
×
226
                        break;
×
227
                    }
228
                }
229
                if (!starts_loop) {
8✔
230
                    queue.push_back(&oedge.dst());
8✔
231
                } else {
8✔
232
                    this->traverse_with_loop_detection(
×
233
                        sdfg, scope, &oedge.dst(), end, continues, breaks, pdom_tree, visited
×
234
                    );
235
                }
236
            }
237
            continue;
8✔
238
        }
239

240
        // Case 3: Branches
241
        if (out_degree > 1) {
3✔
242
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
3✔
243

244
            std::vector<const InterstateEdge*> out_edges_vec;
3✔
245
            for (auto& edge : out_edges) {
9✔
246
                out_edges_vec.push_back(&edge);
6✔
247
            }
248

249
            // Best-effort approach: Find end of if-else
250
            // If not found, the branches may repeat paths yielding a large SDFG
251
            const control_flow::State* local_end = this->find_end_of_if_else(sdfg, curr, out_edges_vec, pdom_tree);
3✔
252
            if (local_end == nullptr) {
3✔
253
                local_end = end;
×
254
            }
×
255

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

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

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

295
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
5,548✔
296

297
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
78✔
298
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
78✔
299

300
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
517✔
301
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type)) {};
517✔
302

303
StructuredSDFGBuilder::StructuredSDFGBuilder(const SDFG& sdfg)
4✔
304
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(sdfg.name(), sdfg.type())) {
4✔
305
    for (auto& entry : sdfg.structures_) {
4✔
306
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
307
    }
308

309
    for (auto& entry : sdfg.containers_) {
11✔
310
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
311
    }
312

313
    for (auto& arg : sdfg.arguments_) {
6✔
314
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
315
    }
316

317
    for (auto& ext : sdfg.externals_) {
5✔
318
        this->structured_sdfg_->externals_.push_back(ext);
1✔
319
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
1✔
320
    }
321

322
    for (auto& entry : sdfg.assumptions_) {
9✔
323
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
324
    }
325

326
    for (auto& entry : sdfg.metadata_) {
6✔
327
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
328
    }
329

330
    this->traverse(sdfg);
4✔
331
};
4✔
332

333
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
974✔
334

335
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
422✔
336
#ifndef NDEBUG
337
    this->structured_sdfg_->validate();
422✔
338
#endif
339

340
    return std::move(this->structured_sdfg_);
422✔
341
};
342

343
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
13✔
344
    auto& sdfg = this->subject();
13✔
345
    std::list<Element*> queue = {&sdfg.root()};
13✔
346
    while (!queue.empty()) {
55✔
347
        auto current = queue.front();
55✔
348
        queue.pop_front();
55✔
349

350
        if (current->element_id() == element_id) {
55✔
351
            return current;
13✔
352
        }
353

354
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
42✔
355
            auto& dataflow = block_stmt->dataflow();
×
356
            for (auto& node : dataflow.nodes()) {
×
357
                queue.push_back(&node);
×
358
            }
359
            for (auto& edge : dataflow.edges()) {
×
360
                queue.push_back(&edge);
×
361
            }
362
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
42✔
363
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
44✔
364
                queue.push_back(&sequence_stmt->at(i).first);
22✔
365
                queue.push_back(&sequence_stmt->at(i).second);
22✔
366
            }
22✔
367
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
42✔
368
            // Do nothing
369
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
20✔
370
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
371
                queue.push_back(&if_else_stmt->at(i).first);
×
372
            }
×
373
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
20✔
374
            queue.push_back(&for_stmt->root());
×
375
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
20✔
376
            queue.push_back(&while_stmt->root());
×
377
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
20✔
378
            // Do nothing
379
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
20✔
380
            // Do nothing
381
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
20✔
382
            queue.push_back(&map_stmt->root());
10✔
383
        }
10✔
384
    }
385

386
    return nullptr;
×
387
};
13✔
388

389
Sequence& StructuredSDFGBuilder::
390
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
27✔
391
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
27✔
392

393
    parent.transitions_
54✔
394
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
27✔
395
        );
396

397
    return static_cast<Sequence&>(*parent.children_.back().get());
27✔
398
};
×
399

400
Sequence& StructuredSDFGBuilder::add_sequence_before(
10✔
401
    Sequence& parent,
402
    ControlFlowNode& child,
403
    const sdfg::control_flow::Assignments& assignments,
404
    const DebugInfo& debug_info
405
) {
406
    int index = parent.index(child);
10✔
407
    if (index == -1) {
10✔
NEW
408
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
409
    }
410

411
    parent.children_.insert(
20✔
412
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
10✔
413
    );
414

415
    parent.transitions_.insert(
20✔
416
        parent.transitions_.begin() + index,
10✔
417
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
10✔
418
    );
419

420
    return static_cast<Sequence&>(*parent.children_.at(index).get());
10✔
NEW
421
};
×
422

NEW
423
Sequence& StructuredSDFGBuilder::add_sequence_after(
×
424
    Sequence& parent,
425
    ControlFlowNode& child,
426
    const sdfg::control_flow::Assignments& assignments,
427
    const DebugInfo& debug_info
428
) {
NEW
429
    int index = parent.index(child);
×
430
    if (index == -1) {
×
NEW
431
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
432
    }
433

NEW
434
    parent.children_.insert(
×
NEW
435
        parent.children_.begin() + index + 1,
×
NEW
436
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
437
    );
438

NEW
439
    parent.transitions_.insert(
×
NEW
440
        parent.transitions_.begin() + index + 1,
×
NEW
441
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
442
    );
443

NEW
444
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
NEW
445
};
×
446

447
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
NEW
448
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
NEW
449
    int index = parent.index(child);
×
NEW
450
    if (index == -1) {
×
NEW
451
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
452
    }
453

UNCOV
454
    parent.children_.insert(
×
UNCOV
455
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
456
    );
457

UNCOV
458
    parent.transitions_.insert(
×
UNCOV
459
        parent.transitions_.begin() + index,
×
UNCOV
460
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
461
    );
462

UNCOV
463
    auto new_entry = parent.at(index);
×
UNCOV
464
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
465

UNCOV
466
    return {new_block, new_entry.second};
×
467
};
×
468

469
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
25✔
470
    parent.children_.erase(parent.children_.begin() + index);
25✔
471
    parent.transitions_.erase(parent.transitions_.begin() + index);
25✔
472
};
25✔
473

NEW
474
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
NEW
475
    parent.children_.clear();
×
NEW
476
    parent.transitions_.clear();
×
UNCOV
477
};
×
478

479
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
10✔
480
    this->move_child(source, source_index, target, target.size());
10✔
481
};
10✔
482

483
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
10✔
484
    auto node_ptr = std::move(source.children_.at(source_index));
10✔
485
    auto trans_ptr = std::move(source.transitions_.at(source_index));
10✔
486
    source.children_.erase(source.children_.begin() + source_index);
10✔
487
    source.transitions_.erase(source.transitions_.begin() + source_index);
10✔
488

489
    trans_ptr->parent_ = &target;
10✔
490
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
10✔
491
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
10✔
492
};
10✔
493

494
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
23✔
495
    this->move_children(source, target, target.size());
23✔
496
};
23✔
497

498
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
23✔
499
    target.children_.insert(
46✔
500
        target.children_.begin() + target_index,
23✔
501
        std::make_move_iterator(source.children_.begin()),
23✔
502
        std::make_move_iterator(source.children_.end())
23✔
503
    );
504
    target.transitions_.insert(
46✔
505
        target.transitions_.begin() + target_index,
23✔
506
        std::make_move_iterator(source.transitions_.begin()),
23✔
507
        std::make_move_iterator(source.transitions_.end())
23✔
508
    );
509
    for (auto& trans : target.transitions_) {
52✔
510
        trans->parent_ = &target;
29✔
511
    }
512
    source.children_.clear();
23✔
513
    source.transitions_.clear();
23✔
514
};
23✔
515

516
Block& StructuredSDFGBuilder::
517
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
502✔
518
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
502✔
519

520
    parent.transitions_
1,004✔
521
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
502✔
522
        );
523

524
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
502✔
525
    (*new_block.dataflow_).parent_ = &new_block;
502✔
526

527
    return new_block;
502✔
528
};
×
529

530
Block& StructuredSDFGBuilder::add_block(
18✔
531
    Sequence& parent,
532
    const data_flow::DataFlowGraph& data_flow_graph,
533
    const sdfg::control_flow::Assignments& assignments,
534
    const DebugInfo& debug_info
535
) {
536
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
18✔
537

538
    parent.transitions_
36✔
539
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
18✔
540
        );
541

542
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
18✔
543
    (*new_block.dataflow_).parent_ = &new_block;
18✔
544

545
    this->add_dataflow(data_flow_graph, new_block);
18✔
546

547
    return new_block;
18✔
548
};
×
549

550
Block& StructuredSDFGBuilder::add_block_before(
11✔
551
    Sequence& parent,
552
    ControlFlowNode& child,
553
    const sdfg::control_flow::Assignments& assignments,
554
    const DebugInfo& debug_info
555
) {
556
    int index = parent.index(child);
11✔
557
    if (index == -1) {
11✔
NEW
558
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
559
    }
560

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

564
    parent.transitions_.insert(
22✔
565
        parent.transitions_.begin() + index,
11✔
566
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
11✔
567
    );
568

569
    return static_cast<Block&>(*parent.children_.at(index).get());
11✔
NEW
570
};
×
571

NEW
572
Block& StructuredSDFGBuilder::add_block_before(
×
573
    Sequence& parent,
574
    ControlFlowNode& child,
575
    data_flow::DataFlowGraph& data_flow_graph,
576
    const sdfg::control_flow::Assignments& assignments,
577
    const DebugInfo& debug_info
578
) {
NEW
579
    int index = parent.index(child);
×
NEW
580
    if (index == -1) {
×
NEW
581
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
582
    }
583

NEW
584
    parent.children_
×
NEW
585
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
586

NEW
587
    parent.transitions_.insert(
×
NEW
588
        parent.transitions_.begin() + index,
×
NEW
589
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
590
    );
591

NEW
592
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index).get());
×
NEW
593
    (*new_block.dataflow_).parent_ = &new_block;
×
NEW
594
    this->add_dataflow(data_flow_graph, new_block);
×
595

NEW
596
    return new_block;
×
NEW
597
};
×
598

599
Block& StructuredSDFGBuilder::add_block_after(
3✔
600
    Sequence& parent,
601
    ControlFlowNode& child,
602
    const sdfg::control_flow::Assignments& assignments,
603
    const DebugInfo& debug_info
604
) {
605
    int index = parent.index(child);
3✔
606
    if (index == -1) {
3✔
NEW
607
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
608
    }
609

610
    parent.children_.insert(
6✔
611
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3✔
612
    );
613

614
    parent.transitions_.insert(
6✔
615
        parent.transitions_.begin() + index + 1,
3✔
616
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3✔
617
    );
618

619
    return static_cast<Block&>(*parent.children_.at(index + 1).get());
3✔
NEW
620
};
×
621

NEW
622
Block& StructuredSDFGBuilder::add_block_after(
×
623
    Sequence& parent,
624
    ControlFlowNode& child,
625
    data_flow::DataFlowGraph& data_flow_graph,
626
    const sdfg::control_flow::Assignments& assignments,
627
    const DebugInfo& debug_info
628
) {
NEW
629
    int index = parent.index(child);
×
NEW
630
    if (index == -1) {
×
NEW
631
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
632
    }
633

NEW
634
    parent.children_.insert(
×
NEW
635
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
636
    );
637

NEW
638
    parent.transitions_.insert(
×
NEW
639
        parent.transitions_.begin() + index + 1,
×
NEW
640
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
641
    );
642

NEW
643
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1).get());
×
NEW
644
    (*new_block.dataflow_).parent_ = &new_block;
×
NEW
645
    this->add_dataflow(data_flow_graph, new_block);
×
646

NEW
647
    return new_block;
×
NEW
648
};
×
649

650
std::pair<Block&, Transition&> StructuredSDFGBuilder::
NEW
651
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
NEW
652
    int index = parent.index(child);
×
NEW
653
    if (index == -1) {
×
NEW
654
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
655
    }
656

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

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

UNCOV
665
    auto new_entry = parent.at(index);
×
UNCOV
666
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
UNCOV
667
    (*new_block.dataflow_).parent_ = &new_block;
×
668

UNCOV
669
    return {new_block, new_entry.second};
×
670
};
×
671

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

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

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

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

692
    this->add_dataflow(data_flow_graph, new_block);
×
693

694
    return {new_block, new_entry.second};
×
695
};
×
696

697
std::pair<Block&, Transition&> StructuredSDFGBuilder::
NEW
698
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
NEW
699
    int index = parent.index(child);
×
NEW
700
    if (index == -1) {
×
NEW
701
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
702
    }
703

UNCOV
704
    parent.children_.insert(
×
UNCOV
705
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
706
    );
707

UNCOV
708
    parent.transitions_.insert(
×
UNCOV
709
        parent.transitions_.begin() + index + 1,
×
UNCOV
710
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
711
    );
712

UNCOV
713
    auto new_entry = parent.at(index + 1);
×
UNCOV
714
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
UNCOV
715
    (*new_block.dataflow_).parent_ = &new_block;
×
716

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

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

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

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

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

741
    this->add_dataflow(data_flow_graph, new_block);
×
742

743
    return {new_block, new_entry.second};
×
744
};
×
745

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

750
    parent.transitions_
80✔
751
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
40✔
752
        );
753

754
    return static_cast<IfElse&>(*parent.children_.back().get());
40✔
755
};
×
756

757
IfElse& StructuredSDFGBuilder::add_if_else_before(
1✔
758
    Sequence& parent,
759
    ControlFlowNode& child,
760
    const sdfg::control_flow::Assignments& assignments,
761
    const DebugInfo& debug_info
762
) {
763
    int index = parent.index(child);
1✔
764
    if (index == -1) {
1✔
NEW
765
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
766
    }
767

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

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

776
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
UNCOV
777
};
×
778

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

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

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

NEW
799
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
UNCOV
800
};
×
801

802
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
NEW
803
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
NEW
804
    int index = parent.index(child);
×
NEW
805
    if (index == -1) {
×
NEW
806
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
807
    }
808

UNCOV
809
    parent.children_
×
UNCOV
810
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
×
811

UNCOV
812
    parent.transitions_.insert(
×
UNCOV
813
        parent.transitions_.begin() + index,
×
UNCOV
814
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
815
    );
816

UNCOV
817
    auto new_entry = parent.at(index);
×
UNCOV
818
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
819

UNCOV
820
    return {new_block, new_entry.second};
×
821
};
×
822

823
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
64✔
824
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
64✔
825

826
    scope.conditions_.push_back(cond);
64✔
827
    return *scope.cases_.back();
64✔
828
};
×
829

NEW
830
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
NEW
831
    scope.cases_.erase(scope.cases_.begin() + index);
×
NEW
832
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
UNCOV
833
};
×
834

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

839
    // Increment element id for body node
840
    this->new_element_id();
33✔
841

842
    parent.transitions_
66✔
843
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
33✔
844
        );
845

846
    return static_cast<While&>(*parent.children_.back().get());
33✔
847
};
×
848

849
For& StructuredSDFGBuilder::add_for(
120✔
850
    Sequence& parent,
851
    const symbolic::Symbol& indvar,
852
    const symbolic::Condition& condition,
853
    const symbolic::Expression& init,
854
    const symbolic::Expression& update,
855
    const sdfg::control_flow::Assignments& assignments,
856
    const DebugInfo& debug_info
857
) {
858
    parent.children_
240✔
859
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
120✔
860

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

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

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

871
For& StructuredSDFGBuilder::add_for_before(
6✔
872
    Sequence& parent,
873
    ControlFlowNode& child,
874
    const symbolic::Symbol& indvar,
875
    const symbolic::Condition& condition,
876
    const symbolic::Expression& init,
877
    const symbolic::Expression& update,
878
    const sdfg::control_flow::Assignments& assignments,
879
    const DebugInfo& debug_info
880
) {
881
    int index = parent.index(child);
6✔
882
    if (index == -1) {
6✔
NEW
883
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
884
    }
885

886
    parent.children_.insert(
12✔
887
        parent.children_.begin() + index,
6✔
888
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
889
    );
890

891
    // Increment element id for body node
892
    this->new_element_id();
6✔
893

894
    parent.transitions_.insert(
12✔
895
        parent.transitions_.begin() + index,
6✔
896
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
897
    );
898

899
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
UNCOV
900
};
×
901

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

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

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

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

930
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
UNCOV
931
};
×
932

933
Map& StructuredSDFGBuilder::add_map(
51✔
934
    Sequence& parent,
935
    const symbolic::Symbol& indvar,
936
    const symbolic::Condition& condition,
937
    const symbolic::Expression& init,
938
    const symbolic::Expression& update,
939
    const ScheduleType& schedule_type,
940
    const sdfg::control_flow::Assignments& assignments,
941
    const DebugInfo& debug_info
942
) {
943
    parent.children_
102✔
944
        .push_back(std::unique_ptr<
51✔
945
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
51✔
946

947
    // Increment element id for body node
948
    this->new_element_id();
51✔
949

950
    parent.transitions_
102✔
951
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
51✔
952
        );
953

954
    return static_cast<Map&>(*parent.children_.back().get());
51✔
955
};
×
956

957
Map& StructuredSDFGBuilder::add_map_before(
6✔
958
    Sequence& parent,
959
    ControlFlowNode& child,
960
    const symbolic::Symbol& indvar,
961
    const symbolic::Condition& condition,
962
    const symbolic::Expression& init,
963
    const symbolic::Expression& update,
964
    const ScheduleType& schedule_type,
965
    const sdfg::control_flow::Assignments& assignments,
966
    const DebugInfo& debug_info
967
) {
968
    int index = parent.index(child);
6✔
969
    if (index == -1) {
6✔
NEW
970
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
971
    }
972

973
    parent.children_.insert(
12✔
974
        parent.children_.begin() + index,
6✔
975
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
6✔
976
        )
977
    );
978

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

982
    parent.transitions_.insert(
12✔
983
        parent.transitions_.begin() + index,
6✔
984
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
985
    );
986

987
    return static_cast<Map&>(*parent.children_.at(index).get());
6✔
UNCOV
988
};
×
989

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

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

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

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

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

1023
Continue& StructuredSDFGBuilder::
1024
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
14✔
1025
    // Check if continue is in a loop
1026
    analysis::AnalysisManager analysis_manager(this->subject());
14✔
1027
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
14✔
1028
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
14✔
1029
    bool in_loop = false;
14✔
1030
    while (current_scope != nullptr) {
24✔
1031
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
24✔
1032
            in_loop = true;
14✔
1033
            break;
14✔
1034
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
NEW
1035
            throw UnstructuredControlFlowException();
×
1036
        }
1037
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
1038
    }
1039
    if (!in_loop) {
14✔
NEW
1040
        throw UnstructuredControlFlowException();
×
1041
    }
1042

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

1045
    parent.transitions_
28✔
1046
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
1047
        );
1048

1049
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
1050
};
14✔
1051

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

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

1074
    parent.transitions_
30✔
1075
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
15✔
1076
        );
1077

1078
    return static_cast<Break&>(*parent.children_.back().get());
15✔
1079
};
15✔
1080

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

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

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

1092
For& StructuredSDFGBuilder::convert_while(
×
1093
    Sequence& parent,
1094
    While& loop,
1095
    const symbolic::Symbol& indvar,
1096
    const symbolic::Condition& condition,
1097
    const symbolic::Expression& init,
1098
    const symbolic::Expression& update
1099
) {
NEW
1100
    int index = parent.index(loop);
×
NEW
1101
    if (index == -1) {
×
NEW
1102
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1103
    }
1104

1105
    auto iter = parent.children_.begin() + index;
×
1106
    auto& new_iter = *parent.children_.insert(
×
1107
        iter + 1,
×
1108
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1109
    );
1110

1111
    // Increment element id for body node
1112
    this->new_element_id();
×
1113

1114
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
NEW
1115
    this->move_children(loop.root(), for_loop.root());
×
1116

1117
    // Remove while loop
1118
    parent.children_.erase(parent.children_.begin() + index);
×
1119

1120
    return for_loop;
×
1121
};
×
1122

1123
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
8✔
1124
    int index = parent.index(loop);
8✔
1125
    if (index == -1) {
8✔
NEW
1126
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1127
    }
1128

1129
    auto iter = parent.children_.begin() + index;
8✔
1130
    auto& new_iter = *parent.children_.insert(
16✔
1131
        iter + 1,
8✔
1132
        std::unique_ptr<Map>(new Map(
16✔
1133
            this->new_element_id(),
8✔
1134
            loop.debug_info(),
8✔
1135
            loop.indvar(),
8✔
1136
            loop.init(),
8✔
1137
            loop.update(),
8✔
1138
            loop.condition(),
8✔
1139
            ScheduleType_Sequential
1140
        ))
1141
    );
1142

1143
    // Increment element id for body node
1144
    this->new_element_id();
8✔
1145

1146
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1147
    this->move_children(loop.root(), map.root());
8✔
1148

1149
    // Remove for loop
1150
    parent.children_.erase(parent.children_.begin() + index);
8✔
1151

1152
    return map;
8✔
1153
};
×
1154

1155
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1156
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1157
    while (!queue.empty()) {
2✔
1158
        auto current = queue.front();
2✔
1159
        queue.pop_front();
2✔
1160

1161
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1162
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1163
                if (&sequence_stmt->at(i).first == &node) {
2✔
1164
                    return *sequence_stmt;
2✔
1165
                }
1166
                queue.push_back(&sequence_stmt->at(i).first);
×
1167
            }
×
1168
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1169
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1170
                queue.push_back(&if_else_stmt->at(i).first);
×
1171
            }
×
1172
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1173
            queue.push_back(&while_stmt->root());
×
1174
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1175
            queue.push_back(&loop_stmt->root());
×
1176
        }
×
1177
    }
1178

1179
    return this->structured_sdfg_->root();
×
1180
};
2✔
1181

1182
/***** Section: Dataflow Graph *****/
1183

1184
data_flow::AccessNode& StructuredSDFGBuilder::
1185
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
604✔
1186
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
604✔
1187
    auto res = block.dataflow_->nodes_.insert(
1,208✔
1188
        {vertex,
604✔
1189
         std::unique_ptr<data_flow::AccessNode>(
604✔
1190
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
604✔
1191
         )}
1192
    );
1193

1194
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
604✔
1195
};
×
1196

1197
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
358✔
1198
    structured_control_flow::Block& block,
1199
    const data_flow::TaskletCode code,
1200
    const std::string& output,
1201
    const std::vector<std::string>& inputs,
1202
    const DebugInfo& debug_info
1203
) {
1204
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
358✔
1205
    auto res = block.dataflow_->nodes_.insert(
716✔
1206
        {vertex,
358✔
1207
         std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
716✔
1208
             this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs, symbolic::__true__()
358✔
1209
         ))}
1210
    );
1211

1212
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
358✔
1213
};
×
1214

1215
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
557✔
1216
    structured_control_flow::Block& block,
1217
    data_flow::DataFlowNode& src,
1218
    const std::string& src_conn,
1219
    data_flow::DataFlowNode& dst,
1220
    const std::string& dst_conn,
1221
    const data_flow::Subset& subset,
1222
    const types::IType& base_type,
1223
    const DebugInfo& debug_info
1224
) {
1225
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
557✔
1226
    auto res = block.dataflow_->edges_.insert(
1,114✔
1227
        {edge.first,
1,114✔
1228
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,114✔
1229
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
557✔
1230
         ))}
1231
    );
1232

1233
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
557✔
1234
#ifndef NDEBUG
1235
    memlet.validate(*this->structured_sdfg_);
557✔
1236
#endif
1237

1238
    return memlet;
557✔
1239
};
×
1240

1241
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
41✔
1242
    structured_control_flow::Block& block,
1243
    data_flow::DataFlowNode& src,
1244
    const std::string& src_conn,
1245
    data_flow::DataFlowNode& dst,
1246
    const std::string& dst_conn,
1247
    const data_flow::Subset& begin_subset,
1248
    const data_flow::Subset& end_subset,
1249
    const types::IType& base_type,
1250
    const DebugInfo& debug_info
1251
) {
1252
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
41✔
1253
    auto res = block.dataflow_->edges_.insert(
82✔
1254
        {edge.first,
82✔
1255
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
82✔
1256
             this->new_element_id(),
41✔
1257
             debug_info,
41✔
1258
             edge.first,
41✔
1259
             block.dataflow(),
41✔
1260
             src,
41✔
1261
             src_conn,
41✔
1262
             dst,
41✔
1263
             dst_conn,
41✔
1264
             begin_subset,
41✔
1265
             end_subset,
41✔
1266
             base_type
41✔
1267
         ))}
1268
    );
1269

1270
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
41✔
1271
#ifndef NDEBUG
1272
    memlet.validate(*this->structured_sdfg_);
41✔
1273
#endif
1274

1275
    return memlet;
41✔
1276
};
×
1277

1278
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
95✔
1279
    structured_control_flow::Block& block,
1280
    data_flow::AccessNode& src,
1281
    data_flow::Tasklet& dst,
1282
    const std::string& dst_conn,
1283
    const data_flow::Subset& subset,
1284
    const types::IType& base_type,
1285
    const DebugInfo& debug_info
1286
) {
1287
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
95✔
1288
};
×
1289

1290
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
86✔
1291
    structured_control_flow::Block& block,
1292
    data_flow::Tasklet& src,
1293
    const std::string& src_conn,
1294
    data_flow::AccessNode& dst,
1295
    const data_flow::Subset& subset,
1296
    const types::IType& base_type,
1297
    const DebugInfo& debug_info
1298
) {
1299
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
86✔
1300
};
×
1301

1302
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
91✔
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 DebugInfo& debug_info
1309
) {
1310
    auto& src_type = this->structured_sdfg_->type(src.data());
91✔
1311
    auto& base_type = types::infer_type(*this->structured_sdfg_, src_type, subset);
91✔
1312
    if (base_type.type_id() != types::TypeID::Scalar) {
91✔
1313
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1314
    }
1315
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, src_type, debug_info);
91✔
1316
};
×
1317

1318
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
267✔
1319
    structured_control_flow::Block& block,
1320
    data_flow::Tasklet& src,
1321
    const std::string& src_conn,
1322
    data_flow::AccessNode& dst,
1323
    const data_flow::Subset& subset,
1324
    const DebugInfo& debug_info
1325
) {
1326
    auto& dst_type = this->structured_sdfg_->type(dst.data());
267✔
1327
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
267✔
1328
    if (base_type.type_id() != types::TypeID::Scalar) {
267✔
1329
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1330
    }
1331
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
267✔
1332
};
×
1333

1334
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
14✔
1335
    structured_control_flow::Block& block,
1336
    data_flow::AccessNode& src,
1337
    data_flow::LibraryNode& dst,
1338
    const std::string& dst_conn,
1339
    const data_flow::Subset& begin_subset,
1340
    const data_flow::Subset& end_subset,
1341
    const types::IType& base_type,
1342
    const DebugInfo& debug_info
1343
) {
1344
    return this->add_memlet(block, src, "void", dst, dst_conn, begin_subset, end_subset, base_type, debug_info);
14✔
1345
};
×
1346

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

1360
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
8✔
1361
    structured_control_flow::Block& block,
1362
    data_flow::AccessNode& src,
1363
    data_flow::AccessNode& dst,
1364
    const data_flow::Subset& subset,
1365
    const types::IType& base_type,
1366
    const DebugInfo& debug_info
1367
) {
1368
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
8✔
1369
};
×
1370

1371
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
10✔
1372
    structured_control_flow::Block& block,
1373
    data_flow::AccessNode& src,
1374
    data_flow::AccessNode& dst,
1375
    bool derefs_src,
1376
    const types::IType& base_type,
1377
    const DebugInfo& debug_info
1378
) {
1379
    if (derefs_src) {
10✔
1380
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
5✔
1381
    } else {
1382
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
5✔
1383
    }
1384
};
10✔
1385

1386
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
19✔
1387
    auto& graph = block.dataflow();
19✔
1388
    auto e = edge.edge();
19✔
1389
    boost::remove_edge(e, graph.graph_);
19✔
1390
    graph.edges_.erase(e);
19✔
1391
};
19✔
1392

1393
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
18✔
1394
    auto& graph = block.dataflow();
18✔
1395
    auto v = node.vertex();
18✔
1396
    boost::remove_vertex(v, graph.graph_);
18✔
1397
    graph.nodes_.erase(v);
18✔
1398
};
18✔
1399

1400
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
8✔
1401
    auto& graph = block.dataflow();
8✔
1402

1403
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
8✔
1404

1405
    // Delete incoming
1406
    std::list<const data_flow::Memlet*> iedges;
8✔
1407
    for (auto& iedge : graph.in_edges(node)) {
15✔
1408
        iedges.push_back(&iedge);
7✔
1409
    }
1410
    for (auto iedge : iedges) {
15✔
1411
        auto& src = iedge->src();
7✔
1412
        to_delete.insert(&src);
7✔
1413

1414
        auto edge = iedge->edge();
7✔
1415
        graph.edges_.erase(edge);
7✔
1416
        boost::remove_edge(edge, graph.graph_);
7✔
1417
    }
1418

1419
    // Delete outgoing
1420
    std::list<const data_flow::Memlet*> oedges;
8✔
1421
    for (auto& oedge : graph.out_edges(node)) {
16✔
1422
        oedges.push_back(&oedge);
8✔
1423
    }
1424
    for (auto oedge : oedges) {
16✔
1425
        auto& dst = oedge->dst();
8✔
1426
        to_delete.insert(&dst);
8✔
1427

1428
        auto edge = oedge->edge();
8✔
1429
        graph.edges_.erase(edge);
8✔
1430
        boost::remove_edge(edge, graph.graph_);
8✔
1431
    }
1432

1433
    // Delete nodes
1434
    for (auto obsolete_node : to_delete) {
31✔
1435
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
1436
            auto vertex = obsolete_node->vertex();
23✔
1437
            graph.nodes_.erase(vertex);
23✔
1438
            boost::remove_vertex(vertex, graph.graph_);
23✔
1439
        }
23✔
1440
    }
1441
};
8✔
1442

1443
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
1✔
1444
    auto& graph = block.dataflow();
1✔
1445
    if (graph.out_degree(node) != 0) {
1✔
1446
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1447
    }
1448

1449
    std::list<const data_flow::Memlet*> tmp;
1✔
1450
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
1451
    while (!queue.empty()) {
3✔
1452
        auto current = queue.front();
2✔
1453
        queue.pop_front();
2✔
1454
        if (current != &node) {
2✔
1455
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
1456
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1457
                    continue;
×
1458
                }
1459
            }
×
1460
        }
1✔
1461

1462
        tmp.clear();
2✔
1463
        for (auto& iedge : graph.in_edges(*current)) {
3✔
1464
            tmp.push_back(&iedge);
1✔
1465
        }
1466
        for (auto iedge : tmp) {
3✔
1467
            auto& src = iedge->src();
1✔
1468
            queue.push_back(&src);
1✔
1469

1470
            auto edge = iedge->edge();
1✔
1471
            graph.edges_.erase(edge);
1✔
1472
            boost::remove_edge(edge, graph.graph_);
1✔
1473
        }
1474

1475
        auto vertex = current->vertex();
2✔
1476
        graph.nodes_.erase(vertex);
2✔
1477
        boost::remove_vertex(vertex, graph.graph_);
2✔
1478
    }
1479
};
1✔
1480

1481
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
18✔
1482
    auto& to_dataflow = to.dataflow();
18✔
1483

1484
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
18✔
1485
    for (auto& entry : from.nodes_) {
19✔
1486
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1487
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1488
        node_mapping.insert({entry.first, vertex});
1✔
1489
    }
1490

1491
    for (auto& entry : from.edges_) {
18✔
1492
        auto src = node_mapping[entry.second->src().vertex()];
×
1493
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1494

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

1497
        to_dataflow.edges_.insert(
×
1498
            {edge.first,
×
1499
             entry.second->clone(
×
1500
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1501
             )}
1502
        );
1503
    }
1504
};
18✔
1505

1506
} // namespace builder
1507
} // 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