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

daisytuner / sdfglib / 15023667831

14 May 2025 02:39PM UTC coverage: 57.575% (+0.001%) from 57.574%
15023667831

Pull #12

github

web-flow
Merge 16ac3d549 into 40eb9f9bb
Pull Request #12: Structured Control Flow Conversion and Debugging Options

103 of 111 new or added lines in 3 files covered. (92.79%)

2 existing lines in 1 file now uncovered.

7152 of 12422 relevant lines covered (57.58%)

524.84 hits per line

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

79.12
/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✔
21
            continue;
1✔
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;
2✔
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

NEW
53
    return false;
×
54
}
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✔
NEW
63
            return nullptr;
×
64
        }
65
    }
66

67
    return pdom;
3✔
68
}
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
    }
4✔
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
        }
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
                }
124
            }
125
        }
126
        assert(exit_states.size() == 1 &&
1✔
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✔
NEW
131
            exit_edges.insert(edge);
×
132
        }
133

134
        // 3. Add while loop
135
        While& loop = this->add_while(scope, {}, current->debug_info());
1✔
136
        this->traverse_without_loop_detection(sdfg, loop.root(), current, exit_state, continues,
1✔
137
                                              exit_edges, pdom_tree);
138

139
        this->traverse_with_loop_detection(sdfg, scope, exit_state, end, continues, breaks,
1✔
140
                                           pdom_tree);
141
    } else {
1✔
142
        this->traverse_without_loop_detection(sdfg, scope, current, end, continues, breaks,
14✔
143
                                              pdom_tree);
144
    }
145
};
15✔
146

147
void StructuredSDFGBuilder::traverse_without_loop_detection(
15✔
148
    const SDFG& sdfg, Sequence& scope, const State* current, const State* end,
149
    const std::unordered_set<const InterstateEdge*>& continues,
150
    const std::unordered_set<const InterstateEdge*>& breaks,
151
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree) {
152
    if (current == end) {
15✔
153
        return;
15✔
154
    }
155

156
    auto in_edges = sdfg.in_edges(*current);
15✔
157
    auto out_edges = sdfg.out_edges(*current);
15✔
158
    auto out_degree = sdfg.out_degree(*current);
15✔
159

160
    // Case 1: Sink node
161
    if (out_degree == 0) {
15✔
162
        this->add_block(scope, current->dataflow(), {}, current->debug_info());
4✔
163
        this->add_return(scope, {}, current->debug_info());
4✔
164
        return;
4✔
165
    }
166

167
    // Case 2: Transition
168
    if (out_degree == 1) {
11✔
169
        auto& oedge = *out_edges.begin();
8✔
170
        assert(oedge.is_unconditional() &&
8✔
171
               "Degenerated structured control flow: Non-deterministic transition");
172
        this->add_block(scope, current->dataflow(), oedge.assignments(), current->debug_info());
8✔
173

174
        if (continues.find(&oedge) != continues.end()) {
8✔
NEW
175
            this->add_continue(scope, oedge.debug_info());
×
176
        } else if (breaks.find(&oedge) != breaks.end()) {
8✔
NEW
177
            this->add_break(scope, oedge.debug_info());
×
178
        } else {
179
            this->traverse_with_loop_detection(sdfg, scope, &oedge.dst(), end, continues, breaks,
8✔
180
                                               pdom_tree);
181
        }
182
        return;
8✔
183
    }
184

185
    // Case 3: Branches
186
    if (out_degree > 1) {
3✔
187
        this->add_block(scope, current->dataflow(), {}, current->debug_info());
3✔
188

189
        std::vector<const InterstateEdge*> out_edges_vec;
3✔
190
        for (auto& edge : out_edges) {
9✔
191
            out_edges_vec.push_back(&edge);
6✔
192
        }
193

194
        // Best-effort approach: Find end of if-else
195
        // If not found, the branches may repeat paths yielding a large SDFG
196
        const control_flow::State* local_end =
197
            this->find_end_of_if_else(sdfg, current, out_edges_vec, pdom_tree);
3✔
198
        if (local_end == nullptr) {
3✔
NEW
199
            local_end = end;
×
200
        }
201

202
        auto& if_else = this->add_if_else(scope, current->debug_info());
3✔
203
        for (size_t i = 0; i < out_degree; i++) {
9✔
204
            auto& out_edge = out_edges_vec[i];
6✔
205

206
            auto& branch = this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
207
            if (!out_edge->assignments().empty()) {
6✔
208
                auto& body =
209
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
210
            }
211
            if (continues.find(out_edge) != continues.end()) {
6✔
212
                this->add_continue(branch, out_edge->debug_info());
1✔
213
            } else if (breaks.find(out_edge) != breaks.end()) {
5✔
214
                this->add_break(branch, out_edge->debug_info());
1✔
215
            } else {
216
                this->traverse_with_loop_detection(sdfg, branch, &out_edge->dst(), local_end,
4✔
217
                                                   continues, breaks, pdom_tree);
218
            }
219
        }
220

221
        if (local_end != end) {
3✔
222
            this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues, breaks,
2✔
223
                                               pdom_tree);
224
        }
225

226
        return;
3✔
227
    }
3✔
228
}
229

230
Function& StructuredSDFGBuilder::function() const {
2,197✔
231
    return static_cast<Function&>(*this->structured_sdfg_);
2,197✔
232
};
233

234
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
182✔
235
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)){};
182✔
236

237
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name)
278✔
238
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name)){};
278✔
239

240
StructuredSDFGBuilder::StructuredSDFGBuilder(const SDFG& sdfg)
4✔
241
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(sdfg.name())) {
4✔
242
    for (auto& entry : sdfg.structures_) {
4✔
243
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
244
    }
245

246
    for (auto& entry : sdfg.containers_) {
11✔
247
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
248
    }
249

250
    for (auto& arg : sdfg.arguments_) {
6✔
251
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
252
    }
253

254
    for (auto& ext : sdfg.externals_) {
5✔
255
        this->structured_sdfg_->externals_.push_back(ext);
1✔
256
    }
257

258
    for (auto& entry : sdfg.assumptions_) {
9✔
259
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
260
    }
261

262
    this->traverse(sdfg);
4✔
263
};
4✔
264

265
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
1,228✔
266

267
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
248✔
268
    return std::move(this->structured_sdfg_);
248✔
269
};
270

271
Sequence& StructuredSDFGBuilder::add_sequence(Sequence& parent,
34✔
272
                                              const sdfg::symbolic::Assignments& assignments,
273
                                              const DebugInfo& debug_info) {
274
    parent.children_.push_back(
34✔
275
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
68✔
276
    this->element_counter_++;
34✔
277
    parent.transitions_.push_back(std::unique_ptr<Transition>(
34✔
278
        new Transition(this->element_counter_, debug_info, assignments)));
34✔
279
    this->element_counter_++;
34✔
280

281
    return static_cast<Sequence&>(*parent.children_.back().get());
34✔
282
};
283

284
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::add_sequence_before(
7✔
285
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
286
    // Insert block before current block
287
    int index = -1;
7✔
288
    for (size_t i = 0; i < parent.children_.size(); i++) {
7✔
289
        if (parent.children_.at(i).get() == &block) {
7✔
290
            index = i;
7✔
291
            break;
7✔
292
        }
293
    }
294
    assert(index > -1);
7✔
295

296
    parent.children_.insert(
14✔
297
        parent.children_.begin() + index,
14✔
298
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
14✔
299
    this->element_counter_++;
7✔
300
    parent.transitions_.insert(
7✔
301
        parent.transitions_.begin() + index,
7✔
302
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
14✔
303
    this->element_counter_++;
7✔
304
    auto new_entry = parent.at(index);
7✔
305
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
7✔
306

307
    return {new_block, new_entry.second};
7✔
308
};
309

310
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t i) {
9✔
311
    parent.children_.erase(parent.children_.begin() + i);
9✔
312
    parent.transitions_.erase(parent.transitions_.begin() + i);
9✔
313
};
9✔
314

315
void StructuredSDFGBuilder::remove_child(Sequence& parent, ControlFlowNode& child) {
51✔
316
    int index = -1;
51✔
317
    for (size_t i = 0; i < parent.children_.size(); i++) {
53✔
318
        if (parent.children_.at(i).get() == &child) {
53✔
319
            index = i;
51✔
320
            break;
51✔
321
        }
322
    }
323

324
    parent.children_.erase(parent.children_.begin() + index);
51✔
325
    parent.transitions_.erase(parent.transitions_.begin() + index);
51✔
326
};
51✔
327

328
void StructuredSDFGBuilder::insert_children(Sequence& parent, Sequence& other, size_t i) {
10✔
329
    parent.children_.insert(parent.children_.begin() + i,
10✔
330
                            std::make_move_iterator(other.children_.begin()),
331
                            std::make_move_iterator(other.children_.end()));
332
    parent.transitions_.insert(parent.transitions_.begin() + i,
10✔
333
                               std::make_move_iterator(other.transitions_.begin()),
334
                               std::make_move_iterator(other.transitions_.end()));
335
    other.children_.clear();
10✔
336
    other.transitions_.clear();
10✔
337
};
10✔
338

339
Block& StructuredSDFGBuilder::add_block(Sequence& parent,
440✔
340
                                        const sdfg::symbolic::Assignments& assignments,
341
                                        const DebugInfo& debug_info) {
342
    parent.children_.push_back(
440✔
343
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
880✔
344
    this->element_counter_++;
440✔
345
    parent.transitions_.push_back(std::unique_ptr<Transition>(
440✔
346
        new Transition(this->element_counter_, debug_info, assignments)));
440✔
347
    this->element_counter_++;
440✔
348

349
    return static_cast<Block&>(*parent.children_.back().get());
440✔
350
};
351

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

363
    return static_cast<Block&>(*parent.children_.back().get());
82✔
364
};
365

366
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
12✔
367
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
368
    // Insert block before current block
369
    int index = -1;
12✔
370
    for (size_t i = 0; i < parent.children_.size(); i++) {
13✔
371
        if (parent.children_.at(i).get() == &block) {
13✔
372
            index = i;
12✔
373
            break;
12✔
374
        }
375
    }
376
    assert(index > -1);
12✔
377

378
    parent.children_.insert(parent.children_.begin() + index,
12✔
379
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
24✔
380
    this->element_counter_++;
12✔
381
    parent.transitions_.insert(
12✔
382
        parent.transitions_.begin() + index,
12✔
383
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
24✔
384
    this->element_counter_++;
12✔
385
    auto new_entry = parent.at(index);
12✔
386
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
12✔
387

388
    return {new_block, new_entry.second};
12✔
389
};
390

391
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
392
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph,
393
    const DebugInfo& debug_info) {
394
    // Insert block before current block
395
    int index = -1;
×
396
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
397
        if (parent.children_.at(i).get() == &block) {
×
398
            index = i;
×
399
            break;
×
400
        }
401
    }
402
    assert(index > -1);
×
403

404
    parent.children_.insert(
×
405
        parent.children_.begin() + index,
×
406
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
407
    this->element_counter_++;
×
408
    parent.transitions_.insert(
×
409
        parent.transitions_.begin() + index,
×
410
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
411
    this->element_counter_++;
×
412
    auto new_entry = parent.at(index);
×
413
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
414

415
    return {new_block, new_entry.second};
×
416
};
417

418
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(Sequence& parent,
2✔
419
                                                                      ControlFlowNode& block,
420
                                                                      const DebugInfo& debug_info) {
421
    // Insert block before current block
422
    int index = -1;
2✔
423
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
424
        if (parent.children_.at(i).get() == &block) {
3✔
425
            index = i;
2✔
426
            break;
2✔
427
        }
428
    }
429
    assert(index > -1);
2✔
430

431
    parent.children_.insert(parent.children_.begin() + index + 1,
2✔
432
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
4✔
433
    this->element_counter_++;
2✔
434
    parent.transitions_.insert(
2✔
435
        parent.transitions_.begin() + index + 1,
2✔
436
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
4✔
437
    this->element_counter_++;
2✔
438
    auto new_entry = parent.at(index + 1);
2✔
439
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
2✔
440

441
    return {new_block, new_entry.second};
2✔
442
};
443

444
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
445
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph,
446
    const DebugInfo& debug_info) {
447
    int index = -1;
×
448
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
449
        if (parent.children_.at(i).get() == &block) {
×
450
            index = i;
×
451
            break;
×
452
        }
453
    }
454
    assert(index > -1);
×
455

456
    parent.children_.insert(
×
457
        parent.children_.begin() + index + 1,
×
458
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
459
    this->element_counter_++;
×
460
    parent.transitions_.insert(
×
461
        parent.transitions_.begin() + index + 1,
×
462
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
463
    this->element_counter_++;
×
464
    auto new_entry = parent.at(index + 1);
×
465
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
466

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

470
For& StructuredSDFGBuilder::add_for(Sequence& parent, const symbolic::Symbol& indvar,
269✔
471
                                    const symbolic::Condition& condition,
472
                                    const symbolic::Expression& init,
473
                                    const symbolic::Expression& update,
474
                                    const sdfg::symbolic::Assignments& assignments,
475
                                    const DebugInfo& debug_info) {
476
    parent.children_.push_back(std::unique_ptr<For>(
538✔
477
        new For(this->element_counter_, debug_info, indvar, init, update, condition)));
269✔
478
    this->element_counter_ = this->element_counter_ + 2;
269✔
479
    parent.transitions_.push_back(std::unique_ptr<Transition>(
269✔
480
        new Transition(this->element_counter_, debug_info, assignments)));
269✔
481
    this->element_counter_++;
269✔
482

483
    return static_cast<For&>(*parent.children_.back().get());
269✔
484
};
485

486
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_before(
51✔
487
    Sequence& parent, ControlFlowNode& block, const symbolic::Symbol& indvar,
488
    const symbolic::Condition& condition, const symbolic::Expression& init,
489
    const symbolic::Expression& update, const DebugInfo& debug_info) {
490
    // Insert block before current block
491
    int index = -1;
51✔
492
    for (size_t i = 0; i < parent.children_.size(); i++) {
73✔
493
        if (parent.children_.at(i).get() == &block) {
73✔
494
            index = i;
51✔
495
            break;
51✔
496
        }
497
    }
498
    assert(index > -1);
51✔
499

500
    parent.children_.insert(parent.children_.begin() + index,
51✔
501
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
153✔
502
                                                         init, update, condition)));
51✔
503
    this->element_counter_ = this->element_counter_ + 2;
51✔
504
    parent.transitions_.insert(
51✔
505
        parent.transitions_.begin() + index,
51✔
506
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
102✔
507
    this->element_counter_++;
51✔
508
    auto new_entry = parent.at(index);
51✔
509
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
51✔
510

511
    return {new_block, new_entry.second};
51✔
512
};
513

514
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_after(
2✔
515
    Sequence& parent, ControlFlowNode& block, const symbolic::Symbol& indvar,
516
    const symbolic::Condition& condition, const symbolic::Expression& init,
517
    const symbolic::Expression& update, const DebugInfo& debug_info) {
518
    // Insert block before current block
519
    int index = -1;
2✔
520
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
521
        if (parent.children_.at(i).get() == &block) {
3✔
522
            index = i;
2✔
523
            break;
2✔
524
        }
525
    }
526
    assert(index > -1);
2✔
527

528
    parent.children_.insert(parent.children_.begin() + index + 1,
2✔
529
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
6✔
530
                                                         init, update, condition)));
2✔
531
    this->element_counter_ = this->element_counter_ + 2;
2✔
532
    parent.transitions_.insert(
2✔
533
        parent.transitions_.begin() + index + 1,
2✔
534
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
4✔
535
    this->element_counter_++;
2✔
536
    auto new_entry = parent.at(index + 1);
2✔
537
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
2✔
538

539
    return {new_block, new_entry.second};
2✔
540
};
541

542
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent, const DebugInfo& debug_info) {
35✔
543
    return this->add_if_else(parent, symbolic::Assignments{}, debug_info);
35✔
544
};
545

546
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent,
37✔
547
                                           const sdfg::symbolic::Assignments& assignments,
548
                                           const DebugInfo& debug_info) {
549
    parent.children_.push_back(
37✔
550
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
74✔
551
    this->element_counter_++;
37✔
552
    parent.transitions_.push_back(std::unique_ptr<Transition>(
37✔
553
        new Transition(this->element_counter_, debug_info, assignments)));
37✔
554
    this->element_counter_++;
37✔
555
    return static_cast<IfElse&>(*parent.children_.back().get());
37✔
556
};
557

558
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::add_if_else_before(
3✔
559
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
560
    // Insert block before current block
561
    int index = -1;
3✔
562
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
563
        if (parent.children_.at(i).get() == &block) {
3✔
564
            index = i;
3✔
565
            break;
3✔
566
        }
567
    }
568
    assert(index > -1);
3✔
569

570
    parent.children_.insert(
6✔
571
        parent.children_.begin() + index,
6✔
572
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
6✔
573
    this->element_counter_++;
3✔
574
    parent.transitions_.insert(
3✔
575
        parent.transitions_.begin() + index,
3✔
576
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
6✔
577
    this->element_counter_++;
3✔
578
    auto new_entry = parent.at(index);
3✔
579
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
3✔
580

581
    return {new_block, new_entry.second};
3✔
582
};
583

584
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond,
62✔
585
                                          const DebugInfo& debug_info) {
586
    scope.cases_.push_back(
62✔
587
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
124✔
588
    this->element_counter_++;
62✔
589
    scope.conditions_.push_back(cond);
62✔
590
    return *scope.cases_.back();
62✔
591
};
592

593
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t i, const DebugInfo& debug_info) {
3✔
594
    scope.cases_.erase(scope.cases_.begin() + i);
3✔
595
    scope.conditions_.erase(scope.conditions_.begin() + i);
3✔
596
};
3✔
597

598
While& StructuredSDFGBuilder::add_while(Sequence& parent,
28✔
599
                                        const sdfg::symbolic::Assignments& assignments,
600
                                        const DebugInfo& debug_info) {
601
    parent.children_.push_back(
28✔
602
        std::unique_ptr<While>(new While(this->element_counter_, debug_info)));
56✔
603
    this->element_counter_ = this->element_counter_ + 2;
28✔
604
    parent.transitions_.push_back(std::unique_ptr<Transition>(
28✔
605
        new Transition(this->element_counter_, debug_info, assignments)));
28✔
606
    this->element_counter_++;
28✔
607
    return static_cast<While&>(*parent.children_.back().get());
28✔
608
};
609

610
Kernel& StructuredSDFGBuilder::add_kernel(
15✔
611
    Sequence& parent, const std::string& suffix, const DebugInfo& debug_info,
612
    const symbolic::Expression& gridDim_x_init, const symbolic::Expression& gridDim_y_init,
613
    const symbolic::Expression& gridDim_z_init, const symbolic::Expression& blockDim_x_init,
614
    const symbolic::Expression& blockDim_y_init, const symbolic::Expression& blockDim_z_init,
615
    const symbolic::Expression& blockIdx_x_init, const symbolic::Expression& blockIdx_y_init,
616
    const symbolic::Expression& blockIdx_z_init, const symbolic::Expression& threadIdx_x_init,
617
    const symbolic::Expression& threadIdx_y_init, const symbolic::Expression& threadIdx_z_init) {
618
    parent.children_.push_back(std::unique_ptr<Kernel>(new Kernel(
30✔
619
        this->element_counter_, debug_info, suffix, gridDim_x_init, gridDim_y_init, gridDim_z_init,
620
        blockDim_x_init, blockDim_y_init, blockDim_z_init, blockIdx_x_init, blockIdx_y_init,
621
        blockIdx_z_init, threadIdx_x_init, threadIdx_y_init, threadIdx_z_init)));
15✔
622
    this->element_counter_ = this->element_counter_ + 2;
15✔
623
    parent.transitions_.push_back(
15✔
624
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
30✔
625
    this->element_counter_++;
15✔
626
    return static_cast<Kernel&>(*parent.children_.back().get());
15✔
627
};
628

629
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent, const DebugInfo& debug_info) {
10✔
630
    return this->add_continue(parent, symbolic::Assignments{}, debug_info);
10✔
631
};
632

633
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent,
11✔
634
                                              const sdfg::symbolic::Assignments& assignments,
635
                                              const DebugInfo& debug_info) {
636
    parent.children_.push_back(
11✔
637
        std::unique_ptr<Continue>(new Continue(this->element_counter_, debug_info)));
22✔
638
    this->element_counter_++;
11✔
639
    parent.transitions_.push_back(std::unique_ptr<Transition>(
11✔
640
        new Transition(this->element_counter_, debug_info, assignments)));
11✔
641
    this->element_counter_++;
11✔
642
    return static_cast<Continue&>(*parent.children_.back().get());
11✔
643
};
644

645
Break& StructuredSDFGBuilder::add_break(Sequence& parent, const DebugInfo& debug_info) {
11✔
646
    return this->add_break(parent, symbolic::Assignments{}, debug_info);
11✔
647
};
648

649
Break& StructuredSDFGBuilder::add_break(Sequence& parent,
12✔
650
                                        const sdfg::symbolic::Assignments& assignments,
651
                                        const DebugInfo& debug_info) {
652
    parent.children_.push_back(
12✔
653
        std::unique_ptr<Break>(new Break(this->element_counter_, debug_info)));
24✔
654
    this->element_counter_++;
12✔
655
    parent.transitions_.push_back(std::unique_ptr<Transition>(
12✔
656
        new Transition(this->element_counter_, debug_info, assignments)));
12✔
657
    this->element_counter_++;
12✔
658
    return static_cast<Break&>(*parent.children_.back().get());
12✔
659
};
660

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

673
For& StructuredSDFGBuilder::convert_while(Sequence& parent, While& loop,
×
674
                                          const symbolic::Symbol& indvar,
675
                                          const symbolic::Condition& condition,
676
                                          const symbolic::Expression& init,
677
                                          const symbolic::Expression& update) {
678
    // Insert for loop
679
    size_t index = 0;
×
680
    for (auto& entry : parent.children_) {
×
681
        if (entry.get() == &loop) {
×
682
            break;
×
683
        }
684
        index++;
×
685
    }
686
    auto iter = parent.children_.begin() + index;
×
687
    auto& new_iter = *parent.children_.insert(
×
688
        iter + 1, std::unique_ptr<For>(new For(this->element_counter_, loop.debug_info(), indvar,
×
689
                                               init, update, condition)));
×
690
    this->element_counter_ = this->element_counter_ + 2;
×
691
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
692
    this->insert_children(for_loop.root(), loop.root(), 0);
×
693

694
    // Remove while loop
695
    parent.children_.erase(parent.children_.begin() + index);
×
696

697
    return for_loop;
×
698
};
699

700
void StructuredSDFGBuilder::clear_sequence(Sequence& parent) {
2✔
701
    parent.children_.clear();
2✔
702
    parent.transitions_.clear();
2✔
703
};
2✔
704

705
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
99✔
706
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
99✔
707
    while (!queue.empty()) {
215✔
708
        auto current = queue.front();
215✔
709
        queue.pop_front();
215✔
710

711
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
215✔
712
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
291✔
713
                if (&sequence_stmt->at(i).first == &node) {
236✔
714
                    return *sequence_stmt;
99✔
715
                }
716
                queue.push_back(&sequence_stmt->at(i).first);
137✔
717
            }
718
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
61✔
719
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
720
                queue.push_back(&if_else_stmt->at(i).first);
×
721
            }
722
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
61✔
723
            queue.push_back(&while_stmt->root());
×
724
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
61✔
725
            queue.push_back(&for_stmt->root());
60✔
726
        } else if (auto kern_stmt = dynamic_cast<const structured_control_flow::Kernel*>(current)) {
1✔
727
            queue.push_back(&kern_stmt->root());
1✔
728
        }
729
    }
730

731
    return this->structured_sdfg_->root();
×
732
};
99✔
733

734
Kernel& StructuredSDFGBuilder::convert_into_kernel() {
5✔
735
    auto old_root = std::move(this->structured_sdfg_->root_);
5✔
736
    this->structured_sdfg_->root_ =
5✔
737
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, old_root->debug_info()));
10✔
738
    this->element_counter_++;
5✔
739
    auto& new_root = this->structured_sdfg_->root();
5✔
740
    auto& kernel = this->add_kernel(new_root, this->function().name());
5✔
741

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

744
    types::Scalar gridDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
745
    add_container(kernel.gridDim_x()->get_name(), gridDim_x);
5✔
746
    types::Scalar gridDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
747
    add_container(kernel.gridDim_y()->get_name(), gridDim_y);
5✔
748
    types::Scalar gridDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
749
    add_container(kernel.gridDim_z()->get_name(), gridDim_z);
5✔
750
    types::Scalar blockDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
751
    add_container(kernel.blockDim_x()->get_name(), blockDim_x);
5✔
752
    types::Scalar blockDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
753
    add_container(kernel.blockDim_y()->get_name(), blockDim_y);
5✔
754
    types::Scalar blockDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
755
    add_container(kernel.blockDim_z()->get_name(), blockDim_z);
5✔
756
    types::Scalar blockIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
757
    add_container(kernel.blockIdx_x()->get_name(), blockIdx_x);
5✔
758
    types::Scalar blockIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
759
    add_container(kernel.blockIdx_y()->get_name(), blockIdx_y);
5✔
760
    types::Scalar blockIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
761
    add_container(kernel.blockIdx_z()->get_name(), blockIdx_z);
5✔
762
    types::Scalar threadIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
763
    add_container(kernel.threadIdx_x()->get_name(), threadIdx_x);
5✔
764
    types::Scalar threadIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
765
    add_container(kernel.threadIdx_y()->get_name(), threadIdx_y);
5✔
766
    types::Scalar threadIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
10✔
767
    add_container(kernel.threadIdx_z()->get_name(), threadIdx_z);
5✔
768

769
    kernel.root().replace(symbolic::symbol("gridDim.x"), kernel.gridDim_x());
5✔
770
    kernel.root().replace(symbolic::symbol("gridDim.y"), kernel.gridDim_y());
5✔
771
    kernel.root().replace(symbolic::symbol("gridDim.z"), kernel.gridDim_z());
5✔
772

773
    kernel.root().replace(symbolic::symbol("blockDim.x"), kernel.blockDim_x());
5✔
774
    kernel.root().replace(symbolic::symbol("blockDim.y"), kernel.blockDim_y());
5✔
775
    kernel.root().replace(symbolic::symbol("blockDim.z"), kernel.blockDim_z());
5✔
776

777
    kernel.root().replace(symbolic::symbol("blockIdx.x"), kernel.blockIdx_x());
5✔
778
    kernel.root().replace(symbolic::symbol("blockIdx.y"), kernel.blockIdx_y());
5✔
779
    kernel.root().replace(symbolic::symbol("blockIdx.z"), kernel.blockIdx_z());
5✔
780

781
    kernel.root().replace(symbolic::symbol("threadIdx.x"), kernel.threadIdx_x());
5✔
782
    kernel.root().replace(symbolic::symbol("threadIdx.y"), kernel.threadIdx_y());
5✔
783
    kernel.root().replace(symbolic::symbol("threadIdx.z"), kernel.threadIdx_z());
5✔
784

785
    return kernel;
5✔
786
};
5✔
787

788
/***** Section: Dataflow Graph *****/
789

790
data_flow::AccessNode& StructuredSDFGBuilder::add_access(structured_control_flow::Block& block,
826✔
791
                                                         const std::string& data,
792
                                                         const DebugInfo& debug_info) {
793
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
826✔
794
    auto res = block.dataflow_->nodes_.insert(
1,652✔
795
        {vertex, std::unique_ptr<data_flow::AccessNode>(new data_flow::AccessNode(
1,652✔
796
                     this->element_counter_, debug_info, vertex, block.dataflow(), data))});
826✔
797
    this->element_counter_++;
826✔
798
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
826✔
799
};
800

801
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
366✔
802
    structured_control_flow::Block& block, const data_flow::TaskletCode code,
803
    const std::pair<std::string, sdfg::types::Scalar>& output,
804
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
805
    const DebugInfo& debug_info) {
806
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
366✔
807
    auto res = block.dataflow_->nodes_.insert(
732✔
808
        {vertex, std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
732✔
809
                     this->element_counter_, debug_info, vertex, block.dataflow(), code, output,
366✔
810
                     inputs, symbolic::__true__()))});
732✔
811
    this->element_counter_++;
366✔
812
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
366✔
813
};
814

815
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
875✔
816
    structured_control_flow::Block& block, data_flow::DataFlowNode& src,
817
    const std::string& src_conn, data_flow::DataFlowNode& dst, const std::string& dst_conn,
818
    const data_flow::Subset& subset, const DebugInfo& debug_info) {
819
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
875✔
820
    auto res = block.dataflow_->edges_.insert(
1,750✔
821
        {edge.first, std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,750✔
822
                         this->element_counter_, debug_info, edge.first, block.dataflow(), src,
875✔
823
                         src_conn, dst, dst_conn, subset))});
875✔
824
    this->element_counter_++;
875✔
825
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
1,750✔
826
};
827

828
data_flow::LibraryNode& StructuredSDFGBuilder::add_library_node(
10✔
829
    structured_control_flow::Block& block, const data_flow::LibraryNodeType& call,
830
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& outputs,
831
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
832
    const bool has_side_effect, const DebugInfo& debug_info) {
833
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
10✔
834
    auto res = block.dataflow_->nodes_.insert(
20✔
835
        {vertex, std::unique_ptr<data_flow::LibraryNode>(new data_flow::LibraryNode(
20✔
836
                     this->element_counter_, debug_info, vertex, block.dataflow(), outputs, inputs,
10✔
837
                     call, has_side_effect))});
10✔
838
    this->element_counter_++;
10✔
839
    return dynamic_cast<data_flow::LibraryNode&>(*(res.first->second));
10✔
840
}
841

842
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block,
×
843
                                          const data_flow::Memlet& edge) {
844
    auto& graph = block.dataflow();
×
845
    auto e = edge.edge();
×
846
    boost::remove_edge(e, graph.graph_);
×
847
    graph.edges_.erase(e);
×
848
};
×
849

850
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block,
×
851
                                        const data_flow::DataFlowNode& node) {
852
    auto& graph = block.dataflow();
×
853
    auto v = node.vertex();
×
854
    boost::remove_vertex(v, graph.graph_);
×
855
    graph.nodes_.erase(v);
×
856
};
×
857

858
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
8✔
859
                                       const data_flow::Tasklet& node) {
860
    auto& graph = block.dataflow();
8✔
861
    auto vertex = node.vertex();
8✔
862

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

865
    // Delete incoming
866
    std::list<const data_flow::Memlet*> iedges;
8✔
867
    for (auto& iedge : graph.in_edges(node)) {
15✔
868
        iedges.push_back(&iedge);
7✔
869
    }
870
    for (auto iedge : iedges) {
15✔
871
        auto& src = iedge->src();
7✔
872
        to_delete.insert(&src);
7✔
873

874
        auto edge = iedge->edge();
7✔
875
        graph.edges_.erase(edge);
7✔
876
        boost::remove_edge(edge, graph.graph_);
7✔
877
    }
878

879
    // Delete outgoing
880
    std::list<const data_flow::Memlet*> oedges;
8✔
881
    for (auto& oedge : graph.out_edges(node)) {
16✔
882
        oedges.push_back(&oedge);
8✔
883
    }
884
    for (auto oedge : oedges) {
16✔
885
        auto& dst = oedge->dst();
8✔
886
        to_delete.insert(&dst);
8✔
887

888
        auto edge = oedge->edge();
8✔
889
        graph.edges_.erase(edge);
8✔
890
        boost::remove_edge(edge, graph.graph_);
8✔
891
    }
892

893
    // Delete nodes
894
    for (auto obsolete_node : to_delete) {
31✔
895
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
896
            auto vertex = obsolete_node->vertex();
23✔
897
            graph.nodes_.erase(vertex);
23✔
898
            boost::remove_vertex(vertex, graph.graph_);
23✔
899
        }
900
    }
901
};
8✔
902

903
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
1✔
904
                                       const data_flow::AccessNode& node) {
905
    auto& graph = block.dataflow();
1✔
906
    auto vertex = node.vertex();
1✔
907
    assert(graph.out_degree(node) == 0);
1✔
908

909
    std::list<const data_flow::Memlet*> tmp;
1✔
910
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
911
    while (!queue.empty()) {
3✔
912
        auto current = queue.front();
2✔
913
        queue.pop_front();
2✔
914
        if (current != &node) {
2✔
915
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
916
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
917
                    continue;
×
918
                }
919
            }
920
        }
921

922
        tmp.clear();
2✔
923
        for (auto& iedge : graph.in_edges(*current)) {
3✔
924
            tmp.push_back(&iedge);
1✔
925
        }
926
        for (auto iedge : tmp) {
3✔
927
            auto& src = iedge->src();
1✔
928
            queue.push_back(&src);
1✔
929

930
            auto edge = iedge->edge();
1✔
931
            graph.edges_.erase(edge);
1✔
932
            boost::remove_edge(edge, graph.graph_);
1✔
933
        }
934

935
        auto vertex = current->vertex();
2✔
936
        graph.nodes_.erase(vertex);
2✔
937
        boost::remove_vertex(vertex, graph.graph_);
2✔
938
    }
939
};
1✔
940

941
data_flow::AccessNode& StructuredSDFGBuilder::symbolic_expression_to_dataflow(
1✔
942
    structured_control_flow::Block& parent, const symbolic::Expression& expr) {
943
    auto& sdfg = this->subject();
1✔
944

945
    codegen::CPPLanguageExtension language_extension;
1✔
946

947
    // Base cases
948
    if (SymEngine::is_a<SymEngine::Symbol>(*expr)) {
1✔
949
        auto sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(expr);
1✔
950

951
        // Determine type
952
        types::Scalar sym_type = types::Scalar(types::PrimitiveType::Void);
2✔
953
        if (symbolic::is_nvptx(sym)) {
1✔
954
            sym_type = types::Scalar(types::PrimitiveType::Int32);
×
955
        } else {
956
            sym_type = static_cast<const types::Scalar&>(sdfg.type(sym->get_name()));
1✔
957
        }
958

959
        // Add new container for intermediate result
960
        auto tmp = this->find_new_name();
2✔
961
        this->add_container(tmp, sym_type);
1✔
962

963
        // Create dataflow graph
964
        auto& input_node = this->add_access(parent, sym->get_name());
1✔
965
        auto& output_node = this->add_access(parent, tmp);
1✔
966
        auto& tasklet = this->add_tasklet(parent, data_flow::TaskletCode::assign,
2✔
967
                                          {"_out", sym_type}, {{"_in", sym_type}});
968
        this->add_memlet(parent, input_node, "void", tasklet, "_in", {symbolic::integer(0)});
2✔
969
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
2✔
970

971
        return output_node;
1✔
972
    } else if (SymEngine::is_a<SymEngine::Integer>(*expr)) {
1✔
973
        auto tmp = this->find_new_name();
×
974
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Int64));
×
975

976
        auto& output_node = this->add_access(parent, tmp);
×
977
        auto& tasklet = this->add_tasklet(
×
978
            parent, data_flow::TaskletCode::assign,
979
            {"_out", types::Scalar(types::PrimitiveType::Int64)},
×
980
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Int64)}});
×
981
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
982
        return output_node;
×
983
    } else if (SymEngine::is_a<SymEngine::BooleanAtom>(*expr)) {
×
984
        auto tmp = this->find_new_name();
×
985
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
986

987
        auto& output_node = this->add_access(parent, tmp);
×
988
        auto& tasklet = this->add_tasklet(
×
989
            parent, data_flow::TaskletCode::assign,
990
            {"_out", types::Scalar(types::PrimitiveType::Bool)},
×
991
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Bool)}});
×
992
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
993
        return output_node;
×
994
    } else if (SymEngine::is_a<SymEngine::Or>(*expr)) {
×
995
        auto or_expr = SymEngine::rcp_static_cast<const SymEngine::Or>(expr);
×
996
        assert(or_expr->get_container().size() == 2);
×
997

998
        std::vector<data_flow::AccessNode*> input_nodes;
×
999
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1000
        for (auto& arg : or_expr->get_container()) {
×
1001
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1002
            input_nodes.push_back(&input_node);
×
1003
            input_types.push_back(
×
1004
                {"_in" + std::to_string(input_types.size() + 1),
×
1005
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1006
        }
1007

1008
        // Add new container for intermediate result
1009
        auto tmp = this->find_new_name();
×
1010
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1011

1012
        auto& output_node = this->add_access(parent, tmp);
×
1013
        auto& tasklet =
1014
            this->add_tasklet(parent, data_flow::TaskletCode::logical_or,
×
1015
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1016
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1017
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1018
                             {symbolic::integer(0)});
×
1019
        }
1020
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1021
        return output_node;
×
1022
    } else if (SymEngine::is_a<SymEngine::And>(*expr)) {
×
1023
        auto and_expr = SymEngine::rcp_static_cast<const SymEngine::And>(expr);
×
1024
        assert(and_expr->get_container().size() == 2);
×
1025

1026
        std::vector<data_flow::AccessNode*> input_nodes;
×
1027
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1028
        for (auto& arg : and_expr->get_container()) {
×
1029
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1030
            input_nodes.push_back(&input_node);
×
1031
            input_types.push_back(
×
1032
                {"_in" + std::to_string(input_types.size() + 1),
×
1033
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1034
        }
1035

1036
        // Add new container for intermediate result
1037
        auto tmp = this->find_new_name();
×
1038
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1039

1040
        auto& output_node = this->add_access(parent, tmp);
×
1041
        auto& tasklet =
1042
            this->add_tasklet(parent, data_flow::TaskletCode::logical_and,
×
1043
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1044
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1045
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1046
                             {symbolic::integer(0)});
×
1047
        }
1048
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1049
        return output_node;
×
1050
    } else {
×
1051
        throw std::runtime_error("Unsupported expression type");
×
1052
    }
1053
};
1054

1055
}  // namespace builder
1056
}  // 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