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

daisytuner / sdfglib / 17316805645

29 Aug 2025 06:46AM UTC coverage: 60.01% (+0.2%) from 59.781%
17316805645

Pull #210

github

web-flow
Merge cd9cb386d into 18d34db1e
Pull Request #210: New debug info

351 of 562 new or added lines in 37 files covered. (62.46%)

15 existing lines in 8 files now uncovered.

9574 of 15954 relevant lines covered (60.01%)

115.01 hits per line

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

80.07
/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/data_flow/library_node.h"
7
#include "sdfg/debug_info.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
        DebugInfoRegion dbg_info = current->debug_info();
1✔
152
        for (auto& edge : in_edges) {
3✔
153
            dbg_info =
2✔
154
                DebugInfoRegion::merge(dbg_info, edge.debug_info(), this->structured_sdfg_->debug_info().instructions());
2✔
155
        }
156
        for (auto node : body) {
4✔
157
            dbg_info =
3✔
158
                DebugInfoRegion::merge(dbg_info, node->debug_info(), this->structured_sdfg_->debug_info().instructions());
3✔
159
        }
160
        for (auto edge : exit_edges) {
2✔
161
            dbg_info =
1✔
162
                DebugInfoRegion::merge(dbg_info, edge->debug_info(), this->structured_sdfg_->debug_info().instructions());
1✔
163
        }
164

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

298
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
5,639✔
299

300
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
78✔
301
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
78✔
302

303
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type, const DebugInfo& debug_info)
518✔
304
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type, debug_info)) {};
518✔
305

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

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

316
    for (auto& arg : sdfg.arguments_) {
6✔
317
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
318
    }
319

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

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

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

333
    this->traverse(sdfg);
4✔
334
};
4✔
335

336
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
993✔
337

338
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
420✔
339
#ifndef NDEBUG
340
    this->structured_sdfg_->validate();
420✔
341
#endif
342

343
    return std::move(this->structured_sdfg_);
420✔
344
};
345

346
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
14✔
347
    auto& sdfg = this->subject();
14✔
348
    std::list<Element*> queue = {&sdfg.root()};
14✔
349
    while (!queue.empty()) {
57✔
350
        auto current = queue.front();
57✔
351
        queue.pop_front();
57✔
352

353
        if (current->element_id() == element_id) {
57✔
354
            return current;
14✔
355
        }
356

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

389
    return nullptr;
×
390
};
14✔
391

392
Sequence& StructuredSDFGBuilder::add_sequence(
39✔
393
    Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfoRegion& debug_info
394
) {
395
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
39✔
396

397
    parent.transitions_
78✔
398
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
39✔
399
        );
400

401
    return static_cast<Sequence&>(*parent.children_.back().get());
39✔
402
};
×
403

404
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
405
    add_sequence_before(Sequence& parent, ControlFlowNode& block, const DebugInfoRegion& debug_info) {
18✔
406
    // Insert block before current block
407
    int index = -1;
18✔
408
    for (size_t i = 0; i < parent.children_.size(); i++) {
18✔
409
        if (parent.children_.at(i).get() == &block) {
18✔
410
            index = i;
18✔
411
            break;
18✔
412
        }
413
    }
×
414
    if (index == -1) {
18✔
415
        throw InvalidSDFGException("StructuredSDFGBuilder: Block not found");
×
416
    }
417

418
    parent.children_.insert(
36✔
419
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
18✔
420
    );
421

422
    parent.transitions_.insert(
36✔
423
        parent.transitions_.begin() + index,
18✔
424
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
18✔
425
    );
426

427
    auto new_entry = parent.at(index);
18✔
428
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
18✔
429

430
    return {new_block, new_entry.second};
18✔
431
};
×
432

433
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t i) {
11✔
434
    parent.children_.erase(parent.children_.begin() + i);
11✔
435
    parent.transitions_.erase(parent.transitions_.begin() + i);
11✔
436
};
11✔
437

438
void StructuredSDFGBuilder::remove_child(Sequence& parent, ControlFlowNode& child) {
24✔
439
    int index = -1;
24✔
440
    for (size_t i = 0; i < parent.children_.size(); i++) {
38✔
441
        if (parent.children_.at(i).get() == &child) {
38✔
442
            index = i;
24✔
443
            break;
24✔
444
        }
445
    }
14✔
446

447
    parent.children_.erase(parent.children_.begin() + index);
24✔
448
    parent.transitions_.erase(parent.transitions_.begin() + index);
24✔
449
};
24✔
450

451
void StructuredSDFGBuilder::insert_children(Sequence& parent, Sequence& other, size_t i) {
25✔
452
    parent.children_.insert(
50✔
453
        parent.children_.begin() + i,
25✔
454
        std::make_move_iterator(other.children_.begin()),
25✔
455
        std::make_move_iterator(other.children_.end())
25✔
456
    );
457
    parent.transitions_.insert(
50✔
458
        parent.transitions_.begin() + i,
25✔
459
        std::make_move_iterator(other.transitions_.begin()),
25✔
460
        std::make_move_iterator(other.transitions_.end())
25✔
461
    );
462
    for (auto& trans : parent.transitions_) {
55✔
463
        trans->parent_ = &parent;
30✔
464
    }
465
    other.children_.clear();
25✔
466
    other.transitions_.clear();
25✔
467
};
25✔
468

469
void StructuredSDFGBuilder::
470
    insert(ControlFlowNode& node, Sequence& source, Sequence& target, const DebugInfoRegion& debug_info) {
9✔
471
    // Insert node into target sequence
472
    int index = -1;
9✔
473
    for (size_t i = 0; i < source.children_.size(); i++) {
18✔
474
        if (source.children_.at(i).get() == &node) {
18✔
475
            index = i;
9✔
476
            break;
9✔
477
        }
478
    }
9✔
479
    if (index == -1) {
9✔
480
        throw InvalidSDFGException("StructuredSDFGBuilder: Node not found in source sequence");
×
481
    }
482

483
    auto node_ptr = std::move(source.children_.at(index));
9✔
484
    source.children_.erase(source.children_.begin() + index);
9✔
485
    source.transitions_.erase(source.transitions_.begin() + index);
9✔
486

487
    target.children_.push_back(std::move(node_ptr));
9✔
488
    target.transitions_.push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, target)
9✔
489
    ));
490
};
9✔
491

492
Block& StructuredSDFGBuilder::
493
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfoRegion& debug_info) {
498✔
494
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
498✔
495

496
    parent.transitions_
996✔
497
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
498✔
498
        );
499

500
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
498✔
501
    (*new_block.dataflow_).parent_ = &new_block;
498✔
502

503
    return new_block;
498✔
504
};
×
505

506
Block& StructuredSDFGBuilder::add_block(
18✔
507
    Sequence& parent,
508
    const data_flow::DataFlowGraph& data_flow_graph,
509
    const sdfg::control_flow::Assignments& assignments,
510
    const DebugInfoRegion& debug_info
511
) {
512
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
18✔
513

514
    parent.transitions_
36✔
515
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
18✔
516
        );
517

518
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
18✔
519
    (*new_block.dataflow_).parent_ = &new_block;
18✔
520

521
    this->add_dataflow(data_flow_graph, new_block);
18✔
522

523
    return new_block;
18✔
524
};
×
525

526
std::pair<Block&, Transition&> StructuredSDFGBuilder::
527
    add_block_before(Sequence& parent, ControlFlowNode& block, const DebugInfoRegion& debug_info) {
11✔
528
    // Insert block before current block
529
    int index = -1;
11✔
530
    for (size_t i = 0; i < parent.children_.size(); i++) {
11✔
531
        if (parent.children_.at(i).get() == &block) {
11✔
532
            index = i;
11✔
533
            break;
11✔
534
        }
535
    }
×
536
    assert(index > -1);
11✔
537

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

541
    parent.transitions_.insert(
22✔
542
        parent.transitions_.begin() + index,
11✔
543
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
11✔
544
    );
545

546
    auto new_entry = parent.at(index);
11✔
547
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
11✔
548
    (*new_block.dataflow_).parent_ = &new_block;
11✔
549

550
    return {new_block, new_entry.second};
11✔
551
};
×
552

553
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
554
    Sequence& parent,
555
    ControlFlowNode& block,
556
    data_flow::DataFlowGraph& data_flow_graph,
557
    const DebugInfoRegion& debug_info
558
) {
559
    // Insert block before current block
560
    int index = -1;
×
561
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
562
        if (parent.children_.at(i).get() == &block) {
×
563
            index = i;
×
564
            break;
×
565
        }
566
    }
×
567
    assert(index > -1);
×
568

569
    parent.children_
×
570
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
571

572
    parent.transitions_.insert(
×
573
        parent.transitions_.begin() + index,
×
574
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
575
    );
576

577
    auto new_entry = parent.at(index);
×
578
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
579
    (*new_block.dataflow_).parent_ = &new_block;
×
580

581
    this->add_dataflow(data_flow_graph, new_block);
×
582

583
    return {new_block, new_entry.second};
×
584
};
×
585

586
std::pair<Block&, Transition&> StructuredSDFGBuilder::
587
    add_block_after(Sequence& parent, ControlFlowNode& block, const DebugInfoRegion& debug_info) {
3✔
588
    // Insert block before current block
589
    int index = -1;
3✔
590
    for (size_t i = 0; i < parent.children_.size(); i++) {
5✔
591
        if (parent.children_.at(i).get() == &block) {
5✔
592
            index = i;
3✔
593
            break;
3✔
594
        }
595
    }
2✔
596
    assert(index > -1);
3✔
597

598
    parent.children_.insert(
6✔
599
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3✔
600
    );
601

602
    parent.transitions_.insert(
6✔
603
        parent.transitions_.begin() + index + 1,
3✔
604
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
3✔
605
    );
606

607
    auto new_entry = parent.at(index + 1);
3✔
608
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
3✔
609
    (*new_block.dataflow_).parent_ = &new_block;
3✔
610

611
    return {new_block, new_entry.second};
3✔
612
};
×
613

614
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
615
    Sequence& parent,
616
    ControlFlowNode& block,
617
    data_flow::DataFlowGraph& data_flow_graph,
618
    const DebugInfoRegion& debug_info
619
) {
620
    int index = -1;
×
621
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
622
        if (parent.children_.at(i).get() == &block) {
×
623
            index = i;
×
624
            break;
×
625
        }
626
    }
×
627
    assert(index > -1);
×
628

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

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

638
    auto new_entry = parent.at(index + 1);
×
639
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
640
    (*new_block.dataflow_).parent_ = &new_block;
×
641

642
    this->add_dataflow(data_flow_graph, new_block);
×
643

644
    return {new_block, new_entry.second};
×
645
};
×
646

647
For& StructuredSDFGBuilder::add_for(
122✔
648
    Sequence& parent,
649
    const symbolic::Symbol& indvar,
650
    const symbolic::Condition& condition,
651
    const symbolic::Expression& init,
652
    const symbolic::Expression& update,
653
    const sdfg::control_flow::Assignments& assignments,
654
    const DebugInfoRegion& debug_info
655
) {
656
    parent.children_
244✔
657
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
122✔
658

659
    // Increment element id for body node
660
    this->new_element_id();
122✔
661

662
    parent.transitions_
244✔
663
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
122✔
664
        );
665

666
    return static_cast<For&>(*parent.children_.back().get());
122✔
667
};
×
668

669
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_before(
9✔
670
    Sequence& parent,
671
    ControlFlowNode& block,
672
    const symbolic::Symbol& indvar,
673
    const symbolic::Condition& condition,
674
    const symbolic::Expression& init,
675
    const symbolic::Expression& update,
676
    const DebugInfoRegion& debug_info
677
) {
678
    // Insert block before current block
679
    int index = -1;
9✔
680
    for (size_t i = 0; i < parent.children_.size(); i++) {
9✔
681
        if (parent.children_.at(i).get() == &block) {
9✔
682
            index = i;
9✔
683
            break;
9✔
684
        }
685
    }
×
686
    assert(index > -1);
9✔
687

688
    parent.children_.insert(
18✔
689
        parent.children_.begin() + index,
9✔
690
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
9✔
691
    );
692

693
    // Increment element id for body node
694
    this->new_element_id();
9✔
695

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

701
    auto new_entry = parent.at(index);
9✔
702
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
9✔
703

704
    return {new_block, new_entry.second};
9✔
705
};
×
706

707
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_after(
6✔
708
    Sequence& parent,
709
    ControlFlowNode& block,
710
    const symbolic::Symbol& indvar,
711
    const symbolic::Condition& condition,
712
    const symbolic::Expression& init,
713
    const symbolic::Expression& update,
714
    const DebugInfoRegion& debug_info
715
) {
716
    // Insert block before current block
717
    int index = -1;
6✔
718
    for (size_t i = 0; i < parent.children_.size(); i++) {
11✔
719
        if (parent.children_.at(i).get() == &block) {
11✔
720
            index = i;
6✔
721
            break;
6✔
722
        }
723
    }
5✔
724
    assert(index > -1);
6✔
725

726
    parent.children_.insert(
12✔
727
        parent.children_.begin() + index + 1,
6✔
728
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
729
    );
730

731
    // Increment element id for body node
732
    this->new_element_id();
6✔
733

734
    parent.transitions_.insert(
12✔
735
        parent.transitions_.begin() + index + 1,
6✔
736
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
6✔
737
    );
738

739
    auto new_entry = parent.at(index + 1);
6✔
740
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
6✔
741

742
    return {new_block, new_entry.second};
6✔
743
};
×
744

745
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent, const DebugInfoRegion& debug_info) {
41✔
746
    return this->add_if_else(parent, control_flow::Assignments{}, debug_info);
41✔
747
};
×
748

749
IfElse& StructuredSDFGBuilder::add_if_else(
48✔
750
    Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfoRegion& debug_info
751
) {
752
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
48✔
753

754
    parent.transitions_
96✔
755
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
48✔
756
        );
757

758
    return static_cast<IfElse&>(*parent.children_.back().get());
48✔
759
};
×
760

761
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
762
    add_if_else_before(Sequence& parent, ControlFlowNode& block, const DebugInfoRegion& debug_info) {
1✔
763
    // Insert block before current block
764
    int index = -1;
1✔
765
    for (size_t i = 0; i < parent.children_.size(); i++) {
1✔
766
        if (parent.children_.at(i).get() == &block) {
1✔
767
            index = i;
1✔
768
            break;
1✔
769
        }
770
    }
×
771
    assert(index > -1);
1✔
772

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

776
    parent.transitions_.insert(
2✔
777
        parent.transitions_.begin() + index,
1✔
778
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
1✔
779
    );
780

781
    auto new_entry = parent.at(index);
1✔
782
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
1✔
783

784
    return {new_block, new_entry.second};
1✔
785
};
×
786

787
Sequence& StructuredSDFGBuilder::
788
    add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfoRegion& debug_info) {
80✔
789
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
80✔
790

791
    scope.conditions_.push_back(cond);
80✔
792
    return *scope.cases_.back();
80✔
793
};
×
794

795
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t i, const DebugInfoRegion& debug_info) {
4✔
796
    scope.cases_.erase(scope.cases_.begin() + i);
4✔
797
    scope.conditions_.erase(scope.conditions_.begin() + i);
4✔
798
};
4✔
799

800
While& StructuredSDFGBuilder::
801
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfoRegion& debug_info) {
33✔
802
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
33✔
803

804
    // Increment element id for body node
805
    this->new_element_id();
33✔
806

807
    parent.transitions_
66✔
808
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
33✔
809
        );
810

811
    return static_cast<While&>(*parent.children_.back().get());
33✔
812
};
×
813

814
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent, const DebugInfoRegion& debug_info) {
12✔
815
    return this->add_continue(parent, control_flow::Assignments{}, debug_info);
12✔
816
};
×
817

818
Continue& StructuredSDFGBuilder::add_continue(
14✔
819
    Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfoRegion& debug_info
820
) {
821
    // Check if continue is in a loop
822
    analysis::AnalysisManager analysis_manager(this->subject());
14✔
823
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
14✔
824
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
14✔
825
    bool in_loop = false;
14✔
826
    while (current_scope != nullptr) {
24✔
827
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
24✔
828
            in_loop = true;
14✔
829
            break;
14✔
830
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
831
            throw UnstructuredControlFlowException();
×
832
        }
833
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
834
    }
835
    if (!in_loop) {
14✔
836
        throw UnstructuredControlFlowException();
×
837
    }
838

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

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

845
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
846
};
14✔
847

848
Break& StructuredSDFGBuilder::add_break(Sequence& parent, const DebugInfoRegion& debug_info) {
13✔
849
    return this->add_break(parent, control_flow::Assignments{}, debug_info);
13✔
850
};
×
851

852
Break& StructuredSDFGBuilder::
853
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfoRegion& debug_info) {
15✔
854
    // Check if break is in a loop
855
    analysis::AnalysisManager analysis_manager(this->subject());
15✔
856
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
15✔
857
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
15✔
858
    bool in_loop = false;
15✔
859
    while (current_scope != nullptr) {
25✔
860
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
25✔
861
            in_loop = true;
15✔
862
            break;
15✔
863
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
864
            throw UnstructuredControlFlowException();
×
865
        }
866
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
867
    }
868
    if (!in_loop) {
15✔
869
        throw UnstructuredControlFlowException();
×
870
    }
871

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

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

878
    return static_cast<Break&>(*parent.children_.back().get());
15✔
879
};
15✔
880

881
Return& StructuredSDFGBuilder::add_return(
14✔
882
    Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfoRegion& debug_info
883
) {
884
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info)));
14✔
885

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

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

893
Map& StructuredSDFGBuilder::add_map(
48✔
894
    Sequence& parent,
895
    const symbolic::Symbol& indvar,
896
    const symbolic::Condition& condition,
897
    const symbolic::Expression& init,
898
    const symbolic::Expression& update,
899
    const ScheduleType& schedule_type,
900
    const sdfg::control_flow::Assignments& assignments,
901
    const DebugInfoRegion& debug_info
902
) {
903
    parent.children_
96✔
904
        .push_back(std::unique_ptr<
48✔
905
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
48✔
906

907
    // Increment element id for body node
908
    this->new_element_id();
48✔
909

910
    parent.transitions_
96✔
911
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
48✔
912
        );
913

914
    return static_cast<Map&>(*parent.children_.back().get());
48✔
915
};
×
916

917
std::pair<Map&, Transition&> StructuredSDFGBuilder::add_map_before(
6✔
918
    Sequence& parent,
919
    ControlFlowNode& block,
920
    const symbolic::Symbol& indvar,
921
    const symbolic::Condition& condition,
922
    const symbolic::Expression& init,
923
    const symbolic::Expression& update,
924
    const ScheduleType& schedule_type,
925
    const sdfg::control_flow::Assignments& assignments,
926
    const DebugInfoRegion& debug_info
927
) {
928
    // Insert block before current block
929
    int index = -1;
6✔
930
    for (size_t i = 0; i < parent.children_.size(); i++) {
6✔
931
        if (parent.children_.at(i).get() == &block) {
6✔
932
            index = i;
6✔
933
            break;
6✔
934
        }
935
    }
×
936
    assert(index > -1);
6✔
937

938
    parent.children_.insert(
12✔
939
        parent.children_.begin() + index,
6✔
940
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
6✔
941
        )
942
    );
943

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

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

952
    auto new_entry = parent.at(index);
6✔
953
    auto& new_block = dynamic_cast<structured_control_flow::Map&>(new_entry.first);
6✔
954

955
    return {new_block, new_entry.second};
6✔
956
};
×
957

958
std::pair<Map&, Transition&> StructuredSDFGBuilder::add_map_after(
10✔
959
    Sequence& parent,
960
    ControlFlowNode& block,
961
    const symbolic::Symbol& indvar,
962
    const symbolic::Condition& condition,
963
    const symbolic::Expression& init,
964
    const symbolic::Expression& update,
965
    const ScheduleType& schedule_type,
966
    const sdfg::control_flow::Assignments& assignments,
967
    const DebugInfoRegion& debug_info
968
) {
969
    // Insert block before current block
970
    int index = -1;
10✔
971
    for (size_t i = 0; i < parent.children_.size(); i++) {
10✔
972
        if (parent.children_.at(i).get() == &block) {
10✔
973
            index = i;
10✔
974
            break;
10✔
975
        }
976
    }
×
977
    assert(index > -1);
10✔
978

979
    parent.children_.insert(
20✔
980
        parent.children_.begin() + index + 1,
10✔
981
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
10✔
982
        )
983
    );
984

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

988
    parent.transitions_.insert(
20✔
989
        parent.transitions_.begin() + index + 1,
10✔
990
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
10✔
991
    );
992

993
    auto new_entry = parent.at(index + 1);
10✔
994
    auto& new_block = dynamic_cast<structured_control_flow::Map&>(new_entry.first);
10✔
995

996
    return {new_block, new_entry.second};
10✔
997
};
×
998

999
For& StructuredSDFGBuilder::convert_while(
×
1000
    Sequence& parent,
1001
    While& loop,
1002
    const symbolic::Symbol& indvar,
1003
    const symbolic::Condition& condition,
1004
    const symbolic::Expression& init,
1005
    const symbolic::Expression& update
1006
) {
1007
    // Insert for loop
1008
    size_t index = 0;
×
1009
    for (auto& entry : parent.children_) {
×
1010
        if (entry.get() == &loop) {
×
1011
            break;
×
1012
        }
1013
        index++;
×
1014
    }
1015
    auto iter = parent.children_.begin() + index;
×
1016
    auto& new_iter = *parent.children_.insert(
×
1017
        iter + 1,
×
1018
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1019
    );
1020

1021
    // Increment element id for body node
1022
    this->new_element_id();
×
1023

1024
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1025
    this->insert_children(for_loop.root(), loop.root(), 0);
×
1026

1027
    // Remove while loop
1028
    parent.children_.erase(parent.children_.begin() + index);
×
1029

1030
    return for_loop;
×
1031
};
×
1032

1033
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
8✔
1034
    // Insert for loop
1035
    size_t index = 0;
8✔
1036
    for (auto& entry : parent.children_) {
8✔
1037
        if (entry.get() == &loop) {
8✔
1038
            break;
8✔
1039
        }
1040
        index++;
×
1041
    }
1042
    auto iter = parent.children_.begin() + index;
8✔
1043
    auto& new_iter = *parent.children_.insert(
16✔
1044
        iter + 1,
8✔
1045
        std::unique_ptr<Map>(new Map(
16✔
1046
            this->new_element_id(),
8✔
1047
            loop.debug_info(),
8✔
1048
            loop.indvar(),
8✔
1049
            loop.init(),
8✔
1050
            loop.update(),
8✔
1051
            loop.condition(),
8✔
1052
            ScheduleType_Sequential
1053
        ))
1054
    );
1055

1056
    // Increment element id for body node
1057
    this->new_element_id();
8✔
1058

1059
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1060
    this->insert_children(map.root(), loop.root(), 0);
8✔
1061

1062
    // Remove for loop
1063
    parent.children_.erase(parent.children_.begin() + index);
8✔
1064

1065
    return map;
8✔
1066
};
×
1067

1068
void StructuredSDFGBuilder::clear_sequence(Sequence& parent) {
×
1069
    parent.children_.clear();
×
1070
    parent.transitions_.clear();
×
1071
};
×
1072

1073
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1074
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1075
    while (!queue.empty()) {
2✔
1076
        auto current = queue.front();
2✔
1077
        queue.pop_front();
2✔
1078

1079
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1080
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1081
                if (&sequence_stmt->at(i).first == &node) {
2✔
1082
                    return *sequence_stmt;
2✔
1083
                }
1084
                queue.push_back(&sequence_stmt->at(i).first);
×
1085
            }
×
1086
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1087
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1088
                queue.push_back(&if_else_stmt->at(i).first);
×
1089
            }
×
1090
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1091
            queue.push_back(&while_stmt->root());
×
1092
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1093
            queue.push_back(&loop_stmt->root());
×
1094
        }
×
1095
    }
1096

1097
    return this->structured_sdfg_->root();
×
1098
};
2✔
1099

1100
/***** Section: Dataflow Graph *****/
1101

1102
data_flow::AccessNode& StructuredSDFGBuilder::
1103
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfoRegion& debug_info) {
599✔
1104
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
599✔
1105
    auto res = block.dataflow_->nodes_.insert(
1,198✔
1106
        {vertex,
599✔
1107
         std::unique_ptr<data_flow::AccessNode>(
599✔
1108
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
599✔
1109
         )}
1110
    );
1111

1112
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
599✔
1113
};
×
1114

1115
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
356✔
1116
    structured_control_flow::Block& block,
1117
    const data_flow::TaskletCode code,
1118
    const std::string& output,
1119
    const std::vector<std::string>& inputs,
1120
    const DebugInfoRegion& debug_info
1121
) {
1122
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
356✔
1123
    auto res = block.dataflow_->nodes_.insert(
712✔
1124
        {vertex,
356✔
1125
         std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
712✔
1126
             this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs, symbolic::__true__()
356✔
1127
         ))}
1128
    );
1129

1130
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
356✔
1131
};
×
1132

1133
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
552✔
1134
    structured_control_flow::Block& block,
1135
    data_flow::DataFlowNode& src,
1136
    const std::string& src_conn,
1137
    data_flow::DataFlowNode& dst,
1138
    const std::string& dst_conn,
1139
    const data_flow::Subset& subset,
1140
    const types::IType& base_type,
1141
    const DebugInfoRegion& debug_info
1142
) {
1143
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
552✔
1144
    auto res = block.dataflow_->edges_.insert(
1,104✔
1145
        {edge.first,
1,104✔
1146
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,104✔
1147
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
552✔
1148
         ))}
1149
    );
1150

1151
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
552✔
1152
#ifndef NDEBUG
1153
    memlet.validate(*this->structured_sdfg_);
552✔
1154
#endif
1155

1156
    return memlet;
552✔
1157
};
×
1158

1159
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
41✔
1160
    structured_control_flow::Block& block,
1161
    data_flow::DataFlowNode& src,
1162
    const std::string& src_conn,
1163
    data_flow::DataFlowNode& dst,
1164
    const std::string& dst_conn,
1165
    const data_flow::Subset& begin_subset,
1166
    const data_flow::Subset& end_subset,
1167
    const types::IType& base_type,
1168
    const DebugInfoRegion& debug_info
1169
) {
1170
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
41✔
1171
    auto res = block.dataflow_->edges_.insert(
82✔
1172
        {edge.first,
82✔
1173
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
82✔
1174
             this->new_element_id(),
41✔
1175
             debug_info,
41✔
1176
             edge.first,
41✔
1177
             block.dataflow(),
41✔
1178
             src,
41✔
1179
             src_conn,
41✔
1180
             dst,
41✔
1181
             dst_conn,
41✔
1182
             begin_subset,
41✔
1183
             end_subset,
41✔
1184
             base_type
41✔
1185
         ))}
1186
    );
1187

1188
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
41✔
1189
#ifndef NDEBUG
1190
    memlet.validate(*this->structured_sdfg_);
41✔
1191
#endif
1192

1193
    return memlet;
41✔
1194
};
×
1195

1196
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
93✔
1197
    structured_control_flow::Block& block,
1198
    data_flow::AccessNode& src,
1199
    data_flow::Tasklet& dst,
1200
    const std::string& dst_conn,
1201
    const data_flow::Subset& subset,
1202
    const types::IType& base_type,
1203
    const DebugInfoRegion& debug_info
1204
) {
1205
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
93✔
1206
};
×
1207

1208
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
84✔
1209
    structured_control_flow::Block& block,
1210
    data_flow::Tasklet& src,
1211
    const std::string& src_conn,
1212
    data_flow::AccessNode& dst,
1213
    const data_flow::Subset& subset,
1214
    const types::IType& base_type,
1215
    const DebugInfoRegion& debug_info
1216
) {
1217
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
84✔
1218
};
×
1219

1220
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
90✔
1221
    structured_control_flow::Block& block,
1222
    data_flow::AccessNode& src,
1223
    data_flow::Tasklet& dst,
1224
    const std::string& dst_conn,
1225
    const data_flow::Subset& subset,
1226
    const DebugInfoRegion& debug_info
1227
) {
1228
    auto& src_type = this->structured_sdfg_->type(src.data());
90✔
1229
    auto& base_type = types::infer_type(*this->structured_sdfg_, src_type, subset);
90✔
1230
    if (base_type.type_id() != types::TypeID::Scalar) {
90✔
1231
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1232
    }
1233
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, src_type, debug_info);
90✔
1234
};
×
1235

1236
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
267✔
1237
    structured_control_flow::Block& block,
1238
    data_flow::Tasklet& src,
1239
    const std::string& src_conn,
1240
    data_flow::AccessNode& dst,
1241
    const data_flow::Subset& subset,
1242
    const DebugInfoRegion& debug_info
1243
) {
1244
    auto& dst_type = this->structured_sdfg_->type(dst.data());
267✔
1245
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
267✔
1246
    if (base_type.type_id() != types::TypeID::Scalar) {
267✔
1247
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1248
    }
1249
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
267✔
1250
};
×
1251

1252
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
14✔
1253
    structured_control_flow::Block& block,
1254
    data_flow::AccessNode& src,
1255
    data_flow::LibraryNode& dst,
1256
    const std::string& dst_conn,
1257
    const data_flow::Subset& begin_subset,
1258
    const data_flow::Subset& end_subset,
1259
    const types::IType& base_type,
1260
    const DebugInfoRegion& debug_info
1261
) {
1262
    return this->add_memlet(block, src, "void", dst, dst_conn, begin_subset, end_subset, base_type, debug_info);
14✔
1263
};
×
1264

1265
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
9✔
1266
    structured_control_flow::Block& block,
1267
    data_flow::LibraryNode& src,
1268
    const std::string& src_conn,
1269
    data_flow::AccessNode& dst,
1270
    const data_flow::Subset& begin_subset,
1271
    const data_flow::Subset& end_subset,
1272
    const types::IType& base_type,
1273
    const DebugInfoRegion& debug_info
1274
) {
1275
    return this->add_memlet(block, src, src_conn, dst, "void", begin_subset, end_subset, base_type, debug_info);
9✔
1276
};
×
1277

1278
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
8✔
1279
    structured_control_flow::Block& block,
1280
    data_flow::AccessNode& src,
1281
    data_flow::AccessNode& dst,
1282
    const data_flow::Subset& subset,
1283
    const types::IType& base_type,
1284
    const DebugInfoRegion& debug_info
1285
) {
1286
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
8✔
1287
};
×
1288

1289
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
10✔
1290
    structured_control_flow::Block& block,
1291
    data_flow::AccessNode& src,
1292
    data_flow::AccessNode& dst,
1293
    bool derefs_src,
1294
    const types::IType& base_type,
1295
    const DebugInfoRegion& debug_info
1296
) {
1297
    if (derefs_src) {
10✔
1298
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
5✔
1299
    } else {
1300
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
5✔
1301
    }
1302
};
10✔
1303

1304
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
19✔
1305
    auto& graph = block.dataflow();
19✔
1306
    auto e = edge.edge();
19✔
1307
    boost::remove_edge(e, graph.graph_);
19✔
1308
    graph.edges_.erase(e);
19✔
1309
};
19✔
1310

1311
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
18✔
1312
    auto& graph = block.dataflow();
18✔
1313
    auto v = node.vertex();
18✔
1314
    boost::remove_vertex(v, graph.graph_);
18✔
1315
    graph.nodes_.erase(v);
18✔
1316
};
18✔
1317

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

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

1323
    // Delete incoming
1324
    std::list<const data_flow::Memlet*> iedges;
8✔
1325
    for (auto& iedge : graph.in_edges(node)) {
15✔
1326
        iedges.push_back(&iedge);
7✔
1327
    }
1328
    for (auto iedge : iedges) {
15✔
1329
        auto& src = iedge->src();
7✔
1330
        to_delete.insert(&src);
7✔
1331

1332
        auto edge = iedge->edge();
7✔
1333
        graph.edges_.erase(edge);
7✔
1334
        boost::remove_edge(edge, graph.graph_);
7✔
1335
    }
1336

1337
    // Delete outgoing
1338
    std::list<const data_flow::Memlet*> oedges;
8✔
1339
    for (auto& oedge : graph.out_edges(node)) {
16✔
1340
        oedges.push_back(&oedge);
8✔
1341
    }
1342
    for (auto oedge : oedges) {
16✔
1343
        auto& dst = oedge->dst();
8✔
1344
        to_delete.insert(&dst);
8✔
1345

1346
        auto edge = oedge->edge();
8✔
1347
        graph.edges_.erase(edge);
8✔
1348
        boost::remove_edge(edge, graph.graph_);
8✔
1349
    }
1350

1351
    // Delete nodes
1352
    for (auto obsolete_node : to_delete) {
31✔
1353
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
1354
            auto vertex = obsolete_node->vertex();
23✔
1355
            graph.nodes_.erase(vertex);
23✔
1356
            boost::remove_vertex(vertex, graph.graph_);
23✔
1357
        }
23✔
1358
    }
1359
};
8✔
1360

1361
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
1✔
1362
    auto& graph = block.dataflow();
1✔
1363
    if (graph.out_degree(node) != 0) {
1✔
1364
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1365
    }
1366

1367
    std::list<const data_flow::Memlet*> tmp;
1✔
1368
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
1369
    while (!queue.empty()) {
3✔
1370
        auto current = queue.front();
2✔
1371
        queue.pop_front();
2✔
1372
        if (current != &node) {
2✔
1373
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
1374
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1375
                    continue;
×
1376
                }
1377
            }
×
1378
        }
1✔
1379

1380
        tmp.clear();
2✔
1381
        for (auto& iedge : graph.in_edges(*current)) {
3✔
1382
            tmp.push_back(&iedge);
1✔
1383
        }
1384
        for (auto iedge : tmp) {
3✔
1385
            auto& src = iedge->src();
1✔
1386
            queue.push_back(&src);
1✔
1387

1388
            auto edge = iedge->edge();
1✔
1389
            graph.edges_.erase(edge);
1✔
1390
            boost::remove_edge(edge, graph.graph_);
1✔
1391
        }
1392

1393
        auto vertex = current->vertex();
2✔
1394
        graph.nodes_.erase(vertex);
2✔
1395
        boost::remove_vertex(vertex, graph.graph_);
2✔
1396
    }
1397
};
1✔
1398

1399
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
18✔
1400
    auto& to_dataflow = to.dataflow();
18✔
1401

1402
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
18✔
1403
    for (auto& entry : from.nodes_) {
19✔
1404
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1405
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1406
        node_mapping.insert({entry.first, vertex});
1✔
1407
    }
1408

1409
    for (auto& entry : from.edges_) {
18✔
1410
        auto src = node_mapping[entry.second->src().vertex()];
×
1411
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1412

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

1415
        to_dataflow.edges_.insert(
×
1416
            {edge.first,
×
1417
             entry.second->clone(
×
1418
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1419
             )}
1420
        );
1421
    }
1422
};
18✔
1423

1424
size_t StructuredSDFGBuilder::add_debug_info_element(const DebugInfoElement& element) {
3✔
1425
    return structured_sdfg_->debug_info().add_element(element);
3✔
NEW
1426
}
×
1427

1428
const DebugInfo& StructuredSDFGBuilder::debug_info() const { return structured_sdfg_->debug_info(); }
3✔
1429

1430
} // namespace builder
1431
} // 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