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

daisytuner / sdfglib / 15044057891

15 May 2025 11:42AM UTC coverage: 59.37% (+1.8%) from 57.525%
15044057891

push

github

web-flow
Merge pull request #14 from daisytuner/sanitizers

enables sanitizer on unit tests

63 of 67 new or added lines in 47 files covered. (94.03%)

570 existing lines in 62 files now uncovered.

7356 of 12390 relevant lines covered (59.37%)

505.93 hits per line

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

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

3
#include "sdfg/codegen/language_extensions/cpp_language_extension.h"
4
#include "sdfg/data_flow/library_node.h"
5

6
using namespace sdfg::control_flow;
7
using namespace sdfg::structured_control_flow;
8

9
namespace sdfg {
10
namespace builder {
11

12
std::unordered_set<const control_flow::State*> StructuredSDFGBuilder::determine_loop_nodes(
1✔
13
    const SDFG& sdfg, const control_flow::State& start, const control_flow::State& end) const {
14
    std::unordered_set<const control_flow::State*> nodes;
1✔
15
    std::unordered_set<const control_flow::State*> visited;
1✔
16
    std::list<const control_flow::State*> queue = {&start};
1✔
17
    while (!queue.empty()) {
4✔
18
        auto curr = queue.front();
3✔
19
        queue.pop_front();
3✔
20
        if (visited.find(curr) != visited.end()) {
3✔
UNCOV
21
            continue;
×
22
        }
23
        visited.insert(curr);
3✔
24

25
        nodes.insert(curr);
3✔
26
        if (curr == &end) {
3✔
27
            continue;
1✔
28
        }
29

30
        for (auto& iedge : sdfg.in_edges(*curr)) {
4✔
31
            queue.push_back(&iedge.src());
2✔
32
        }
33
    }
34

35
    return nodes;
1✔
36
};
1✔
37

38
bool post_dominates(
6✔
39
    const State* pdom, const State* node,
40
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree) {
41
    if (pdom == node) {
6✔
42
        return true;
1✔
43
    }
44

45
    auto current = pdom_tree.at(node);
5✔
46
    while (current != nullptr) {
9✔
47
        if (current == pdom) {
9✔
48
            return true;
5✔
49
        }
50
        current = pdom_tree.at(current);
4✔
51
    }
52

53
    return false;
×
54
}
6✔
55

56
const control_flow::State* StructuredSDFGBuilder::find_end_of_if_else(
3✔
57
    const SDFG& sdfg, const State* current, std::vector<const InterstateEdge*>& out_edges,
58
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree) {
59
    // Best-effort approach: Check if post-dominator of current dominates all out edges
60
    auto pdom = pdom_tree.at(current);
3✔
61
    for (auto& edge : out_edges) {
9✔
62
        if (!post_dominates(pdom, &edge->dst(), pdom_tree)) {
6✔
63
            return nullptr;
×
64
        }
65
    }
66

67
    return pdom;
3✔
68
}
3✔
69

70
void StructuredSDFGBuilder::traverse(const SDFG& sdfg) {
4✔
71
    // Start of SDFGS
72
    Sequence& root = *structured_sdfg_->root_;
4✔
73
    const State* start_state = &sdfg.start_state();
4✔
74

75
    auto pdom_tree = sdfg.post_dominator_tree();
4✔
76

77
    std::unordered_set<const InterstateEdge*> breaks;
4✔
78
    std::unordered_set<const InterstateEdge*> continues;
4✔
79
    for (auto& edge : sdfg.back_edges()) {
5✔
80
        continues.insert(edge);
1✔
81
    }
82

83
    this->traverse_with_loop_detection(sdfg, root, start_state, nullptr, continues, breaks,
4✔
84
                                       pdom_tree);
85
};
4✔
86

87
void StructuredSDFGBuilder::traverse_with_loop_detection(
19✔
88
    const SDFG& sdfg, Sequence& scope, const State* current, const State* end,
89
    const std::unordered_set<const InterstateEdge*>& continues,
90
    const std::unordered_set<const InterstateEdge*>& breaks,
91
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree) {
92
    if (current == end) {
19✔
93
        return;
4✔
94
    }
95

96
    auto in_edges = sdfg.in_edges(*current);
15✔
97
    auto out_edges = sdfg.out_edges(*current);
15✔
98
    auto out_degree = sdfg.out_degree(*current);
15✔
99

100
    // Loop detection
101
    std::unordered_set<const InterstateEdge*> loop_edges;
15✔
102
    for (auto& iedge : in_edges) {
29✔
103
        if (continues.find(&iedge) != continues.end()) {
14✔
104
            loop_edges.insert(&iedge);
1✔
105
        }
1✔
106
    }
107
    if (!loop_edges.empty()) {
15✔
108
        // 1. Determine nodes of loop body
109
        std::unordered_set<const control_flow::State*> body;
1✔
110
        for (auto back_edge : loop_edges) {
2✔
111
            auto loop_nodes = this->determine_loop_nodes(sdfg, back_edge->src(), back_edge->dst());
1✔
112
            body.insert(loop_nodes.begin(), loop_nodes.end());
1✔
113
        }
1✔
114

115
        // 2. Determine exit states and exit edges
116
        std::unordered_set<const control_flow::State*> exit_states;
1✔
117
        std::unordered_set<const control_flow::InterstateEdge*> exit_edges;
1✔
118
        for (auto node : body) {
4✔
119
            for (auto& edge : sdfg.out_edges(*node)) {
7✔
120
                if (body.find(&edge.dst()) == body.end()) {
4✔
121
                    exit_edges.insert(&edge);
1✔
122
                    exit_states.insert(&edge.dst());
1✔
123
                }
1✔
124
            }
125
        }
126
        assert(exit_states.size() == 1 &&
2✔
127
               "Degenerated structured control flow: Loop body must have exactly one exit state");
128
        const control_flow::State* exit_state = *exit_states.begin();
1✔
129

130
        for (auto& edge : breaks) {
1✔
131
            exit_edges.insert(edge);
×
132
        }
133

134
        // Collect debug information (could be removed when this is computed dynamically)
135
        DebugInfo dbg_info = current->debug_info();
1✔
136
        for (auto& edge : in_edges) {
3✔
137
            dbg_info = DebugInfo::merge(dbg_info, edge.debug_info());
2✔
138
        }
139
        for (auto node : body) {
4✔
140
            dbg_info = DebugInfo::merge(dbg_info, node->debug_info());
3✔
141
        }
142
        for (auto edge : exit_edges) {
2✔
143
            dbg_info = DebugInfo::merge(dbg_info, edge->debug_info());
1✔
144
        }
145

146
        // 3. Add while loop
147
        While& loop = this->add_while(scope, {}, dbg_info);
1✔
148
        this->traverse_without_loop_detection(sdfg, loop.root(), current, exit_state, continues,
1✔
149
                                              exit_edges, pdom_tree);
1✔
150

151
        this->traverse_with_loop_detection(sdfg, scope, exit_state, end, continues, breaks,
2✔
152
                                           pdom_tree);
1✔
153
    } else {
1✔
154
        this->traverse_without_loop_detection(sdfg, scope, current, end, continues, breaks,
28✔
155
                                              pdom_tree);
14✔
156
    }
157
};
19✔
158

159
void StructuredSDFGBuilder::traverse_without_loop_detection(
15✔
160
    const SDFG& sdfg, Sequence& scope, const State* current, const State* end,
161
    const std::unordered_set<const InterstateEdge*>& continues,
162
    const std::unordered_set<const InterstateEdge*>& breaks,
163
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree) {
164
    if (current == end) {
15✔
UNCOV
165
        return;
×
166
    }
167

168
    auto in_edges = sdfg.in_edges(*current);
15✔
169
    auto out_edges = sdfg.out_edges(*current);
15✔
170
    auto out_degree = sdfg.out_degree(*current);
15✔
171

172
    // Case 1: Sink node
173
    if (out_degree == 0) {
15✔
174
        this->add_block(scope, current->dataflow(), {}, current->debug_info());
4✔
175
        this->add_return(scope, {}, current->debug_info());
4✔
176
        return;
4✔
177
    }
178

179
    // Case 2: Transition
180
    if (out_degree == 1) {
11✔
181
        auto& oedge = *out_edges.begin();
8✔
182
        assert(oedge.is_unconditional() &&
16✔
183
               "Degenerated structured control flow: Non-deterministic transition");
184
        this->add_block(scope, current->dataflow(), oedge.assignments(), current->debug_info());
8✔
185

186
        if (continues.find(&oedge) != continues.end()) {
8✔
187
            this->add_continue(scope, oedge.debug_info());
×
188
        } else if (breaks.find(&oedge) != breaks.end()) {
8✔
189
            this->add_break(scope, oedge.debug_info());
×
UNCOV
190
        } else {
×
191
            this->traverse_with_loop_detection(sdfg, scope, &oedge.dst(), end, continues, breaks,
16✔
192
                                               pdom_tree);
8✔
193
        }
194
        return;
8✔
195
    }
196

197
    // Case 3: Branches
198
    if (out_degree > 1) {
3✔
199
        this->add_block(scope, current->dataflow(), {}, current->debug_info());
3✔
200

201
        std::vector<const InterstateEdge*> out_edges_vec;
3✔
202
        for (auto& edge : out_edges) {
9✔
203
            out_edges_vec.push_back(&edge);
6✔
204
        }
205

206
        // Best-effort approach: Find end of if-else
207
        // If not found, the branches may repeat paths yielding a large SDFG
208
        const control_flow::State* local_end =
3✔
209
            this->find_end_of_if_else(sdfg, current, out_edges_vec, pdom_tree);
3✔
210
        if (local_end == nullptr) {
3✔
211
            local_end = end;
×
UNCOV
212
        }
×
213

214
        auto& if_else = this->add_if_else(scope, current->debug_info());
3✔
215
        for (size_t i = 0; i < out_degree; i++) {
9✔
216
            auto& out_edge = out_edges_vec[i];
6✔
217

218
            auto& branch = this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
219
            if (!out_edge->assignments().empty()) {
6✔
220
                auto& body =
2✔
221
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
222
            }
2✔
223
            if (continues.find(out_edge) != continues.end()) {
6✔
224
                this->add_continue(branch, out_edge->debug_info());
1✔
225
            } else if (breaks.find(out_edge) != breaks.end()) {
6✔
226
                this->add_break(branch, out_edge->debug_info());
1✔
227
            } else {
1✔
228
                this->traverse_with_loop_detection(sdfg, branch, &out_edge->dst(), local_end,
4✔
229
                                                   continues, breaks, pdom_tree);
4✔
230
            }
231
        }
6✔
232

233
        if (local_end != end) {
3✔
234
            this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues, breaks,
4✔
235
                                               pdom_tree);
2✔
236
        }
2✔
237

238
        return;
239
    }
3✔
240
}
15✔
241

242
Function& StructuredSDFGBuilder::function() const {
2,183✔
243
    return static_cast<Function&>(*this->structured_sdfg_);
2,183✔
244
};
245

246
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
181✔
247
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
181✔
248

249
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name)
277✔
250
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name)) {};
277✔
251

252
StructuredSDFGBuilder::StructuredSDFGBuilder(const SDFG& sdfg)
4✔
253
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(sdfg.name())) {
4✔
254
    for (auto& entry : sdfg.structures_) {
4✔
255
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
256
    }
257

258
    for (auto& entry : sdfg.containers_) {
11✔
259
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
260
    }
261

262
    for (auto& arg : sdfg.arguments_) {
6✔
263
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
264
    }
265

266
    for (auto& ext : sdfg.externals_) {
5✔
267
        this->structured_sdfg_->externals_.push_back(ext);
1✔
268
    }
269

270
    for (auto& entry : sdfg.assumptions_) {
9✔
271
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
272
    }
273

274
    this->traverse(sdfg);
4✔
275
};
4✔
276

277
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
1,213✔
278

279
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
247✔
280
    return std::move(this->structured_sdfg_);
247✔
281
};
282

283
Sequence& StructuredSDFGBuilder::add_sequence(Sequence& parent,
34✔
284
                                              const sdfg::symbolic::Assignments& assignments,
285
                                              const DebugInfo& debug_info) {
286
    parent.children_.push_back(
34✔
287
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
34✔
288
    this->element_counter_++;
34✔
289
    parent.transitions_.push_back(std::unique_ptr<Transition>(
34✔
290
        new Transition(this->element_counter_, debug_info, assignments)));
34✔
291
    this->element_counter_++;
34✔
292

293
    return static_cast<Sequence&>(*parent.children_.back().get());
34✔
UNCOV
294
};
×
295

296
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::add_sequence_before(
7✔
297
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
298
    // Insert block before current block
299
    int index = -1;
7✔
300
    for (size_t i = 0; i < parent.children_.size(); i++) {
7✔
301
        if (parent.children_.at(i).get() == &block) {
7✔
302
            index = i;
7✔
303
            break;
7✔
304
        }
UNCOV
305
    }
×
306
    assert(index > -1);
7✔
307

308
    parent.children_.insert(
7✔
309
        parent.children_.begin() + index,
7✔
310
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
7✔
311
    this->element_counter_++;
7✔
312
    parent.transitions_.insert(
7✔
313
        parent.transitions_.begin() + index,
7✔
314
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
7✔
315
    this->element_counter_++;
7✔
316
    auto new_entry = parent.at(index);
7✔
317
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
7✔
318

319
    return {new_block, new_entry.second};
7✔
UNCOV
320
};
×
321

322
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t i) {
9✔
323
    parent.children_.erase(parent.children_.begin() + i);
9✔
324
    parent.transitions_.erase(parent.transitions_.begin() + i);
9✔
325
};
9✔
326

327
void StructuredSDFGBuilder::remove_child(Sequence& parent, ControlFlowNode& child) {
50✔
328
    int index = -1;
50✔
329
    for (size_t i = 0; i < parent.children_.size(); i++) {
51✔
330
        if (parent.children_.at(i).get() == &child) {
51✔
331
            index = i;
50✔
332
            break;
50✔
333
        }
334
    }
1✔
335

336
    parent.children_.erase(parent.children_.begin() + index);
50✔
337
    parent.transitions_.erase(parent.transitions_.begin() + index);
50✔
338
};
50✔
339

340
void StructuredSDFGBuilder::insert_children(Sequence& parent, Sequence& other, size_t i) {
9✔
341
    parent.children_.insert(parent.children_.begin() + i,
18✔
342
                            std::make_move_iterator(other.children_.begin()),
9✔
343
                            std::make_move_iterator(other.children_.end()));
9✔
344
    parent.transitions_.insert(parent.transitions_.begin() + i,
18✔
345
                               std::make_move_iterator(other.transitions_.begin()),
9✔
346
                               std::make_move_iterator(other.transitions_.end()));
9✔
347
    other.children_.clear();
9✔
348
    other.transitions_.clear();
9✔
349
};
9✔
350

351
Block& StructuredSDFGBuilder::add_block(Sequence& parent,
437✔
352
                                        const sdfg::symbolic::Assignments& assignments,
353
                                        const DebugInfo& debug_info) {
354
    parent.children_.push_back(
437✔
355
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
437✔
356
    this->element_counter_++;
437✔
357
    parent.transitions_.push_back(std::unique_ptr<Transition>(
437✔
358
        new Transition(this->element_counter_, debug_info, assignments)));
437✔
359
    this->element_counter_++;
437✔
360

361
    return static_cast<Block&>(*parent.children_.back().get());
437✔
UNCOV
362
};
×
363

364
Block& StructuredSDFGBuilder::add_block(Sequence& parent,
82✔
365
                                        const data_flow::DataFlowGraph& data_flow_graph,
366
                                        const sdfg::symbolic::Assignments& assignments,
367
                                        const DebugInfo& debug_info) {
368
    parent.children_.push_back(
82✔
369
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
82✔
370
    this->element_counter_++;
82✔
371
    parent.transitions_.push_back(std::unique_ptr<Transition>(
82✔
372
        new Transition(this->element_counter_, debug_info, assignments)));
82✔
373
    this->element_counter_++;
82✔
374

375
    return static_cast<Block&>(*parent.children_.back().get());
82✔
UNCOV
376
};
×
377

378
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
12✔
379
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
380
    // Insert block before current block
381
    int index = -1;
12✔
382
    for (size_t i = 0; i < parent.children_.size(); i++) {
13✔
383
        if (parent.children_.at(i).get() == &block) {
13✔
384
            index = i;
12✔
385
            break;
12✔
386
        }
387
    }
1✔
388
    assert(index > -1);
12✔
389

390
    parent.children_.insert(parent.children_.begin() + index,
12✔
391
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
12✔
392
    this->element_counter_++;
12✔
393
    parent.transitions_.insert(
12✔
394
        parent.transitions_.begin() + index,
12✔
395
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
12✔
396
    this->element_counter_++;
12✔
397
    auto new_entry = parent.at(index);
12✔
398
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
12✔
399

400
    return {new_block, new_entry.second};
12✔
UNCOV
401
};
×
402

403
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
404
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph,
405
    const DebugInfo& debug_info) {
406
    // Insert block before current block
407
    int index = -1;
×
408
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
409
        if (parent.children_.at(i).get() == &block) {
×
410
            index = i;
×
411
            break;
×
412
        }
UNCOV
413
    }
×
414
    assert(index > -1);
×
415

416
    parent.children_.insert(
×
417
        parent.children_.begin() + index,
×
418
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
419
    this->element_counter_++;
×
420
    parent.transitions_.insert(
×
421
        parent.transitions_.begin() + index,
×
422
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
423
    this->element_counter_++;
×
424
    auto new_entry = parent.at(index);
×
425
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
426

427
    return {new_block, new_entry.second};
×
UNCOV
428
};
×
429

430
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(Sequence& parent,
2✔
431
                                                                      ControlFlowNode& block,
432
                                                                      const DebugInfo& debug_info) {
433
    // Insert block before current block
434
    int index = -1;
2✔
435
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
436
        if (parent.children_.at(i).get() == &block) {
3✔
437
            index = i;
2✔
438
            break;
2✔
439
        }
440
    }
1✔
441
    assert(index > -1);
2✔
442

443
    parent.children_.insert(parent.children_.begin() + index + 1,
2✔
444
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
2✔
445
    this->element_counter_++;
2✔
446
    parent.transitions_.insert(
2✔
447
        parent.transitions_.begin() + index + 1,
2✔
448
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
449
    this->element_counter_++;
2✔
450
    auto new_entry = parent.at(index + 1);
2✔
451
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
2✔
452

453
    return {new_block, new_entry.second};
2✔
UNCOV
454
};
×
455

456
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
457
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph,
458
    const DebugInfo& debug_info) {
459
    int index = -1;
×
460
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
461
        if (parent.children_.at(i).get() == &block) {
×
462
            index = i;
×
463
            break;
×
464
        }
UNCOV
465
    }
×
466
    assert(index > -1);
×
467

468
    parent.children_.insert(
×
469
        parent.children_.begin() + index + 1,
×
470
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
471
    this->element_counter_++;
×
472
    parent.transitions_.insert(
×
473
        parent.transitions_.begin() + index + 1,
×
474
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
475
    this->element_counter_++;
×
476
    auto new_entry = parent.at(index + 1);
×
477
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
478

479
    return {new_block, new_entry.second};
×
UNCOV
480
};
×
481

482
For& StructuredSDFGBuilder::add_for(Sequence& parent, const symbolic::Symbol& indvar,
266✔
483
                                    const symbolic::Condition& condition,
484
                                    const symbolic::Expression& init,
485
                                    const symbolic::Expression& update,
486
                                    const sdfg::symbolic::Assignments& assignments,
487
                                    const DebugInfo& debug_info) {
488
    parent.children_.push_back(std::unique_ptr<For>(
532✔
489
        new For(this->element_counter_, debug_info, indvar, init, update, condition)));
266✔
490
    this->element_counter_ = this->element_counter_ + 2;
266✔
491
    parent.transitions_.push_back(std::unique_ptr<Transition>(
266✔
492
        new Transition(this->element_counter_, debug_info, assignments)));
266✔
493
    this->element_counter_++;
266✔
494

495
    return static_cast<For&>(*parent.children_.back().get());
266✔
UNCOV
496
};
×
497

498
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_before(
51✔
499
    Sequence& parent, ControlFlowNode& block, const symbolic::Symbol& indvar,
500
    const symbolic::Condition& condition, const symbolic::Expression& init,
501
    const symbolic::Expression& update, const DebugInfo& debug_info) {
502
    // Insert block before current block
503
    int index = -1;
51✔
504
    for (size_t i = 0; i < parent.children_.size(); i++) {
73✔
505
        if (parent.children_.at(i).get() == &block) {
73✔
506
            index = i;
51✔
507
            break;
51✔
508
        }
509
    }
22✔
510
    assert(index > -1);
51✔
511

512
    parent.children_.insert(parent.children_.begin() + index,
102✔
513
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
102✔
514
                                                         init, update, condition)));
51✔
515
    this->element_counter_ = this->element_counter_ + 2;
51✔
516
    parent.transitions_.insert(
51✔
517
        parent.transitions_.begin() + index,
51✔
518
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
51✔
519
    this->element_counter_++;
51✔
520
    auto new_entry = parent.at(index);
51✔
521
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
51✔
522

523
    return {new_block, new_entry.second};
51✔
UNCOV
524
};
×
525

526
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_after(
2✔
527
    Sequence& parent, ControlFlowNode& block, const symbolic::Symbol& indvar,
528
    const symbolic::Condition& condition, const symbolic::Expression& init,
529
    const symbolic::Expression& update, const DebugInfo& debug_info) {
530
    // Insert block before current block
531
    int index = -1;
2✔
532
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
533
        if (parent.children_.at(i).get() == &block) {
3✔
534
            index = i;
2✔
535
            break;
2✔
536
        }
537
    }
1✔
538
    assert(index > -1);
2✔
539

540
    parent.children_.insert(parent.children_.begin() + index + 1,
4✔
541
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
4✔
542
                                                         init, update, condition)));
2✔
543
    this->element_counter_ = this->element_counter_ + 2;
2✔
544
    parent.transitions_.insert(
2✔
545
        parent.transitions_.begin() + index + 1,
2✔
546
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
547
    this->element_counter_++;
2✔
548
    auto new_entry = parent.at(index + 1);
2✔
549
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
2✔
550

551
    return {new_block, new_entry.second};
2✔
UNCOV
552
};
×
553

554
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent, const DebugInfo& debug_info) {
35✔
555
    return this->add_if_else(parent, symbolic::Assignments{}, debug_info);
35✔
UNCOV
556
};
×
557

558
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent,
37✔
559
                                           const sdfg::symbolic::Assignments& assignments,
560
                                           const DebugInfo& debug_info) {
561
    parent.children_.push_back(
37✔
562
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
37✔
563
    this->element_counter_++;
37✔
564
    parent.transitions_.push_back(std::unique_ptr<Transition>(
37✔
565
        new Transition(this->element_counter_, debug_info, assignments)));
37✔
566
    this->element_counter_++;
37✔
567
    return static_cast<IfElse&>(*parent.children_.back().get());
37✔
UNCOV
568
};
×
569

570
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::add_if_else_before(
2✔
571
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
572
    // Insert block before current block
573
    int index = -1;
2✔
574
    for (size_t i = 0; i < parent.children_.size(); i++) {
2✔
575
        if (parent.children_.at(i).get() == &block) {
2✔
576
            index = i;
2✔
577
            break;
2✔
578
        }
UNCOV
579
    }
×
580
    assert(index > -1);
2✔
581

582
    parent.children_.insert(
2✔
583
        parent.children_.begin() + index,
2✔
584
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
2✔
585
    this->element_counter_++;
2✔
586
    parent.transitions_.insert(
2✔
587
        parent.transitions_.begin() + index,
2✔
588
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
589
    this->element_counter_++;
2✔
590
    auto new_entry = parent.at(index);
2✔
591
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
2✔
592

593
    return {new_block, new_entry.second};
2✔
UNCOV
594
};
×
595

596
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond,
61✔
597
                                          const DebugInfo& debug_info) {
598
    scope.cases_.push_back(
61✔
599
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
61✔
600
    this->element_counter_++;
61✔
601
    scope.conditions_.push_back(cond);
61✔
602
    return *scope.cases_.back();
61✔
UNCOV
603
};
×
604

605
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t i, const DebugInfo& debug_info) {
3✔
606
    scope.cases_.erase(scope.cases_.begin() + i);
3✔
607
    scope.conditions_.erase(scope.conditions_.begin() + i);
3✔
608
};
3✔
609

610
While& StructuredSDFGBuilder::add_while(Sequence& parent,
28✔
611
                                        const sdfg::symbolic::Assignments& assignments,
612
                                        const DebugInfo& debug_info) {
613
    parent.children_.push_back(
28✔
614
        std::unique_ptr<While>(new While(this->element_counter_, debug_info)));
28✔
615
    this->element_counter_ = this->element_counter_ + 2;
28✔
616
    parent.transitions_.push_back(std::unique_ptr<Transition>(
28✔
617
        new Transition(this->element_counter_, debug_info, assignments)));
28✔
618
    this->element_counter_++;
28✔
619
    return static_cast<While&>(*parent.children_.back().get());
28✔
UNCOV
620
};
×
621

622
Kernel& StructuredSDFGBuilder::add_kernel(
14✔
623
    Sequence& parent, const std::string& suffix, const DebugInfo& debug_info,
624
    const symbolic::Expression& gridDim_x_init, const symbolic::Expression& gridDim_y_init,
625
    const symbolic::Expression& gridDim_z_init, const symbolic::Expression& blockDim_x_init,
626
    const symbolic::Expression& blockDim_y_init, const symbolic::Expression& blockDim_z_init,
627
    const symbolic::Expression& blockIdx_x_init, const symbolic::Expression& blockIdx_y_init,
628
    const symbolic::Expression& blockIdx_z_init, const symbolic::Expression& threadIdx_x_init,
629
    const symbolic::Expression& threadIdx_y_init, const symbolic::Expression& threadIdx_z_init) {
630
    parent.children_.push_back(std::unique_ptr<Kernel>(new Kernel(
28✔
631
        this->element_counter_, debug_info, suffix, gridDim_x_init, gridDim_y_init, gridDim_z_init,
14✔
632
        blockDim_x_init, blockDim_y_init, blockDim_z_init, blockIdx_x_init, blockIdx_y_init,
14✔
633
        blockIdx_z_init, threadIdx_x_init, threadIdx_y_init, threadIdx_z_init)));
14✔
634
    this->element_counter_ = this->element_counter_ + 2;
14✔
635
    parent.transitions_.push_back(
14✔
636
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
14✔
637
    this->element_counter_++;
14✔
638
    return static_cast<Kernel&>(*parent.children_.back().get());
14✔
UNCOV
639
};
×
640

641
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent, const DebugInfo& debug_info) {
10✔
642
    return this->add_continue(parent, symbolic::Assignments{}, debug_info);
10✔
UNCOV
643
};
×
644

645
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent,
11✔
646
                                              const sdfg::symbolic::Assignments& assignments,
647
                                              const DebugInfo& debug_info) {
648
    parent.children_.push_back(
11✔
649
        std::unique_ptr<Continue>(new Continue(this->element_counter_, debug_info)));
11✔
650
    this->element_counter_++;
11✔
651
    parent.transitions_.push_back(std::unique_ptr<Transition>(
11✔
652
        new Transition(this->element_counter_, debug_info, assignments)));
11✔
653
    this->element_counter_++;
11✔
654
    return static_cast<Continue&>(*parent.children_.back().get());
11✔
UNCOV
655
};
×
656

657
Break& StructuredSDFGBuilder::add_break(Sequence& parent, const DebugInfo& debug_info) {
11✔
658
    return this->add_break(parent, symbolic::Assignments{}, debug_info);
11✔
UNCOV
659
};
×
660

661
Break& StructuredSDFGBuilder::add_break(Sequence& parent,
12✔
662
                                        const sdfg::symbolic::Assignments& assignments,
663
                                        const DebugInfo& debug_info) {
664
    parent.children_.push_back(
12✔
665
        std::unique_ptr<Break>(new Break(this->element_counter_, debug_info)));
12✔
666
    this->element_counter_++;
12✔
667
    parent.transitions_.push_back(std::unique_ptr<Transition>(
12✔
668
        new Transition(this->element_counter_, debug_info, assignments)));
12✔
669
    this->element_counter_++;
12✔
670
    return static_cast<Break&>(*parent.children_.back().get());
12✔
UNCOV
671
};
×
672

673
Return& StructuredSDFGBuilder::add_return(Sequence& parent,
10✔
674
                                          const sdfg::symbolic::Assignments& assignments,
675
                                          const DebugInfo& debug_info) {
676
    parent.children_.push_back(
10✔
677
        std::unique_ptr<Return>(new Return(this->element_counter_, debug_info)));
10✔
678
    this->element_counter_++;
10✔
679
    parent.transitions_.push_back(std::unique_ptr<Transition>(
10✔
680
        new Transition(this->element_counter_, debug_info, assignments)));
10✔
681
    this->element_counter_++;
10✔
682
    return static_cast<Return&>(*parent.children_.back().get());
10✔
UNCOV
683
};
×
684

685
For& StructuredSDFGBuilder::convert_while(Sequence& parent, While& loop,
×
686
                                          const symbolic::Symbol& indvar,
687
                                          const symbolic::Condition& condition,
688
                                          const symbolic::Expression& init,
689
                                          const symbolic::Expression& update) {
690
    // Insert for loop
691
    size_t index = 0;
×
692
    for (auto& entry : parent.children_) {
×
693
        if (entry.get() == &loop) {
×
694
            break;
×
695
        }
696
        index++;
×
697
    }
698
    auto iter = parent.children_.begin() + index;
×
699
    auto& new_iter = *parent.children_.insert(
×
700
        iter + 1, std::unique_ptr<For>(new For(this->element_counter_, loop.debug_info(), indvar,
×
701
                                               init, update, condition)));
×
702
    this->element_counter_ = this->element_counter_ + 2;
×
703
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
704
    this->insert_children(for_loop.root(), loop.root(), 0);
×
705

706
    // Remove while loop
707
    parent.children_.erase(parent.children_.begin() + index);
×
708

709
    return for_loop;
×
UNCOV
710
};
×
711

712
void StructuredSDFGBuilder::clear_sequence(Sequence& parent) {
2✔
713
    parent.children_.clear();
2✔
714
    parent.transitions_.clear();
2✔
715
};
2✔
716

717
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
96✔
718
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
96✔
719
    while (!queue.empty()) {
206✔
720
        auto current = queue.front();
206✔
721
        queue.pop_front();
206✔
722

723
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
206✔
724
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
282✔
725
                if (&sequence_stmt->at(i).first == &node) {
230✔
726
                    return *sequence_stmt;
96✔
727
                }
728
                queue.push_back(&sequence_stmt->at(i).first);
134✔
729
            }
134✔
730
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
110✔
731
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
732
                queue.push_back(&if_else_stmt->at(i).first);
×
UNCOV
733
            }
×
734
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
58✔
735
            queue.push_back(&while_stmt->root());
×
736
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
58✔
737
            queue.push_back(&for_stmt->root());
58✔
738
        } else if (auto kern_stmt = dynamic_cast<const structured_control_flow::Kernel*>(current)) {
58✔
UNCOV
739
            queue.push_back(&kern_stmt->root());
×
UNCOV
740
        }
×
741
    }
742

743
    return this->structured_sdfg_->root();
×
744
};
96✔
745

746
Kernel& StructuredSDFGBuilder::convert_into_kernel() {
5✔
747
    auto old_root = std::move(this->structured_sdfg_->root_);
5✔
748
    this->structured_sdfg_->root_ =
5✔
749
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, old_root->debug_info()));
5✔
750
    this->element_counter_++;
5✔
751
    auto& new_root = this->structured_sdfg_->root();
5✔
752
    auto& kernel = this->add_kernel(new_root, this->function().name());
5✔
753

754
    this->insert_children(kernel.root(), *old_root, 0);
5✔
755

756
    types::Scalar gridDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
757
    add_container(kernel.gridDim_x()->get_name(), gridDim_x);
5✔
758
    types::Scalar gridDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
759
    add_container(kernel.gridDim_y()->get_name(), gridDim_y);
5✔
760
    types::Scalar gridDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
761
    add_container(kernel.gridDim_z()->get_name(), gridDim_z);
5✔
762
    types::Scalar blockDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
763
    add_container(kernel.blockDim_x()->get_name(), blockDim_x);
5✔
764
    types::Scalar blockDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
765
    add_container(kernel.blockDim_y()->get_name(), blockDim_y);
5✔
766
    types::Scalar blockDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
767
    add_container(kernel.blockDim_z()->get_name(), blockDim_z);
5✔
768
    types::Scalar blockIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
769
    add_container(kernel.blockIdx_x()->get_name(), blockIdx_x);
5✔
770
    types::Scalar blockIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
771
    add_container(kernel.blockIdx_y()->get_name(), blockIdx_y);
5✔
772
    types::Scalar blockIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
773
    add_container(kernel.blockIdx_z()->get_name(), blockIdx_z);
5✔
774
    types::Scalar threadIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
775
    add_container(kernel.threadIdx_x()->get_name(), threadIdx_x);
5✔
776
    types::Scalar threadIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
777
    add_container(kernel.threadIdx_y()->get_name(), threadIdx_y);
5✔
778
    types::Scalar threadIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
5✔
779
    add_container(kernel.threadIdx_z()->get_name(), threadIdx_z);
5✔
780

781
    kernel.root().replace(symbolic::symbol("gridDim.x"), kernel.gridDim_x());
5✔
782
    kernel.root().replace(symbolic::symbol("gridDim.y"), kernel.gridDim_y());
5✔
783
    kernel.root().replace(symbolic::symbol("gridDim.z"), kernel.gridDim_z());
5✔
784

785
    kernel.root().replace(symbolic::symbol("blockDim.x"), kernel.blockDim_x());
5✔
786
    kernel.root().replace(symbolic::symbol("blockDim.y"), kernel.blockDim_y());
5✔
787
    kernel.root().replace(symbolic::symbol("blockDim.z"), kernel.blockDim_z());
5✔
788

789
    kernel.root().replace(symbolic::symbol("blockIdx.x"), kernel.blockIdx_x());
5✔
790
    kernel.root().replace(symbolic::symbol("blockIdx.y"), kernel.blockIdx_y());
5✔
791
    kernel.root().replace(symbolic::symbol("blockIdx.z"), kernel.blockIdx_z());
5✔
792

793
    kernel.root().replace(symbolic::symbol("threadIdx.x"), kernel.threadIdx_x());
5✔
794
    kernel.root().replace(symbolic::symbol("threadIdx.y"), kernel.threadIdx_y());
5✔
795
    kernel.root().replace(symbolic::symbol("threadIdx.z"), kernel.threadIdx_z());
5✔
796

797
    return kernel;
5✔
798
};
5✔
799

800
/***** Section: Dataflow Graph *****/
801

802
data_flow::AccessNode& StructuredSDFGBuilder::add_access(structured_control_flow::Block& block,
822✔
803
                                                         const std::string& data,
804
                                                         const DebugInfo& debug_info) {
805
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
822✔
806
    auto res = block.dataflow_->nodes_.insert(
1,644✔
807
        {vertex, std::unique_ptr<data_flow::AccessNode>(new data_flow::AccessNode(
822✔
808
                     this->element_counter_, debug_info, vertex, block.dataflow(), data))});
822✔
809
    this->element_counter_++;
822✔
810
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
822✔
UNCOV
811
};
×
812

813
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
364✔
814
    structured_control_flow::Block& block, const data_flow::TaskletCode code,
815
    const std::pair<std::string, sdfg::types::Scalar>& output,
816
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
817
    const DebugInfo& debug_info) {
818
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
364✔
819
    auto res = block.dataflow_->nodes_.insert(
728✔
820
        {vertex, std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
728✔
821
                     this->element_counter_, debug_info, vertex, block.dataflow(), code, output,
364✔
822
                     inputs, symbolic::__true__()))});
364✔
823
    this->element_counter_++;
364✔
824
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
364✔
UNCOV
825
};
×
826

827
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
871✔
828
    structured_control_flow::Block& block, data_flow::DataFlowNode& src,
829
    const std::string& src_conn, data_flow::DataFlowNode& dst, const std::string& dst_conn,
830
    const data_flow::Subset& subset, const DebugInfo& debug_info) {
831
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
871✔
832
    auto res = block.dataflow_->edges_.insert(
1,742✔
833
        {edge.first, std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
871✔
834
                         this->element_counter_, debug_info, edge.first, block.dataflow(), src,
871✔
835
                         src_conn, dst, dst_conn, subset))});
871✔
836
    this->element_counter_++;
871✔
837
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
871✔
UNCOV
838
};
×
839

840
data_flow::LibraryNode& StructuredSDFGBuilder::add_library_node(
9✔
841
    structured_control_flow::Block& block, const data_flow::LibraryNodeType& call,
842
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& outputs,
843
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
844
    const bool has_side_effect, const DebugInfo& debug_info) {
845
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
9✔
846
    auto res = block.dataflow_->nodes_.insert(
18✔
847
        {vertex, std::unique_ptr<data_flow::LibraryNode>(new data_flow::LibraryNode(
9✔
848
                     this->element_counter_, debug_info, vertex, block.dataflow(), outputs, inputs,
9✔
849
                     call, has_side_effect))});
9✔
850
    this->element_counter_++;
9✔
851
    return dynamic_cast<data_flow::LibraryNode&>(*(res.first->second));
9✔
UNCOV
852
}
×
853

854
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block,
×
855
                                          const data_flow::Memlet& edge) {
856
    auto& graph = block.dataflow();
×
857
    auto e = edge.edge();
×
858
    boost::remove_edge(e, graph.graph_);
×
859
    graph.edges_.erase(e);
×
860
};
×
861

862
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block,
×
863
                                        const data_flow::DataFlowNode& node) {
864
    auto& graph = block.dataflow();
×
865
    auto v = node.vertex();
×
866
    boost::remove_vertex(v, graph.graph_);
×
867
    graph.nodes_.erase(v);
×
868
};
×
869

870
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
8✔
871
                                       const data_flow::Tasklet& node) {
872
    auto& graph = block.dataflow();
8✔
873
    auto vertex = node.vertex();
8✔
874

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

877
    // Delete incoming
878
    std::list<const data_flow::Memlet*> iedges;
8✔
879
    for (auto& iedge : graph.in_edges(node)) {
15✔
880
        iedges.push_back(&iedge);
7✔
881
    }
882
    for (auto iedge : iedges) {
15✔
883
        auto& src = iedge->src();
7✔
884
        to_delete.insert(&src);
7✔
885

886
        auto edge = iedge->edge();
7✔
887
        graph.edges_.erase(edge);
7✔
888
        boost::remove_edge(edge, graph.graph_);
7✔
889
    }
890

891
    // Delete outgoing
892
    std::list<const data_flow::Memlet*> oedges;
8✔
893
    for (auto& oedge : graph.out_edges(node)) {
16✔
894
        oedges.push_back(&oedge);
8✔
895
    }
896
    for (auto oedge : oedges) {
16✔
897
        auto& dst = oedge->dst();
8✔
898
        to_delete.insert(&dst);
8✔
899

900
        auto edge = oedge->edge();
8✔
901
        graph.edges_.erase(edge);
8✔
902
        boost::remove_edge(edge, graph.graph_);
8✔
903
    }
904

905
    // Delete nodes
906
    for (auto obsolete_node : to_delete) {
31✔
907
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
908
            auto vertex = obsolete_node->vertex();
23✔
909
            graph.nodes_.erase(vertex);
23✔
910
            boost::remove_vertex(vertex, graph.graph_);
23✔
911
        }
23✔
912
    }
913
};
8✔
914

915
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
1✔
916
                                       const data_flow::AccessNode& node) {
917
    auto& graph = block.dataflow();
1✔
918
    auto vertex = node.vertex();
1✔
919
    assert(graph.out_degree(node) == 0);
1✔
920

921
    std::list<const data_flow::Memlet*> tmp;
1✔
922
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
923
    while (!queue.empty()) {
3✔
924
        auto current = queue.front();
2✔
925
        queue.pop_front();
2✔
926
        if (current != &node) {
2✔
927
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
928
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
929
                    continue;
×
930
                }
UNCOV
931
            }
×
932
        }
1✔
933

934
        tmp.clear();
2✔
935
        for (auto& iedge : graph.in_edges(*current)) {
3✔
936
            tmp.push_back(&iedge);
1✔
937
        }
938
        for (auto iedge : tmp) {
3✔
939
            auto& src = iedge->src();
1✔
940
            queue.push_back(&src);
1✔
941

942
            auto edge = iedge->edge();
1✔
943
            graph.edges_.erase(edge);
1✔
944
            boost::remove_edge(edge, graph.graph_);
1✔
945
        }
946

947
        auto vertex = current->vertex();
2✔
948
        graph.nodes_.erase(vertex);
2✔
949
        boost::remove_vertex(vertex, graph.graph_);
2✔
950
    }
951
};
1✔
952

953
data_flow::AccessNode& StructuredSDFGBuilder::symbolic_expression_to_dataflow(
1✔
954
    structured_control_flow::Block& parent, const symbolic::Expression& expr) {
955
    auto& sdfg = this->subject();
1✔
956

957
    codegen::CPPLanguageExtension language_extension;
1✔
958

959
    // Base cases
960
    if (SymEngine::is_a<SymEngine::Symbol>(*expr)) {
1✔
961
        auto sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(expr);
1✔
962

963
        // Determine type
964
        types::Scalar sym_type = types::Scalar(types::PrimitiveType::Void);
1✔
965
        if (symbolic::is_nvptx(sym)) {
1✔
966
            sym_type = types::Scalar(types::PrimitiveType::Int32);
×
UNCOV
967
        } else {
×
968
            sym_type = static_cast<const types::Scalar&>(sdfg.type(sym->get_name()));
1✔
969
        }
970

971
        // Add new container for intermediate result
972
        auto tmp = this->find_new_name();
1✔
973
        this->add_container(tmp, sym_type);
1✔
974

975
        // Create dataflow graph
976
        auto& input_node = this->add_access(parent, sym->get_name());
1✔
977
        auto& output_node = this->add_access(parent, tmp);
1✔
978
        auto& tasklet = this->add_tasklet(parent, data_flow::TaskletCode::assign,
2✔
979
                                          {"_out", sym_type}, {{"_in", sym_type}});
1✔
980
        this->add_memlet(parent, input_node, "void", tasklet, "_in", {symbolic::integer(0)});
1✔
981
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
1✔
982

983
        return output_node;
1✔
984
    } else if (SymEngine::is_a<SymEngine::Integer>(*expr)) {
1✔
985
        auto tmp = this->find_new_name();
×
986
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Int64));
×
987

988
        auto& output_node = this->add_access(parent, tmp);
×
989
        auto& tasklet = this->add_tasklet(
×
UNCOV
990
            parent, data_flow::TaskletCode::assign,
×
991
            {"_out", types::Scalar(types::PrimitiveType::Int64)},
×
992
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Int64)}});
×
993
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
994
        return output_node;
×
995
    } else if (SymEngine::is_a<SymEngine::BooleanAtom>(*expr)) {
×
996
        auto tmp = this->find_new_name();
×
997
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
998

999
        auto& output_node = this->add_access(parent, tmp);
×
1000
        auto& tasklet = this->add_tasklet(
×
UNCOV
1001
            parent, data_flow::TaskletCode::assign,
×
1002
            {"_out", types::Scalar(types::PrimitiveType::Bool)},
×
1003
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Bool)}});
×
1004
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1005
        return output_node;
×
1006
    } else if (SymEngine::is_a<SymEngine::Or>(*expr)) {
×
1007
        auto or_expr = SymEngine::rcp_static_cast<const SymEngine::Or>(expr);
×
1008
        assert(or_expr->get_container().size() == 2);
×
1009

1010
        std::vector<data_flow::AccessNode*> input_nodes;
×
1011
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1012
        for (auto& arg : or_expr->get_container()) {
×
1013
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1014
            input_nodes.push_back(&input_node);
×
1015
            input_types.push_back(
×
1016
                {"_in" + std::to_string(input_types.size() + 1),
×
1017
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1018
        }
1019

1020
        // Add new container for intermediate result
1021
        auto tmp = this->find_new_name();
×
1022
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1023

1024
        auto& output_node = this->add_access(parent, tmp);
×
UNCOV
1025
        auto& tasklet =
×
1026
            this->add_tasklet(parent, data_flow::TaskletCode::logical_or,
×
1027
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1028
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1029
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1030
                             {symbolic::integer(0)});
×
UNCOV
1031
        }
×
1032
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1033
        return output_node;
×
1034
    } else if (SymEngine::is_a<SymEngine::And>(*expr)) {
×
1035
        auto and_expr = SymEngine::rcp_static_cast<const SymEngine::And>(expr);
×
1036
        assert(and_expr->get_container().size() == 2);
×
1037

1038
        std::vector<data_flow::AccessNode*> input_nodes;
×
1039
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1040
        for (auto& arg : and_expr->get_container()) {
×
1041
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1042
            input_nodes.push_back(&input_node);
×
1043
            input_types.push_back(
×
1044
                {"_in" + std::to_string(input_types.size() + 1),
×
1045
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1046
        }
1047

1048
        // Add new container for intermediate result
1049
        auto tmp = this->find_new_name();
×
1050
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1051

1052
        auto& output_node = this->add_access(parent, tmp);
×
UNCOV
1053
        auto& tasklet =
×
1054
            this->add_tasklet(parent, data_flow::TaskletCode::logical_and,
×
1055
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1056
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1057
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1058
                             {symbolic::integer(0)});
×
UNCOV
1059
        }
×
1060
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1061
        return output_node;
×
1062
    } else {
×
1063
        throw std::runtime_error("Unsupported expression type");
×
1064
    }
1065
};
1✔
1066

1067
}  // namespace builder
1068
}  // 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