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

daisytuner / sdfglib / 16439520920

22 Jul 2025 08:53AM UTC coverage: 65.927% (+0.8%) from 65.094%
16439520920

Pull #153

github

web-flow
Merge a0eea6968 into abe57c083
Pull Request #153: Restricts memlets to contiguous memory

211 of 300 new or added lines in 29 files covered. (70.33%)

66 existing lines in 7 files now uncovered.

8314 of 12611 relevant lines covered (65.93%)

128.5 hits per line

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

70.3
/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/types/utils.h"
11

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

15
namespace sdfg {
16
namespace builder {
17

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

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

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

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

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

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

61
    return false;
×
62
}
6✔
63

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

78
    return pdom;
3✔
79
}
3✔
80

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

294
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
4,955✔
295

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

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

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

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

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

316
    for (auto& ext : sdfg.externals_) {
5✔
317
        this->structured_sdfg_->externals_.push_back(ext);
1✔
318
    }
319

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

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

328
    this->traverse(sdfg);
4✔
329
};
4✔
330

331
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
895✔
332

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

338
    return std::move(this->structured_sdfg_);
405✔
339
};
340

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

348
        if (current->element_id() == element_id) {
32✔
349
            return current;
9✔
350
        }
351

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

384
    return nullptr;
×
385
};
9✔
386

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

391
    parent.transitions_
78✔
392
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
39✔
393
        );
394

395
    return static_cast<Sequence&>(*parent.children_.back().get());
39✔
396
};
×
397

398
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
399
    add_sequence_before(Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
9✔
400
    // Insert block before current block
401
    int index = -1;
9✔
402
    for (size_t i = 0; i < parent.children_.size(); i++) {
9✔
403
        if (parent.children_.at(i).get() == &block) {
9✔
404
            index = i;
9✔
405
            break;
9✔
406
        }
407
    }
×
408
    if (index == -1) {
9✔
409
        throw InvalidSDFGException("StructuredSDFGBuilder: Block not found");
×
410
    }
411

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

416
    parent.transitions_.insert(
18✔
417
        parent.transitions_.begin() + index,
9✔
418
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
9✔
419
    );
420

421
    auto new_entry = parent.at(index);
9✔
422
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
9✔
423

424
    return {new_block, new_entry.second};
9✔
425
};
×
426

427
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t i) {
11✔
428
    parent.children_.erase(parent.children_.begin() + i);
11✔
429
    parent.transitions_.erase(parent.transitions_.begin() + i);
11✔
430
};
11✔
431

432
void StructuredSDFGBuilder::remove_child(Sequence& parent, ControlFlowNode& child) {
13✔
433
    int index = -1;
13✔
434
    for (size_t i = 0; i < parent.children_.size(); i++) {
18✔
435
        if (parent.children_.at(i).get() == &child) {
18✔
436
            index = i;
13✔
437
            break;
13✔
438
        }
439
    }
5✔
440

441
    parent.children_.erase(parent.children_.begin() + index);
13✔
442
    parent.transitions_.erase(parent.transitions_.begin() + index);
13✔
443
};
13✔
444

445
void StructuredSDFGBuilder::insert_children(Sequence& parent, Sequence& other, size_t i) {
20✔
446
    parent.children_.insert(
40✔
447
        parent.children_.begin() + i,
20✔
448
        std::make_move_iterator(other.children_.begin()),
20✔
449
        std::make_move_iterator(other.children_.end())
20✔
450
    );
451
    parent.transitions_.insert(
40✔
452
        parent.transitions_.begin() + i,
20✔
453
        std::make_move_iterator(other.transitions_.begin()),
20✔
454
        std::make_move_iterator(other.transitions_.end())
20✔
455
    );
456
    for (auto& trans : parent.transitions_) {
44✔
457
        trans->parent_ = &parent;
24✔
458
    }
459
    other.children_.clear();
20✔
460
    other.transitions_.clear();
20✔
461
};
20✔
462

463
void StructuredSDFGBuilder::insert(ControlFlowNode& node, Sequence& source, Sequence& target, const DebugInfo& debug_info) {
8✔
464
    // Insert node into target sequence
465
    int index = -1;
8✔
466
    for (size_t i = 0; i < source.children_.size(); i++) {
16✔
467
        if (source.children_.at(i).get() == &node) {
16✔
468
            index = i;
8✔
469
            break;
8✔
470
        }
471
    }
8✔
472
    if (index == -1) {
8✔
473
        throw InvalidSDFGException("StructuredSDFGBuilder: Node not found in source sequence");
×
474
    }
475

476
    auto node_ptr = std::move(source.children_.at(index));
8✔
477
    source.children_.erase(source.children_.begin() + index);
8✔
478
    source.transitions_.erase(source.transitions_.begin() + index);
8✔
479

480
    target.children_.push_back(std::move(node_ptr));
8✔
481
    target.transitions_.push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, target)
8✔
482
    ));
483
};
8✔
484

485
Block& StructuredSDFGBuilder::
486
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
462✔
487
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
462✔
488

489
    parent.transitions_
924✔
490
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
462✔
491
        );
492

493
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
462✔
494
    (*new_block.dataflow_).parent_ = &new_block;
462✔
495

496
    return new_block;
462✔
497
};
×
498

499
Block& StructuredSDFGBuilder::add_block(
18✔
500
    Sequence& parent,
501
    const data_flow::DataFlowGraph& data_flow_graph,
502
    const sdfg::control_flow::Assignments& assignments,
503
    const DebugInfo& debug_info
504
) {
505
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
18✔
506

507
    parent.transitions_
36✔
508
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
18✔
509
        );
510

511
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
18✔
512
    (*new_block.dataflow_).parent_ = &new_block;
18✔
513

514
    this->add_dataflow(data_flow_graph, new_block);
18✔
515

516
    return new_block;
18✔
517
};
×
518

519
std::pair<Block&, Transition&> StructuredSDFGBuilder::
520
    add_block_before(Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
10✔
521
    // Insert block before current block
522
    int index = -1;
10✔
523
    for (size_t i = 0; i < parent.children_.size(); i++) {
10✔
524
        if (parent.children_.at(i).get() == &block) {
10✔
525
            index = i;
10✔
526
            break;
10✔
527
        }
528
    }
×
529
    assert(index > -1);
10✔
530

531
    parent.children_
20✔
532
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
10✔
533

534
    parent.transitions_.insert(
20✔
535
        parent.transitions_.begin() + index,
10✔
536
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
10✔
537
    );
538

539
    auto new_entry = parent.at(index);
10✔
540
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
10✔
541
    (*new_block.dataflow_).parent_ = &new_block;
10✔
542

543
    return {new_block, new_entry.second};
10✔
544
};
×
545

546
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
547
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
548
) {
549
    // Insert block before current block
550
    int index = -1;
×
551
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
552
        if (parent.children_.at(i).get() == &block) {
×
553
            index = i;
×
554
            break;
×
555
        }
556
    }
×
557
    assert(index > -1);
×
558

559
    parent.children_
×
560
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
561

562
    parent.transitions_.insert(
×
563
        parent.transitions_.begin() + index,
×
564
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
565
    );
566

567
    auto new_entry = parent.at(index);
×
568
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
569
    (*new_block.dataflow_).parent_ = &new_block;
×
570

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

573
    return {new_block, new_entry.second};
×
574
};
×
575

576
std::pair<Block&, Transition&> StructuredSDFGBuilder::
577
    add_block_after(Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
2✔
578
    // Insert block before current block
579
    int index = -1;
2✔
580
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
581
        if (parent.children_.at(i).get() == &block) {
3✔
582
            index = i;
2✔
583
            break;
2✔
584
        }
585
    }
1✔
586
    assert(index > -1);
2✔
587

588
    parent.children_.insert(
4✔
589
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
2✔
590
    );
591

592
    parent.transitions_.insert(
4✔
593
        parent.transitions_.begin() + index + 1,
2✔
594
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
2✔
595
    );
596

597
    auto new_entry = parent.at(index + 1);
2✔
598
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
2✔
599
    (*new_block.dataflow_).parent_ = &new_block;
2✔
600

601
    return {new_block, new_entry.second};
2✔
602
};
×
603

604
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
605
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
606
) {
607
    int index = -1;
×
608
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
609
        if (parent.children_.at(i).get() == &block) {
×
610
            index = i;
×
611
            break;
×
612
        }
613
    }
×
614
    assert(index > -1);
×
615

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

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

625
    auto new_entry = parent.at(index + 1);
×
626
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
627
    (*new_block.dataflow_).parent_ = &new_block;
×
628

629
    this->add_dataflow(data_flow_graph, new_block);
×
630

631
    return {new_block, new_entry.second};
×
632
};
×
633

634
For& StructuredSDFGBuilder::add_for(
107✔
635
    Sequence& parent,
636
    const symbolic::Symbol& indvar,
637
    const symbolic::Condition& condition,
638
    const symbolic::Expression& init,
639
    const symbolic::Expression& update,
640
    const sdfg::control_flow::Assignments& assignments,
641
    const DebugInfo& debug_info
642
) {
643
    parent.children_
214✔
644
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
107✔
645

646
    // Increment element id for body node
647
    this->new_element_id();
107✔
648

649
    parent.transitions_
214✔
650
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
107✔
651
        );
652

653
    return static_cast<For&>(*parent.children_.back().get());
107✔
654
};
×
655

656
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_before(
10✔
657
    Sequence& parent,
658
    ControlFlowNode& block,
659
    const symbolic::Symbol& indvar,
660
    const symbolic::Condition& condition,
661
    const symbolic::Expression& init,
662
    const symbolic::Expression& update,
663
    const DebugInfo& debug_info
664
) {
665
    // Insert block before current block
666
    int index = -1;
10✔
667
    for (size_t i = 0; i < parent.children_.size(); i++) {
10✔
668
        if (parent.children_.at(i).get() == &block) {
10✔
669
            index = i;
10✔
670
            break;
10✔
671
        }
672
    }
×
673
    assert(index > -1);
10✔
674

675
    parent.children_.insert(
20✔
676
        parent.children_.begin() + index,
10✔
677
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
10✔
678
    );
679

680
    // Increment element id for body node
681
    this->new_element_id();
10✔
682

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

688
    auto new_entry = parent.at(index);
10✔
689
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
10✔
690

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

694
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_after(
6✔
695
    Sequence& parent,
696
    ControlFlowNode& block,
697
    const symbolic::Symbol& indvar,
698
    const symbolic::Condition& condition,
699
    const symbolic::Expression& init,
700
    const symbolic::Expression& update,
701
    const DebugInfo& debug_info
702
) {
703
    // Insert block before current block
704
    int index = -1;
6✔
705
    for (size_t i = 0; i < parent.children_.size(); i++) {
11✔
706
        if (parent.children_.at(i).get() == &block) {
11✔
707
            index = i;
6✔
708
            break;
6✔
709
        }
710
    }
5✔
711
    assert(index > -1);
6✔
712

713
    parent.children_.insert(
12✔
714
        parent.children_.begin() + index + 1,
6✔
715
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
716
    );
717

718
    // Increment element id for body node
719
    this->new_element_id();
6✔
720

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

726
    auto new_entry = parent.at(index + 1);
6✔
727
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
6✔
728

729
    return {new_block, new_entry.second};
6✔
730
};
×
731

732
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent, const DebugInfo& debug_info) {
39✔
733
    return this->add_if_else(parent, control_flow::Assignments{}, debug_info);
39✔
734
};
×
735

736
IfElse& StructuredSDFGBuilder::
737
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
44✔
738
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
44✔
739

740
    parent.transitions_
88✔
741
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
44✔
742
        );
743

744
    return static_cast<IfElse&>(*parent.children_.back().get());
44✔
745
};
×
746

747
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
748
    add_if_else_before(Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
1✔
749
    // Insert block before current block
750
    int index = -1;
1✔
751
    for (size_t i = 0; i < parent.children_.size(); i++) {
1✔
752
        if (parent.children_.at(i).get() == &block) {
1✔
753
            index = i;
1✔
754
            break;
1✔
755
        }
756
    }
×
757
    assert(index > -1);
1✔
758

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

762
    parent.transitions_.insert(
2✔
763
        parent.transitions_.begin() + index,
1✔
764
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
1✔
765
    );
766

767
    auto new_entry = parent.at(index);
1✔
768
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
1✔
769

770
    return {new_block, new_entry.second};
1✔
771
};
×
772

773
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
76✔
774
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
76✔
775

776
    scope.conditions_.push_back(cond);
76✔
777
    return *scope.cases_.back();
76✔
778
};
×
779

780
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t i, const DebugInfo& debug_info) {
4✔
781
    scope.cases_.erase(scope.cases_.begin() + i);
4✔
782
    scope.conditions_.erase(scope.conditions_.begin() + i);
4✔
783
};
4✔
784

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

789
    // Increment element id for body node
790
    this->new_element_id();
33✔
791

792
    parent.transitions_
66✔
793
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
33✔
794
        );
795

796
    return static_cast<While&>(*parent.children_.back().get());
33✔
797
};
×
798

799
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent, const DebugInfo& debug_info) {
12✔
800
    return this->add_continue(parent, control_flow::Assignments{}, debug_info);
12✔
801
};
×
802

803
Continue& StructuredSDFGBuilder::
804
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
14✔
805
    // Check if continue is in a loop
806
    analysis::AnalysisManager analysis_manager(this->subject());
14✔
807
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
14✔
808
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
14✔
809
    bool in_loop = false;
14✔
810
    while (current_scope != nullptr) {
24✔
811
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
24✔
812
            in_loop = true;
14✔
813
            break;
14✔
814
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
815
            throw UnstructuredControlFlowException();
×
816
        }
817
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
818
    }
819
    if (!in_loop) {
14✔
820
        throw UnstructuredControlFlowException();
×
821
    }
822

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

825
    parent.transitions_
28✔
826
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
827
        );
828

829
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
830
};
14✔
831

832
Break& StructuredSDFGBuilder::add_break(Sequence& parent, const DebugInfo& debug_info) {
13✔
833
    return this->add_break(parent, control_flow::Assignments{}, debug_info);
13✔
834
};
×
835

836
Break& StructuredSDFGBuilder::
837
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
15✔
838
    // Check if break is in a loop
839
    analysis::AnalysisManager analysis_manager(this->subject());
15✔
840
    auto& scope_tree_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
15✔
841
    auto current_scope = scope_tree_analysis.parent_scope(&parent);
15✔
842
    bool in_loop = false;
15✔
843
    while (current_scope != nullptr) {
25✔
844
        if (dynamic_cast<structured_control_flow::While*>(current_scope)) {
25✔
845
            in_loop = true;
15✔
846
            break;
15✔
847
        } else if (dynamic_cast<structured_control_flow::For*>(current_scope)) {
10✔
848
            throw UnstructuredControlFlowException();
×
849
        }
850
        current_scope = scope_tree_analysis.parent_scope(current_scope);
10✔
851
    }
852
    if (!in_loop) {
15✔
853
        throw UnstructuredControlFlowException();
×
854
    }
855

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

858
    parent.transitions_
30✔
859
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
15✔
860
        );
861

862
    return static_cast<Break&>(*parent.children_.back().get());
15✔
863
};
15✔
864

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

869
    parent.transitions_
28✔
870
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
871
        );
872

873
    return static_cast<Return&>(*parent.children_.back().get());
14✔
874
};
×
875

876
Map& StructuredSDFGBuilder::add_map(
27✔
877
    Sequence& parent,
878
    const symbolic::Symbol& indvar,
879
    const symbolic::Condition& condition,
880
    const symbolic::Expression& init,
881
    const symbolic::Expression& update,
882
    const ScheduleType& schedule_type,
883
    const sdfg::control_flow::Assignments& assignments,
884
    const DebugInfo& debug_info
885
) {
886
    parent.children_
54✔
887
        .push_back(std::unique_ptr<
27✔
888
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
27✔
889

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

893
    parent.transitions_
54✔
894
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
27✔
895
        );
896

897
    return static_cast<Map&>(*parent.children_.back().get());
27✔
898
};
×
899

900
std::pair<Map&, Transition&> StructuredSDFGBuilder::add_map_before(
4✔
901
    Sequence& parent,
902
    ControlFlowNode& block,
903
    const symbolic::Symbol& indvar,
904
    const symbolic::Condition& condition,
905
    const symbolic::Expression& init,
906
    const symbolic::Expression& update,
907
    const ScheduleType& schedule_type,
908
    const sdfg::control_flow::Assignments& assignments,
909
    const DebugInfo& debug_info
910
) {
911
    // Insert block before current block
912
    int index = -1;
4✔
913
    for (size_t i = 0; i < parent.children_.size(); i++) {
4✔
914
        if (parent.children_.at(i).get() == &block) {
4✔
915
            index = i;
4✔
916
            break;
4✔
917
        }
918
    }
×
919
    assert(index > -1);
4✔
920

921
    parent.children_.insert(
8✔
922
        parent.children_.begin() + index,
4✔
923
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
4✔
924
        )
925
    );
926

927
    // Increment element id for body node
928
    this->new_element_id();
4✔
929

930
    parent.transitions_.insert(
8✔
931
        parent.transitions_.begin() + index,
4✔
932
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
4✔
933
    );
934

935
    auto new_entry = parent.at(index);
4✔
936
    auto& new_block = dynamic_cast<structured_control_flow::Map&>(new_entry.first);
4✔
937

938
    return {new_block, new_entry.second};
4✔
939
};
×
940

941
std::pair<Map&, Transition&> StructuredSDFGBuilder::add_map_after(
8✔
942
    Sequence& parent,
943
    ControlFlowNode& block,
944
    const symbolic::Symbol& indvar,
945
    const symbolic::Condition& condition,
946
    const symbolic::Expression& init,
947
    const symbolic::Expression& update,
948
    const ScheduleType& schedule_type,
949
    const sdfg::control_flow::Assignments& assignments,
950
    const DebugInfo& debug_info
951
) {
952
    // Insert block before current block
953
    int index = -1;
8✔
954
    for (size_t i = 0; i < parent.children_.size(); i++) {
8✔
955
        if (parent.children_.at(i).get() == &block) {
8✔
956
            index = i;
8✔
957
            break;
8✔
958
        }
959
    }
×
960
    assert(index > -1);
8✔
961

962
    parent.children_.insert(
16✔
963
        parent.children_.begin() + index + 1,
8✔
964
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
8✔
965
        )
966
    );
967

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

971
    parent.transitions_.insert(
16✔
972
        parent.transitions_.begin() + index + 1,
8✔
973
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
8✔
974
    );
975

976
    auto new_entry = parent.at(index + 1);
8✔
977
    auto& new_block = dynamic_cast<structured_control_flow::Map&>(new_entry.first);
8✔
978

979
    return {new_block, new_entry.second};
8✔
980
};
×
981

982
For& StructuredSDFGBuilder::convert_while(
×
983
    Sequence& parent,
984
    While& loop,
985
    const symbolic::Symbol& indvar,
986
    const symbolic::Condition& condition,
987
    const symbolic::Expression& init,
988
    const symbolic::Expression& update
989
) {
990
    // Insert for loop
991
    size_t index = 0;
×
992
    for (auto& entry : parent.children_) {
×
993
        if (entry.get() == &loop) {
×
994
            break;
×
995
        }
996
        index++;
×
997
    }
998
    auto iter = parent.children_.begin() + index;
×
999
    auto& new_iter = *parent.children_.insert(
×
1000
        iter + 1,
×
1001
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1002
    );
1003

1004
    // Increment element id for body node
1005
    this->new_element_id();
×
1006

1007
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1008
    this->insert_children(for_loop.root(), loop.root(), 0);
×
1009

1010
    // Remove while loop
1011
    parent.children_.erase(parent.children_.begin() + index);
×
1012

1013
    return for_loop;
×
1014
};
×
1015

1016
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
8✔
1017
    // Insert for loop
1018
    size_t index = 0;
8✔
1019
    for (auto& entry : parent.children_) {
8✔
1020
        if (entry.get() == &loop) {
8✔
1021
            break;
8✔
1022
        }
1023
        index++;
×
1024
    }
1025
    auto iter = parent.children_.begin() + index;
8✔
1026
    auto& new_iter = *parent.children_.insert(
16✔
1027
        iter + 1,
8✔
1028
        std::unique_ptr<Map>(new Map(
16✔
1029
            this->new_element_id(),
8✔
1030
            loop.debug_info(),
8✔
1031
            loop.indvar(),
8✔
1032
            loop.init(),
8✔
1033
            loop.update(),
8✔
1034
            loop.condition(),
8✔
1035
            ScheduleType_Sequential
1036
        ))
1037
    );
1038

1039
    // Increment element id for body node
1040
    this->new_element_id();
8✔
1041

1042
    auto& map = dynamic_cast<Map&>(*new_iter);
8✔
1043
    this->insert_children(map.root(), loop.root(), 0);
8✔
1044

1045
    // Remove for loop
1046
    parent.children_.erase(parent.children_.begin() + index);
8✔
1047

1048
    return map;
8✔
1049
};
×
1050

1051
void StructuredSDFGBuilder::clear_sequence(Sequence& parent) {
×
1052
    parent.children_.clear();
×
1053
    parent.transitions_.clear();
×
1054
};
×
1055

1056
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1057
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1058
    while (!queue.empty()) {
2✔
1059
        auto current = queue.front();
2✔
1060
        queue.pop_front();
2✔
1061

1062
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1063
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1064
                if (&sequence_stmt->at(i).first == &node) {
2✔
1065
                    return *sequence_stmt;
2✔
1066
                }
1067
                queue.push_back(&sequence_stmt->at(i).first);
×
1068
            }
×
1069
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1070
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1071
                queue.push_back(&if_else_stmt->at(i).first);
×
1072
            }
×
1073
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1074
            queue.push_back(&while_stmt->root());
×
1075
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
×
1076
            queue.push_back(&for_stmt->root());
×
1077
        }
×
1078
    }
1079

1080
    return this->structured_sdfg_->root();
×
1081
};
2✔
1082

1083
/***** Section: Dataflow Graph *****/
1084

1085
data_flow::AccessNode& StructuredSDFGBuilder::
1086
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
512✔
1087
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
512✔
1088
    auto res = block.dataflow_->nodes_.insert(
1,024✔
1089
        {vertex,
512✔
1090
         std::unique_ptr<data_flow::AccessNode>(
512✔
1091
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
512✔
1092
         )}
1093
    );
1094

1095
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
512✔
1096
};
×
1097

1098
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
328✔
1099
    structured_control_flow::Block& block,
1100
    const data_flow::TaskletCode code,
1101
    const std::pair<std::string, sdfg::types::Scalar>& output,
1102
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
1103
    const DebugInfo& debug_info
1104
) {
1105
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
328✔
1106
    auto res = block.dataflow_->nodes_.insert(
656✔
1107
        {vertex,
328✔
1108
         std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
656✔
1109
             this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs, symbolic::__true__()
328✔
1110
         ))}
1111
    );
1112

1113
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
328✔
UNCOV
1114
};
×
1115

1116
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
496✔
1117
    structured_control_flow::Block& block,
1118
    data_flow::DataFlowNode& src,
1119
    const std::string& src_conn,
1120
    data_flow::DataFlowNode& dst,
1121
    const std::string& dst_conn,
1122
    const data_flow::Subset& subset,
1123
    const DebugInfo& debug_info
1124
) {
1125
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
496✔
1126
    auto res = block.dataflow_->edges_.insert(
992✔
1127
        {edge.first,
992✔
1128
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
992✔
1129
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset
496✔
1130
         ))}
1131
    );
1132

1133
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
496✔
1134
};
×
1135

1136
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
12✔
1137
    structured_control_flow::Block& block,
1138
    data_flow::DataFlowNode& src,
1139
    const std::string& src_conn,
1140
    data_flow::DataFlowNode& dst,
1141
    const std::string& dst_conn,
1142
    const data_flow::Subset& begin_subset,
1143
    const data_flow::Subset& end_subset,
1144
    const DebugInfo& debug_info
1145
) {
1146
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
12✔
1147
    auto res = block.dataflow_->edges_.insert(
24✔
1148
        {edge.first,
24✔
1149
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
24✔
1150
             this->new_element_id(),
12✔
1151
             debug_info,
12✔
1152
             edge.first,
12✔
1153
             block.dataflow(),
12✔
1154
             src,
12✔
1155
             src_conn,
12✔
1156
             dst,
12✔
1157
             dst_conn,
12✔
1158
             begin_subset,
12✔
1159
             end_subset
12✔
1160
         ))}
1161
    );
1162

1163
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
12✔
1164
};
×
1165

NEW
1166
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
×
1167
    structured_control_flow::Block& block,
1168
    data_flow::AccessNode& src,
1169
    data_flow::Tasklet& dst,
1170
    const std::string& dst_conn,
1171
    const data_flow::Subset& subset,
1172
    const DebugInfo& debug_info
1173
) {
NEW
1174
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, debug_info);
×
NEW
1175
};
×
1176

NEW
1177
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
×
1178
    structured_control_flow::Block& block,
1179
    data_flow::Tasklet& src,
1180
    const std::string& src_conn,
1181
    data_flow::AccessNode& dst,
1182
    const data_flow::Subset& subset,
1183
    const DebugInfo& debug_info
1184
) {
NEW
1185
    return this->add_memlet(block, src, src_conn, dst, "void", subset, debug_info);
×
NEW
1186
};
×
1187

NEW
1188
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
×
1189
    structured_control_flow::Block& block,
1190
    data_flow::AccessNode& src,
1191
    data_flow::LibraryNode& dst,
1192
    const std::string& dst_conn,
1193
    const data_flow::Subset& begin_subset,
1194
    const data_flow::Subset& end_subset,
1195
    const DebugInfo& debug_info
1196
) {
NEW
1197
    return this->add_memlet(block, src, "void", dst, dst_conn, begin_subset, end_subset, debug_info);
×
NEW
1198
};
×
1199

NEW
1200
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
×
1201
    structured_control_flow::Block& block,
1202
    data_flow::LibraryNode& src,
1203
    const std::string& src_conn,
1204
    data_flow::AccessNode& dst,
1205
    const data_flow::Subset& begin_subset,
1206
    const data_flow::Subset& end_subset,
1207
    const DebugInfo& debug_info
1208
) {
NEW
1209
    return this->add_memlet(block, src, src_conn, dst, "void", begin_subset, end_subset, debug_info);
×
NEW
1210
};
×
1211

NEW
1212
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
×
1213
    structured_control_flow::Block& block,
1214
    data_flow::AccessNode& src,
1215
    data_flow::AccessNode& dst,
1216
    const data_flow::Subset& subset,
1217
    const DebugInfo& debug_info
1218
) {
NEW
1219
    return this->add_memlet(block, src, "void", dst, "ref", subset, debug_info);
×
NEW
1220
};
×
1221

NEW
1222
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
×
1223
    structured_control_flow::Block& block,
1224
    data_flow::AccessNode& src,
1225
    data_flow::AccessNode& dst,
1226
    bool derefs_src,
1227
    const DebugInfo& debug_info
1228
) {
NEW
1229
    if (derefs_src) {
×
NEW
1230
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, debug_info);
×
1231
    } else {
NEW
1232
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, debug_info);
×
1233
    }
NEW
1234
};
×
1235

1236
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
2✔
1237
    auto& graph = block.dataflow();
2✔
1238
    auto e = edge.edge();
2✔
1239
    boost::remove_edge(e, graph.graph_);
2✔
1240
    graph.edges_.erase(e);
2✔
1241
};
2✔
1242

1243
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
3✔
1244
    auto& graph = block.dataflow();
3✔
1245
    auto v = node.vertex();
3✔
1246
    boost::remove_vertex(v, graph.graph_);
3✔
1247
    graph.nodes_.erase(v);
3✔
1248
};
3✔
1249

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

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

1255
    // Delete incoming
1256
    std::list<const data_flow::Memlet*> iedges;
8✔
1257
    for (auto& iedge : graph.in_edges(node)) {
15✔
1258
        iedges.push_back(&iedge);
7✔
1259
    }
1260
    for (auto iedge : iedges) {
15✔
1261
        auto& src = iedge->src();
7✔
1262
        to_delete.insert(&src);
7✔
1263

1264
        auto edge = iedge->edge();
7✔
1265
        graph.edges_.erase(edge);
7✔
1266
        boost::remove_edge(edge, graph.graph_);
7✔
1267
    }
1268

1269
    // Delete outgoing
1270
    std::list<const data_flow::Memlet*> oedges;
8✔
1271
    for (auto& oedge : graph.out_edges(node)) {
16✔
1272
        oedges.push_back(&oedge);
8✔
1273
    }
1274
    for (auto oedge : oedges) {
16✔
1275
        auto& dst = oedge->dst();
8✔
1276
        to_delete.insert(&dst);
8✔
1277

1278
        auto edge = oedge->edge();
8✔
1279
        graph.edges_.erase(edge);
8✔
1280
        boost::remove_edge(edge, graph.graph_);
8✔
1281
    }
1282

1283
    // Delete nodes
1284
    for (auto obsolete_node : to_delete) {
31✔
1285
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
1286
            auto vertex = obsolete_node->vertex();
23✔
1287
            graph.nodes_.erase(vertex);
23✔
1288
            boost::remove_vertex(vertex, graph.graph_);
23✔
1289
        }
23✔
1290
    }
1291
};
8✔
1292

1293
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
1✔
1294
    auto& graph = block.dataflow();
1✔
1295
    if (graph.out_degree(node) != 0) {
1✔
1296
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1297
    }
1298

1299
    std::list<const data_flow::Memlet*> tmp;
1✔
1300
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
1301
    while (!queue.empty()) {
3✔
1302
        auto current = queue.front();
2✔
1303
        queue.pop_front();
2✔
1304
        if (current != &node) {
2✔
1305
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
1306
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1307
                    continue;
×
1308
                }
1309
            }
×
1310
        }
1✔
1311

1312
        tmp.clear();
2✔
1313
        for (auto& iedge : graph.in_edges(*current)) {
3✔
1314
            tmp.push_back(&iedge);
1✔
1315
        }
1316
        for (auto iedge : tmp) {
3✔
1317
            auto& src = iedge->src();
1✔
1318
            queue.push_back(&src);
1✔
1319

1320
            auto edge = iedge->edge();
1✔
1321
            graph.edges_.erase(edge);
1✔
1322
            boost::remove_edge(edge, graph.graph_);
1✔
1323
        }
1324

1325
        auto vertex = current->vertex();
2✔
1326
        graph.nodes_.erase(vertex);
2✔
1327
        boost::remove_vertex(vertex, graph.graph_);
2✔
1328
    }
1329
};
1✔
1330

1331
data_flow::AccessNode& StructuredSDFGBuilder::
1332
    symbolic_expression_to_dataflow(structured_control_flow::Block& parent, const symbolic::Expression& expr) {
×
1333
    auto& sdfg = this->subject();
×
1334

1335
    codegen::CPPLanguageExtension language_extension;
×
1336

1337
    // Base cases
1338
    if (SymEngine::is_a<SymEngine::Symbol>(*expr)) {
×
1339
        auto sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(expr);
×
1340

1341
        // Determine type
1342
        types::Scalar sym_type = types::Scalar(types::PrimitiveType::Void);
×
1343
        if (symbolic::is_nv(sym)) {
×
1344
            sym_type = types::Scalar(types::PrimitiveType::Int32);
×
1345
        } else {
×
1346
            sym_type = static_cast<const types::Scalar&>(sdfg.type(sym->get_name()));
×
1347
        }
1348

1349
        // Add new container for intermediate result
1350
        auto tmp = this->find_new_name();
×
1351
        this->add_container(tmp, sym_type);
×
1352

1353
        // Create dataflow graph
1354
        auto& input_node = this->add_access(parent, sym->get_name());
×
1355
        auto& output_node = this->add_access(parent, tmp);
×
1356
        auto& tasklet =
×
1357
            this->add_tasklet(parent, data_flow::TaskletCode::assign, {"_out", sym_type}, {{"_in", sym_type}});
×
1358
        this->add_memlet(parent, input_node, "void", tasklet, "_in", {});
×
1359
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {});
×
1360

1361
        return output_node;
×
1362
    } else if (SymEngine::is_a<SymEngine::Integer>(*expr)) {
×
1363
        auto tmp = this->find_new_name();
×
1364
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Int64));
×
1365

1366
        auto& output_node = this->add_access(parent, tmp);
×
1367
        auto& tasklet = this->add_tasklet(
×
1368
            parent,
×
1369
            data_flow::TaskletCode::assign,
1370
            {"_out", types::Scalar(types::PrimitiveType::Int64)},
×
1371
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Int64)}}
×
1372
        );
1373
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {});
×
1374
        return output_node;
×
1375
    } else if (SymEngine::is_a<SymEngine::BooleanAtom>(*expr)) {
×
1376
        auto tmp = this->find_new_name();
×
1377
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1378

1379
        auto& output_node = this->add_access(parent, tmp);
×
1380
        auto& tasklet = this->add_tasklet(
×
1381
            parent,
×
1382
            data_flow::TaskletCode::assign,
1383
            {"_out", types::Scalar(types::PrimitiveType::Bool)},
×
1384
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Bool)}}
×
1385
        );
1386
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {});
×
1387
        return output_node;
×
1388
    } else if (SymEngine::is_a<SymEngine::Or>(*expr)) {
×
1389
        auto or_expr = SymEngine::rcp_static_cast<const SymEngine::Or>(expr);
×
1390
        if (or_expr->get_container().size() != 2) {
×
1391
            throw InvalidSDFGException("StructuredSDFGBuilder: Or expression must have exactly two arguments");
×
1392
        }
1393

1394
        std::vector<data_flow::AccessNode*> input_nodes;
×
1395
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1396
        for (auto& arg : or_expr->get_container()) {
×
1397
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1398
            input_nodes.push_back(&input_node);
×
1399
            input_types.push_back(
×
1400
                {"_in" + std::to_string(input_types.size() + 1),
×
1401
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))}
×
1402
            );
1403
        }
1404

1405
        // Add new container for intermediate result
1406
        auto tmp = this->find_new_name();
×
1407
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1408

1409
        auto& output_node = this->add_access(parent, tmp);
×
1410
        auto& tasklet = this->add_tasklet(
×
1411
            parent, data_flow::TaskletCode::logical_or, {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types
×
1412
        );
1413
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1414
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first, {});
×
1415
        }
×
1416
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {});
×
1417
        return output_node;
×
1418
    } else if (SymEngine::is_a<SymEngine::And>(*expr)) {
×
1419
        auto and_expr = SymEngine::rcp_static_cast<const SymEngine::And>(expr);
×
1420
        if (and_expr->get_container().size() != 2) {
×
1421
            throw InvalidSDFGException("StructuredSDFGBuilder: And expression must have exactly two arguments");
×
1422
        }
1423

1424
        std::vector<data_flow::AccessNode*> input_nodes;
×
1425
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1426
        for (auto& arg : and_expr->get_container()) {
×
1427
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1428
            input_nodes.push_back(&input_node);
×
1429
            input_types.push_back(
×
1430
                {"_in" + std::to_string(input_types.size() + 1),
×
1431
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))}
×
1432
            );
1433
        }
1434

1435
        // Add new container for intermediate result
1436
        auto tmp = this->find_new_name();
×
1437
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1438

1439
        auto& output_node = this->add_access(parent, tmp);
×
1440
        auto& tasklet = this->add_tasklet(
×
1441
            parent, data_flow::TaskletCode::logical_and, {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types
×
1442
        );
1443
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1444
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first, {});
×
1445
        }
×
1446
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {});
×
1447
        return output_node;
×
1448
    } else {
×
1449
        throw std::runtime_error("Unsupported expression type");
×
1450
    }
1451
};
×
1452

1453
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
18✔
1454
    auto& to_dataflow = to.dataflow();
18✔
1455

1456
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
18✔
1457
    for (auto& entry : from.nodes_) {
19✔
1458
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1459
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1460
        node_mapping.insert({entry.first, vertex});
1✔
1461
    }
1462

1463
    for (auto& entry : from.edges_) {
18✔
1464
        auto src = node_mapping[entry.second->src().vertex()];
×
1465
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1466

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

1469
        to_dataflow.edges_.insert(
×
1470
            {edge.first,
×
1471
             entry.second->clone(
×
1472
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1473
             )}
1474
        );
1475
    }
1476
};
18✔
1477

1478
} // namespace builder
1479
} // 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