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

daisytuner / sdfglib / 15206971294

23 May 2025 09:24AM UTC coverage: 60.604% (+0.1%) from 60.482%
15206971294

Pull #26

github

web-flow
Merge 14900737f into aa7d2127d
Pull Request #26: Develop Map node

254 of 387 new or added lines in 26 files covered. (65.63%)

17 existing lines in 14 files now uncovered.

8264 of 13636 relevant lines covered (60.6%)

101.91 hits per line

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

71.84
/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
#include "sdfg/structured_control_flow/map.h"
6
#include "sdfg/structured_control_flow/sequence.h"
7

8
using namespace sdfg::control_flow;
9
using namespace sdfg::structured_control_flow;
10

11
namespace sdfg {
12
namespace builder {
13

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

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

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

37
    return nodes;
1✔
38
};
1✔
39

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

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

55
    return false;
×
56
}
6✔
57

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

69
    return pdom;
3✔
70
}
3✔
71

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

77
    auto pdom_tree = sdfg.post_dominator_tree();
4✔
78

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

85
    std::unordered_set<const control_flow::State*> visited;
4✔
86
    this->traverse_with_loop_detection(sdfg, root, start_state, nullptr, continues, breaks,
4✔
87
                                       pdom_tree, visited);
88
};
4✔
89

90
void StructuredSDFGBuilder::traverse_with_loop_detection(
9✔
91
    const SDFG& sdfg, Sequence& scope, const State* current, const State* end,
92
    const std::unordered_set<const InterstateEdge*>& continues,
93
    const std::unordered_set<const InterstateEdge*>& breaks,
94
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
95
    std::unordered_set<const control_flow::State*>& visited) {
96
    if (current == end) {
9✔
97
        return;
1✔
98
    }
99

100
    auto in_edges = sdfg.in_edges(*current);
8✔
101

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

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

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

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

148
        // 3. Add while loop
149
        While& loop = this->add_while(scope, {}, dbg_info);
1✔
150

151
        std::unordered_set<const control_flow::State*> loop_visited(visited);
1✔
152
        this->traverse_without_loop_detection(sdfg, loop.root(), current, exit_state, continues,
1✔
153
                                              exit_edges, pdom_tree, loop_visited);
1✔
154

155
        this->traverse_with_loop_detection(sdfg, scope, exit_state, end, continues, breaks,
2✔
156
                                           pdom_tree, visited);
1✔
157
    } else {
1✔
158
        this->traverse_without_loop_detection(sdfg, scope, current, end, continues, breaks,
14✔
159
                                              pdom_tree, visited);
7✔
160
    }
161
};
9✔
162

163
void StructuredSDFGBuilder::traverse_without_loop_detection(
8✔
164
    const SDFG& sdfg, Sequence& scope, const State* current, const State* end,
165
    const std::unordered_set<const InterstateEdge*>& continues,
166
    const std::unordered_set<const InterstateEdge*>& breaks,
167
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
168
    std::unordered_set<const control_flow::State*>& visited) {
169
    std::list<const State*> queue = {current};
8✔
170
    while (!queue.empty()) {
26✔
171
        auto curr = queue.front();
18✔
172
        queue.pop_front();
18✔
173
        if (curr == end) {
18✔
174
            continue;
3✔
175
        }
176

177
        if (visited.find(curr) != visited.end()) {
15✔
178
            throw UnstructuredControlFlowException();
×
179
        }
180
        visited.insert(curr);
15✔
181

182
        auto out_edges = sdfg.out_edges(*curr);
15✔
183
        auto out_degree = sdfg.out_degree(*curr);
15✔
184

185
        // Case 1: Sink node
186
        if (out_degree == 0) {
15✔
187
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
4✔
188
            this->add_return(scope, {}, curr->debug_info());
4✔
189
            continue;
4✔
190
        }
191

192
        // Case 2: Transition
193
        if (out_degree == 1) {
11✔
194
            auto& oedge = *out_edges.begin();
8✔
195
            assert(oedge.is_unconditional() &&
16✔
196
                   "Degenerated structured control flow: Non-deterministic transition");
197
            this->add_block(scope, curr->dataflow(), oedge.assignments(), curr->debug_info());
8✔
198

199
            if (continues.find(&oedge) != continues.end()) {
8✔
200
                this->add_continue(scope, oedge.debug_info());
×
201
            } else if (breaks.find(&oedge) != breaks.end()) {
8✔
202
                this->add_break(scope, oedge.debug_info());
×
203
            } else {
×
204
                bool starts_loop = false;
8✔
205
                for (auto& iedge : sdfg.in_edges(oedge.dst())) {
19✔
206
                    if (continues.find(&iedge) != continues.end()) {
11✔
207
                        starts_loop = true;
×
208
                        break;
×
209
                    }
210
                }
211
                if (!starts_loop) {
8✔
212
                    queue.push_back(&oedge.dst());
8✔
213
                } else {
8✔
214
                    this->traverse_with_loop_detection(sdfg, scope, &oedge.dst(), end, continues,
×
215
                                                       breaks, pdom_tree, visited);
×
216
                }
217
            }
218
            continue;
8✔
219
        }
220

221
        // Case 3: Branches
222
        if (out_degree > 1) {
3✔
223
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
3✔
224

225
            std::vector<const InterstateEdge*> out_edges_vec;
3✔
226
            for (auto& edge : out_edges) {
9✔
227
                out_edges_vec.push_back(&edge);
6✔
228
            }
229

230
            // Best-effort approach: Find end of if-else
231
            // If not found, the branches may repeat paths yielding a large SDFG
232
            const control_flow::State* local_end =
3✔
233
                this->find_end_of_if_else(sdfg, curr, out_edges_vec, pdom_tree);
3✔
234
            if (local_end == nullptr) {
3✔
235
                local_end = end;
×
236
            }
×
237

238
            auto& if_else = this->add_if_else(scope, curr->debug_info());
3✔
239
            for (size_t i = 0; i < out_degree; i++) {
9✔
240
                auto& out_edge = out_edges_vec[i];
6✔
241

242
                auto& branch =
6✔
243
                    this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
244
                if (!out_edge->assignments().empty()) {
6✔
245
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
246
                }
2✔
247
                if (continues.find(out_edge) != continues.end()) {
6✔
248
                    this->add_continue(branch, out_edge->debug_info());
1✔
249
                } else if (breaks.find(out_edge) != breaks.end()) {
6✔
250
                    this->add_break(branch, out_edge->debug_info());
1✔
251
                } else {
1✔
252
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
4✔
253
                    this->traverse_with_loop_detection(sdfg, branch, &out_edge->dst(), local_end,
4✔
254
                                                       continues, breaks, pdom_tree,
4✔
255
                                                       branch_visited);
256
                }
4✔
257
            }
6✔
258

259
            if (local_end != end) {
3✔
260
                bool starts_loop = false;
2✔
261
                for (auto& iedge : sdfg.in_edges(*local_end)) {
6✔
262
                    if (continues.find(&iedge) != continues.end()) {
4✔
263
                        starts_loop = true;
×
264
                        break;
×
265
                    }
266
                }
267
                if (!starts_loop) {
2✔
268
                    queue.push_back(local_end);
2✔
269
                } else {
2✔
270
                    this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues,
×
271
                                                       breaks, pdom_tree, visited);
×
272
                }
273
            }
2✔
274
            continue;
275
        }
3✔
276
    }
277
}
8✔
278

279
Function& StructuredSDFGBuilder::function() const {
1,738✔
280
    return static_cast<Function&>(*this->structured_sdfg_);
1,738✔
281
};
282

283
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
320✔
284
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
320✔
285

286
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name)
477✔
287
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name)) {};
477✔
288

289
StructuredSDFGBuilder::StructuredSDFGBuilder(const SDFG& sdfg)
4✔
290
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(sdfg.name())) {
4✔
291
    for (auto& entry : sdfg.structures_) {
4✔
292
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
293
    }
294

295
    for (auto& entry : sdfg.containers_) {
11✔
296
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
297
    }
298

299
    for (auto& arg : sdfg.arguments_) {
6✔
300
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
301
    }
302

303
    for (auto& ext : sdfg.externals_) {
5✔
304
        this->structured_sdfg_->externals_.push_back(ext);
1✔
305
    }
306

307
    for (auto& entry : sdfg.assumptions_) {
9✔
308
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
309
    }
310

311
    for (auto& entry : sdfg.metadata_) {
6✔
312
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
313
    }
314

315
    this->traverse(sdfg);
4✔
316
};
4✔
317

318
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
2,570✔
319

320
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
443✔
321
    return std::move(this->structured_sdfg_);
443✔
322
};
323

324
Sequence& StructuredSDFGBuilder::add_sequence(Sequence& parent,
36✔
325
                                              const sdfg::symbolic::Assignments& assignments,
326
                                              const DebugInfo& debug_info) {
327
    parent.children_.push_back(
36✔
328
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
36✔
329
    this->element_counter_++;
36✔
330
    parent.transitions_.push_back(std::unique_ptr<Transition>(
36✔
331
        new Transition(this->element_counter_, debug_info, assignments)));
36✔
332
    this->element_counter_++;
36✔
333

334
    return static_cast<Sequence&>(*parent.children_.back().get());
36✔
335
};
×
336

337
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::add_sequence_before(
4✔
338
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
339
    // Insert block before current block
340
    int index = -1;
4✔
341
    for (size_t i = 0; i < parent.children_.size(); i++) {
4✔
342
        if (parent.children_.at(i).get() == &block) {
4✔
343
            index = i;
4✔
344
            break;
4✔
345
        }
346
    }
×
347
    assert(index > -1);
4✔
348

349
    parent.children_.insert(
4✔
350
        parent.children_.begin() + index,
4✔
351
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
4✔
352
    this->element_counter_++;
4✔
353
    parent.transitions_.insert(
4✔
354
        parent.transitions_.begin() + index,
4✔
355
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
4✔
356
    this->element_counter_++;
4✔
357
    auto new_entry = parent.at(index);
4✔
358
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
4✔
359

360
    return {new_block, new_entry.second};
4✔
361
};
×
362

363
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t i) {
7✔
364
    parent.children_.erase(parent.children_.begin() + i);
7✔
365
    parent.transitions_.erase(parent.transitions_.begin() + i);
7✔
366
};
7✔
367

368
void StructuredSDFGBuilder::remove_child(Sequence& parent, ControlFlowNode& child) {
3✔
369
    int index = -1;
3✔
370
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
371
        if (parent.children_.at(i).get() == &child) {
3✔
372
            index = i;
3✔
373
            break;
3✔
374
        }
375
    }
×
376

377
    parent.children_.erase(parent.children_.begin() + index);
3✔
378
    parent.transitions_.erase(parent.transitions_.begin() + index);
3✔
379
};
3✔
380

381
void StructuredSDFGBuilder::insert_children(Sequence& parent, Sequence& other, size_t i) {
14✔
382
    parent.children_.insert(parent.children_.begin() + i,
28✔
383
                            std::make_move_iterator(other.children_.begin()),
14✔
384
                            std::make_move_iterator(other.children_.end()));
14✔
385
    parent.transitions_.insert(parent.transitions_.begin() + i,
28✔
386
                               std::make_move_iterator(other.transitions_.begin()),
14✔
387
                               std::make_move_iterator(other.transitions_.end()));
14✔
388
    other.children_.clear();
14✔
389
    other.transitions_.clear();
14✔
390
};
14✔
391

392
Block& StructuredSDFGBuilder::add_block(Sequence& parent,
481✔
393
                                        const sdfg::symbolic::Assignments& assignments,
394
                                        const DebugInfo& debug_info) {
395
    parent.children_.push_back(
481✔
396
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
481✔
397
    this->element_counter_++;
481✔
398
    parent.transitions_.push_back(std::unique_ptr<Transition>(
481✔
399
        new Transition(this->element_counter_, debug_info, assignments)));
481✔
400
    this->element_counter_++;
481✔
401
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
481✔
402
    (*new_block.dataflow_).parent_ = &new_block;
481✔
403

404
    return new_block;
481✔
405
};
×
406

407
Block& StructuredSDFGBuilder::add_block(Sequence& parent,
28✔
408
                                        const data_flow::DataFlowGraph& data_flow_graph,
409
                                        const sdfg::symbolic::Assignments& assignments,
410
                                        const DebugInfo& debug_info) {
411
    parent.children_.push_back(
28✔
412
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
28✔
413
    this->element_counter_++;
28✔
414
    parent.transitions_.push_back(std::unique_ptr<Transition>(
28✔
415
        new Transition(this->element_counter_, debug_info, assignments)));
28✔
416
    this->element_counter_++;
28✔
417
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
28✔
418
    (*new_block.dataflow_).parent_ = &new_block;
28✔
419

420
    return new_block;
28✔
421
};
×
422

423
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
12✔
424
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
425
    // Insert block before current block
426
    int index = -1;
12✔
427
    for (size_t i = 0; i < parent.children_.size(); i++) {
13✔
428
        if (parent.children_.at(i).get() == &block) {
13✔
429
            index = i;
12✔
430
            break;
12✔
431
        }
432
    }
1✔
433
    assert(index > -1);
12✔
434

435
    parent.children_.insert(parent.children_.begin() + index,
12✔
436
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
12✔
437
    this->element_counter_++;
12✔
438
    parent.transitions_.insert(
12✔
439
        parent.transitions_.begin() + index,
12✔
440
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
12✔
441
    this->element_counter_++;
12✔
442
    auto new_entry = parent.at(index);
12✔
443
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
12✔
444
    (*new_block.dataflow_).parent_ = &new_block;
12✔
445

446
    return {new_block, new_entry.second};
12✔
447
};
×
448

449
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
450
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph,
451
    const DebugInfo& debug_info) {
452
    // Insert block before current block
453
    int index = -1;
×
454
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
455
        if (parent.children_.at(i).get() == &block) {
×
456
            index = i;
×
457
            break;
×
458
        }
459
    }
×
460
    assert(index > -1);
×
461

462
    parent.children_.insert(
×
463
        parent.children_.begin() + index,
×
464
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
465
    this->element_counter_++;
×
466
    parent.transitions_.insert(
×
467
        parent.transitions_.begin() + index,
×
468
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
469
    this->element_counter_++;
×
470
    auto new_entry = parent.at(index);
×
471
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
472
    (*new_block.dataflow_).parent_ = &new_block;
×
473

474
    return {new_block, new_entry.second};
×
475
};
×
476

477
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(Sequence& parent,
2✔
478
                                                                      ControlFlowNode& block,
479
                                                                      const DebugInfo& debug_info) {
480
    // Insert block before current block
481
    int index = -1;
2✔
482
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
483
        if (parent.children_.at(i).get() == &block) {
3✔
484
            index = i;
2✔
485
            break;
2✔
486
        }
487
    }
1✔
488
    assert(index > -1);
2✔
489

490
    parent.children_.insert(parent.children_.begin() + index + 1,
2✔
491
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
2✔
492
    this->element_counter_++;
2✔
493
    parent.transitions_.insert(
2✔
494
        parent.transitions_.begin() + index + 1,
2✔
495
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
496
    this->element_counter_++;
2✔
497
    auto new_entry = parent.at(index + 1);
2✔
498
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
2✔
499
    (*new_block.dataflow_).parent_ = &new_block;
2✔
500

501
    return {new_block, new_entry.second};
2✔
502
};
×
503

504
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
505
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph,
506
    const DebugInfo& debug_info) {
507
    int index = -1;
×
508
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
509
        if (parent.children_.at(i).get() == &block) {
×
510
            index = i;
×
511
            break;
×
512
        }
513
    }
×
514
    assert(index > -1);
×
515

516
    parent.children_.insert(
×
517
        parent.children_.begin() + index + 1,
×
518
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
519
    this->element_counter_++;
×
520
    parent.transitions_.insert(
×
521
        parent.transitions_.begin() + index + 1,
×
522
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
523
    this->element_counter_++;
×
524
    auto new_entry = parent.at(index + 1);
×
525
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
526
    (*new_block.dataflow_).parent_ = &new_block;
×
527

528
    return {new_block, new_entry.second};
×
529
};
×
530

531
For& StructuredSDFGBuilder::add_for(Sequence& parent, const symbolic::Symbol& indvar,
123✔
532
                                    const symbolic::Condition& condition,
533
                                    const symbolic::Expression& init,
534
                                    const symbolic::Expression& update,
535
                                    const sdfg::symbolic::Assignments& assignments,
536
                                    const DebugInfo& debug_info) {
537
    parent.children_.push_back(std::unique_ptr<For>(
246✔
538
        new For(this->element_counter_, debug_info, indvar, init, update, condition)));
123✔
539
    this->element_counter_ = this->element_counter_ + 2;
123✔
540
    parent.transitions_.push_back(std::unique_ptr<Transition>(
123✔
541
        new Transition(this->element_counter_, debug_info, assignments)));
123✔
542
    this->element_counter_++;
123✔
543

544
    return static_cast<For&>(*parent.children_.back().get());
123✔
545
};
×
546

547
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_before(
4✔
548
    Sequence& parent, ControlFlowNode& block, const symbolic::Symbol& indvar,
549
    const symbolic::Condition& condition, const symbolic::Expression& init,
550
    const symbolic::Expression& update, const DebugInfo& debug_info) {
551
    // Insert block before current block
552
    int index = -1;
4✔
553
    for (size_t i = 0; i < parent.children_.size(); i++) {
4✔
554
        if (parent.children_.at(i).get() == &block) {
4✔
555
            index = i;
4✔
556
            break;
4✔
557
        }
558
    }
×
559
    assert(index > -1);
4✔
560

561
    parent.children_.insert(parent.children_.begin() + index,
8✔
562
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
8✔
563
                                                         init, update, condition)));
4✔
564
    this->element_counter_ = this->element_counter_ + 2;
4✔
565
    parent.transitions_.insert(
4✔
566
        parent.transitions_.begin() + index,
4✔
567
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
4✔
568
    this->element_counter_++;
4✔
569
    auto new_entry = parent.at(index);
4✔
570
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
4✔
571

572
    return {new_block, new_entry.second};
4✔
573
};
×
574

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

589
    parent.children_.insert(parent.children_.begin() + index + 1,
4✔
590
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
4✔
591
                                                         init, update, condition)));
2✔
592
    this->element_counter_ = this->element_counter_ + 2;
2✔
593
    parent.transitions_.insert(
2✔
594
        parent.transitions_.begin() + index + 1,
2✔
595
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
596
    this->element_counter_++;
2✔
597
    auto new_entry = parent.at(index + 1);
2✔
598
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
2✔
599

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

603
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent, const DebugInfo& debug_info) {
35✔
604
    return this->add_if_else(parent, symbolic::Assignments{}, debug_info);
35✔
605
};
×
606

607
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent,
36✔
608
                                           const sdfg::symbolic::Assignments& assignments,
609
                                           const DebugInfo& debug_info) {
610
    parent.children_.push_back(
36✔
611
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
36✔
612
    this->element_counter_++;
36✔
613
    parent.transitions_.push_back(std::unique_ptr<Transition>(
36✔
614
        new Transition(this->element_counter_, debug_info, assignments)));
36✔
615
    this->element_counter_++;
36✔
616
    return static_cast<IfElse&>(*parent.children_.back().get());
36✔
617
};
×
618

619
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::add_if_else_before(
1✔
620
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
621
    // Insert block before current block
622
    int index = -1;
1✔
623
    for (size_t i = 0; i < parent.children_.size(); i++) {
1✔
624
        if (parent.children_.at(i).get() == &block) {
1✔
625
            index = i;
1✔
626
            break;
1✔
627
        }
628
    }
×
629
    assert(index > -1);
1✔
630

631
    parent.children_.insert(
1✔
632
        parent.children_.begin() + index,
1✔
633
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
1✔
634
    this->element_counter_++;
1✔
635
    parent.transitions_.insert(
1✔
636
        parent.transitions_.begin() + index,
1✔
637
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
1✔
638
    this->element_counter_++;
1✔
639
    auto new_entry = parent.at(index);
1✔
640
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
1✔
641

642
    return {new_block, new_entry.second};
1✔
643
};
×
644

645
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond,
63✔
646
                                          const DebugInfo& debug_info) {
647
    scope.cases_.push_back(
63✔
648
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
63✔
649
    this->element_counter_++;
63✔
650
    scope.conditions_.push_back(cond);
63✔
651
    return *scope.cases_.back();
63✔
652
};
×
653

654
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t i, const DebugInfo& debug_info) {
1✔
655
    scope.cases_.erase(scope.cases_.begin() + i);
1✔
656
    scope.conditions_.erase(scope.conditions_.begin() + i);
1✔
657
};
1✔
658

659
While& StructuredSDFGBuilder::add_while(Sequence& parent,
38✔
660
                                        const sdfg::symbolic::Assignments& assignments,
661
                                        const DebugInfo& debug_info) {
662
    parent.children_.push_back(
38✔
663
        std::unique_ptr<While>(new While(this->element_counter_, debug_info)));
38✔
664
    this->element_counter_ = this->element_counter_ + 2;
38✔
665
    parent.transitions_.push_back(std::unique_ptr<Transition>(
38✔
666
        new Transition(this->element_counter_, debug_info, assignments)));
38✔
667
    this->element_counter_++;
38✔
668
    return static_cast<While&>(*parent.children_.back().get());
38✔
669
};
×
670

671
Kernel& StructuredSDFGBuilder::add_kernel(
18✔
672
    Sequence& parent, const std::string& suffix, const DebugInfo& debug_info,
673
    const symbolic::Expression& gridDim_x_init, const symbolic::Expression& gridDim_y_init,
674
    const symbolic::Expression& gridDim_z_init, const symbolic::Expression& blockDim_x_init,
675
    const symbolic::Expression& blockDim_y_init, const symbolic::Expression& blockDim_z_init,
676
    const symbolic::Expression& blockIdx_x_init, const symbolic::Expression& blockIdx_y_init,
677
    const symbolic::Expression& blockIdx_z_init, const symbolic::Expression& threadIdx_x_init,
678
    const symbolic::Expression& threadIdx_y_init, const symbolic::Expression& threadIdx_z_init) {
679
    parent.children_.push_back(std::unique_ptr<Kernel>(new Kernel(
36✔
680
        this->element_counter_, debug_info, suffix, gridDim_x_init, gridDim_y_init, gridDim_z_init,
18✔
681
        blockDim_x_init, blockDim_y_init, blockDim_z_init, blockIdx_x_init, blockIdx_y_init,
18✔
682
        blockIdx_z_init, threadIdx_x_init, threadIdx_y_init, threadIdx_z_init)));
18✔
683
    this->element_counter_ = this->element_counter_ + 2;
18✔
684
    parent.transitions_.push_back(
18✔
685
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
18✔
686
    this->element_counter_++;
18✔
687
    return static_cast<Kernel&>(*parent.children_.back().get());
18✔
688
};
×
689

690
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent, const DebugInfo& debug_info) {
14✔
691
    return this->add_continue(parent, symbolic::Assignments{}, debug_info);
14✔
692
};
×
693

694
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent,
15✔
695
                                              const sdfg::symbolic::Assignments& assignments,
696
                                              const DebugInfo& debug_info) {
697
    parent.children_.push_back(
15✔
698
        std::unique_ptr<Continue>(new Continue(this->element_counter_, debug_info)));
15✔
699
    this->element_counter_++;
15✔
700
    parent.transitions_.push_back(std::unique_ptr<Transition>(
15✔
701
        new Transition(this->element_counter_, debug_info, assignments)));
15✔
702
    this->element_counter_++;
15✔
703
    return static_cast<Continue&>(*parent.children_.back().get());
15✔
704
};
×
705

706
Break& StructuredSDFGBuilder::add_break(Sequence& parent, const DebugInfo& debug_info) {
15✔
707
    return this->add_break(parent, symbolic::Assignments{}, debug_info);
15✔
708
};
×
709

710
Break& StructuredSDFGBuilder::add_break(Sequence& parent,
16✔
711
                                        const sdfg::symbolic::Assignments& assignments,
712
                                        const DebugInfo& debug_info) {
713
    parent.children_.push_back(
16✔
714
        std::unique_ptr<Break>(new Break(this->element_counter_, debug_info)));
16✔
715
    this->element_counter_++;
16✔
716
    parent.transitions_.push_back(std::unique_ptr<Transition>(
16✔
717
        new Transition(this->element_counter_, debug_info, assignments)));
16✔
718
    this->element_counter_++;
16✔
719
    return static_cast<Break&>(*parent.children_.back().get());
16✔
720
};
×
721

722
Return& StructuredSDFGBuilder::add_return(Sequence& parent,
14✔
723
                                          const sdfg::symbolic::Assignments& assignments,
724
                                          const DebugInfo& debug_info) {
725
    parent.children_.push_back(
14✔
726
        std::unique_ptr<Return>(new Return(this->element_counter_, debug_info)));
14✔
727
    this->element_counter_++;
14✔
728
    parent.transitions_.push_back(std::unique_ptr<Transition>(
14✔
729
        new Transition(this->element_counter_, debug_info, assignments)));
14✔
730
    this->element_counter_++;
14✔
731
    return static_cast<Return&>(*parent.children_.back().get());
14✔
732
};
×
733

734
Map& StructuredSDFGBuilder::add_map(Sequence& parent, const symbolic::Symbol& indvar,
9✔
735
                                    const symbolic::Expression& num_iterations,
736
                                    const sdfg::symbolic::Assignments& assignments,
737
                                    const DebugInfo& debug_info) {
738
    parent.children_.push_back(
18✔
739
        std::unique_ptr<Map>(new Map(this->element_counter_, debug_info, indvar, num_iterations)));
9✔
740
    this->element_counter_ = this->element_counter_ + 2;
9✔
741
    parent.transitions_.push_back(std::unique_ptr<Transition>(
9✔
742
        new Transition(this->element_counter_, debug_info, assignments)));
9✔
743
    this->element_counter_++;
9✔
744

745
    return static_cast<Map&>(*parent.children_.back().get());
9✔
NEW
746
};
×
747

UNCOV
748
For& StructuredSDFGBuilder::convert_while(Sequence& parent, While& loop,
×
749
                                          const symbolic::Symbol& indvar,
750
                                          const symbolic::Condition& condition,
751
                                          const symbolic::Expression& init,
752
                                          const symbolic::Expression& update) {
753
    // Insert for loop
754
    size_t index = 0;
×
755
    for (auto& entry : parent.children_) {
×
756
        if (entry.get() == &loop) {
×
757
            break;
×
758
        }
759
        index++;
×
760
    }
761
    auto iter = parent.children_.begin() + index;
×
762
    auto& new_iter = *parent.children_.insert(
×
763
        iter + 1, std::unique_ptr<For>(new For(this->element_counter_, loop.debug_info(), indvar,
×
764
                                               init, update, condition)));
×
765
    this->element_counter_ = this->element_counter_ + 2;
×
766
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
767
    this->insert_children(for_loop.root(), loop.root(), 0);
×
768

769
    // Remove while loop
770
    parent.children_.erase(parent.children_.begin() + index);
×
771

772
    return for_loop;
×
773
};
×
774

775
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop,
4✔
776
                                        const symbolic::Expression& num_iterations) {
777
    // Insert for loop
778
    size_t index = 0;
4✔
779
    for (auto& entry : parent.children_) {
4✔
780
        if (entry.get() == &loop) {
4✔
781
            break;
4✔
782
        }
NEW
783
        index++;
×
784
    }
785
    auto iter = parent.children_.begin() + index;
4✔
786
    auto& new_iter = *parent.children_.insert(
8✔
787
        iter + 1, std::unique_ptr<Map>(new Map(this->element_counter_, loop.debug_info(),
8✔
788
                                               loop.indvar(), num_iterations)));
4✔
789
    this->element_counter_ = this->element_counter_ + 2;
4✔
790
    auto& map = dynamic_cast<Map&>(*new_iter);
4✔
791
    this->insert_children(map.root(), loop.root(), 0);
4✔
792

793
    // Remove for loop
794
    parent.children_.erase(parent.children_.begin() + index);
4✔
795

796
    return map;
4✔
NEW
797
};
×
798

799
void StructuredSDFGBuilder::clear_sequence(Sequence& parent) {
2✔
800
    parent.children_.clear();
2✔
801
    parent.transitions_.clear();
2✔
802
};
2✔
803

804
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
7✔
805
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
7✔
806
    while (!queue.empty()) {
7✔
807
        auto current = queue.front();
7✔
808
        queue.pop_front();
7✔
809

810
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
7✔
811
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
7✔
812
                if (&sequence_stmt->at(i).first == &node) {
7✔
813
                    return *sequence_stmt;
7✔
814
                }
815
                queue.push_back(&sequence_stmt->at(i).first);
×
816
            }
×
817
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
818
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
819
                queue.push_back(&if_else_stmt->at(i).first);
×
820
            }
×
821
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
822
            queue.push_back(&while_stmt->root());
×
823
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
×
824
            queue.push_back(&for_stmt->root());
×
825
        } else if (auto kern_stmt = dynamic_cast<const structured_control_flow::Kernel*>(current)) {
×
826
            queue.push_back(&kern_stmt->root());
×
827
        }
×
828
    }
829

830
    return this->structured_sdfg_->root();
×
831
};
7✔
832

833
Kernel& StructuredSDFGBuilder::convert_into_kernel() {
6✔
834
    auto old_root = std::move(this->structured_sdfg_->root_);
6✔
835
    this->structured_sdfg_->root_ =
6✔
836
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, old_root->debug_info()));
6✔
837
    this->element_counter_++;
6✔
838
    auto& new_root = this->structured_sdfg_->root();
6✔
839
    auto& kernel = this->add_kernel(new_root, this->function().name());
6✔
840

841
    this->insert_children(kernel.root(), *old_root, 0);
6✔
842

843
    types::Scalar gridDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
844
    add_container(kernel.gridDim_x()->get_name(), gridDim_x);
6✔
845
    types::Scalar gridDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
846
    add_container(kernel.gridDim_y()->get_name(), gridDim_y);
6✔
847
    types::Scalar gridDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
848
    add_container(kernel.gridDim_z()->get_name(), gridDim_z);
6✔
849
    types::Scalar blockDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
850
    add_container(kernel.blockDim_x()->get_name(), blockDim_x);
6✔
851
    types::Scalar blockDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
852
    add_container(kernel.blockDim_y()->get_name(), blockDim_y);
6✔
853
    types::Scalar blockDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
854
    add_container(kernel.blockDim_z()->get_name(), blockDim_z);
6✔
855
    types::Scalar blockIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
856
    add_container(kernel.blockIdx_x()->get_name(), blockIdx_x);
6✔
857
    types::Scalar blockIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
858
    add_container(kernel.blockIdx_y()->get_name(), blockIdx_y);
6✔
859
    types::Scalar blockIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
860
    add_container(kernel.blockIdx_z()->get_name(), blockIdx_z);
6✔
861
    types::Scalar threadIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
862
    add_container(kernel.threadIdx_x()->get_name(), threadIdx_x);
6✔
863
    types::Scalar threadIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
864
    add_container(kernel.threadIdx_y()->get_name(), threadIdx_y);
6✔
865
    types::Scalar threadIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
866
    add_container(kernel.threadIdx_z()->get_name(), threadIdx_z);
6✔
867

868
    kernel.root().replace(symbolic::symbol("gridDim.x"), kernel.gridDim_x());
6✔
869
    kernel.root().replace(symbolic::symbol("gridDim.y"), kernel.gridDim_y());
6✔
870
    kernel.root().replace(symbolic::symbol("gridDim.z"), kernel.gridDim_z());
6✔
871

872
    kernel.root().replace(symbolic::symbol("blockDim.x"), kernel.blockDim_x());
6✔
873
    kernel.root().replace(symbolic::symbol("blockDim.y"), kernel.blockDim_y());
6✔
874
    kernel.root().replace(symbolic::symbol("blockDim.z"), kernel.blockDim_z());
6✔
875

876
    kernel.root().replace(symbolic::symbol("blockIdx.x"), kernel.blockIdx_x());
6✔
877
    kernel.root().replace(symbolic::symbol("blockIdx.y"), kernel.blockIdx_y());
6✔
878
    kernel.root().replace(symbolic::symbol("blockIdx.z"), kernel.blockIdx_z());
6✔
879

880
    kernel.root().replace(symbolic::symbol("threadIdx.x"), kernel.threadIdx_x());
6✔
881
    kernel.root().replace(symbolic::symbol("threadIdx.y"), kernel.threadIdx_y());
6✔
882
    kernel.root().replace(symbolic::symbol("threadIdx.z"), kernel.threadIdx_z());
6✔
883

884
    return kernel;
6✔
885
};
6✔
886

887
/***** Section: Dataflow Graph *****/
888

889
data_flow::AccessNode& StructuredSDFGBuilder::add_access(structured_control_flow::Block& block,
585✔
890
                                                         const std::string& data,
891
                                                         const DebugInfo& debug_info) {
892
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
585✔
893
    auto res = block.dataflow_->nodes_.insert(
1,170✔
894
        {vertex, std::unique_ptr<data_flow::AccessNode>(new data_flow::AccessNode(
585✔
895
                     this->element_counter_, debug_info, vertex, block.dataflow(), data))});
585✔
896
    this->element_counter_++;
585✔
897
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
585✔
898
};
×
899

900
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
368✔
901
    structured_control_flow::Block& block, const data_flow::TaskletCode code,
902
    const std::pair<std::string, sdfg::types::Scalar>& output,
903
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
904
    const DebugInfo& debug_info) {
905
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
368✔
906
    auto res = block.dataflow_->nodes_.insert(
736✔
907
        {vertex, std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
736✔
908
                     this->element_counter_, debug_info, vertex, block.dataflow(), code, output,
368✔
909
                     inputs, symbolic::__true__()))});
368✔
910
    this->element_counter_++;
368✔
911
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
368✔
912
};
×
913

914
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
595✔
915
    structured_control_flow::Block& block, data_flow::DataFlowNode& src,
916
    const std::string& src_conn, data_flow::DataFlowNode& dst, const std::string& dst_conn,
917
    const data_flow::Subset& subset, const DebugInfo& debug_info) {
918
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
595✔
919
    auto res = block.dataflow_->edges_.insert(
1,190✔
920
        {edge.first, std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
595✔
921
                         this->element_counter_, debug_info, edge.first, block.dataflow(), src,
595✔
922
                         src_conn, dst, dst_conn, subset))});
595✔
923
    this->element_counter_++;
595✔
924
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
595✔
925
};
×
926

927
data_flow::LibraryNode& StructuredSDFGBuilder::add_library_node(
10✔
928
    structured_control_flow::Block& block, const data_flow::LibraryNodeType& call,
929
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& outputs,
930
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
931
    const bool has_side_effect, const DebugInfo& debug_info) {
932
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
10✔
933
    auto res = block.dataflow_->nodes_.insert(
20✔
934
        {vertex, std::unique_ptr<data_flow::LibraryNode>(new data_flow::LibraryNode(
10✔
935
                     this->element_counter_, debug_info, vertex, block.dataflow(), outputs, inputs,
10✔
936
                     call, has_side_effect))});
10✔
937
    this->element_counter_++;
10✔
938
    return dynamic_cast<data_flow::LibraryNode&>(*(res.first->second));
10✔
939
}
×
940

941
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block,
×
942
                                          const data_flow::Memlet& edge) {
943
    auto& graph = block.dataflow();
×
944
    auto e = edge.edge();
×
945
    boost::remove_edge(e, graph.graph_);
×
946
    graph.edges_.erase(e);
×
947
};
×
948

949
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block,
×
950
                                        const data_flow::DataFlowNode& node) {
951
    auto& graph = block.dataflow();
×
952
    auto v = node.vertex();
×
953
    boost::remove_vertex(v, graph.graph_);
×
954
    graph.nodes_.erase(v);
×
955
};
×
956

957
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
8✔
958
                                       const data_flow::Tasklet& node) {
959
    auto& graph = block.dataflow();
8✔
960

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

963
    // Delete incoming
964
    std::list<const data_flow::Memlet*> iedges;
8✔
965
    for (auto& iedge : graph.in_edges(node)) {
15✔
966
        iedges.push_back(&iedge);
7✔
967
    }
968
    for (auto iedge : iedges) {
15✔
969
        auto& src = iedge->src();
7✔
970
        to_delete.insert(&src);
7✔
971

972
        auto edge = iedge->edge();
7✔
973
        graph.edges_.erase(edge);
7✔
974
        boost::remove_edge(edge, graph.graph_);
7✔
975
    }
976

977
    // Delete outgoing
978
    std::list<const data_flow::Memlet*> oedges;
8✔
979
    for (auto& oedge : graph.out_edges(node)) {
16✔
980
        oedges.push_back(&oedge);
8✔
981
    }
982
    for (auto oedge : oedges) {
16✔
983
        auto& dst = oedge->dst();
8✔
984
        to_delete.insert(&dst);
8✔
985

986
        auto edge = oedge->edge();
8✔
987
        graph.edges_.erase(edge);
8✔
988
        boost::remove_edge(edge, graph.graph_);
8✔
989
    }
990

991
    // Delete nodes
992
    for (auto obsolete_node : to_delete) {
31✔
993
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
994
            auto vertex = obsolete_node->vertex();
23✔
995
            graph.nodes_.erase(vertex);
23✔
996
            boost::remove_vertex(vertex, graph.graph_);
23✔
997
        }
23✔
998
    }
999
};
8✔
1000

1001
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
1✔
1002
                                       const data_flow::AccessNode& node) {
1003
    auto& graph = block.dataflow();
1✔
1004
    assert(graph.out_degree(node) == 0);
1✔
1005

1006
    std::list<const data_flow::Memlet*> tmp;
1✔
1007
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
1008
    while (!queue.empty()) {
3✔
1009
        auto current = queue.front();
2✔
1010
        queue.pop_front();
2✔
1011
        if (current != &node) {
2✔
1012
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
1013
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1014
                    continue;
×
1015
                }
1016
            }
×
1017
        }
1✔
1018

1019
        tmp.clear();
2✔
1020
        for (auto& iedge : graph.in_edges(*current)) {
3✔
1021
            tmp.push_back(&iedge);
1✔
1022
        }
1023
        for (auto iedge : tmp) {
3✔
1024
            auto& src = iedge->src();
1✔
1025
            queue.push_back(&src);
1✔
1026

1027
            auto edge = iedge->edge();
1✔
1028
            graph.edges_.erase(edge);
1✔
1029
            boost::remove_edge(edge, graph.graph_);
1✔
1030
        }
1031

1032
        auto vertex = current->vertex();
2✔
1033
        graph.nodes_.erase(vertex);
2✔
1034
        boost::remove_vertex(vertex, graph.graph_);
2✔
1035
    }
1036
};
1✔
1037

1038
data_flow::AccessNode& StructuredSDFGBuilder::symbolic_expression_to_dataflow(
×
1039
    structured_control_flow::Block& parent, const symbolic::Expression& expr) {
1040
    auto& sdfg = this->subject();
×
1041

1042
    codegen::CPPLanguageExtension language_extension;
×
1043

1044
    // Base cases
1045
    if (SymEngine::is_a<SymEngine::Symbol>(*expr)) {
×
1046
        auto sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(expr);
×
1047

1048
        // Determine type
1049
        types::Scalar sym_type = types::Scalar(types::PrimitiveType::Void);
×
1050
        if (symbolic::is_nvptx(sym)) {
×
1051
            sym_type = types::Scalar(types::PrimitiveType::Int32);
×
1052
        } else {
×
1053
            sym_type = static_cast<const types::Scalar&>(sdfg.type(sym->get_name()));
×
1054
        }
1055

1056
        // Add new container for intermediate result
1057
        auto tmp = this->find_new_name();
×
1058
        this->add_container(tmp, sym_type);
×
1059

1060
        // Create dataflow graph
1061
        auto& input_node = this->add_access(parent, sym->get_name());
×
1062
        auto& output_node = this->add_access(parent, tmp);
×
1063
        auto& tasklet = this->add_tasklet(parent, data_flow::TaskletCode::assign,
×
1064
                                          {"_out", sym_type}, {{"_in", sym_type}});
×
1065
        this->add_memlet(parent, input_node, "void", tasklet, "_in", {symbolic::integer(0)});
×
1066
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1067

1068
        return output_node;
×
1069
    } else if (SymEngine::is_a<SymEngine::Integer>(*expr)) {
×
1070
        auto tmp = this->find_new_name();
×
1071
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Int64));
×
1072

1073
        auto& output_node = this->add_access(parent, tmp);
×
1074
        auto& tasklet = this->add_tasklet(
×
1075
            parent, data_flow::TaskletCode::assign,
×
1076
            {"_out", types::Scalar(types::PrimitiveType::Int64)},
×
1077
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Int64)}});
×
1078
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1079
        return output_node;
×
1080
    } else if (SymEngine::is_a<SymEngine::BooleanAtom>(*expr)) {
×
1081
        auto tmp = this->find_new_name();
×
1082
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1083

1084
        auto& output_node = this->add_access(parent, tmp);
×
1085
        auto& tasklet = this->add_tasklet(
×
1086
            parent, data_flow::TaskletCode::assign,
×
1087
            {"_out", types::Scalar(types::PrimitiveType::Bool)},
×
1088
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Bool)}});
×
1089
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1090
        return output_node;
×
1091
    } else if (SymEngine::is_a<SymEngine::Or>(*expr)) {
×
1092
        auto or_expr = SymEngine::rcp_static_cast<const SymEngine::Or>(expr);
×
1093
        assert(or_expr->get_container().size() == 2);
×
1094

1095
        std::vector<data_flow::AccessNode*> input_nodes;
×
1096
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1097
        for (auto& arg : or_expr->get_container()) {
×
1098
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1099
            input_nodes.push_back(&input_node);
×
1100
            input_types.push_back(
×
1101
                {"_in" + std::to_string(input_types.size() + 1),
×
1102
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1103
        }
1104

1105
        // Add new container for intermediate result
1106
        auto tmp = this->find_new_name();
×
1107
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1108

1109
        auto& output_node = this->add_access(parent, tmp);
×
1110
        auto& tasklet =
×
1111
            this->add_tasklet(parent, data_flow::TaskletCode::logical_or,
×
1112
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1113
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1114
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1115
                             {symbolic::integer(0)});
×
1116
        }
×
1117
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1118
        return output_node;
×
1119
    } else if (SymEngine::is_a<SymEngine::And>(*expr)) {
×
1120
        auto and_expr = SymEngine::rcp_static_cast<const SymEngine::And>(expr);
×
1121
        assert(and_expr->get_container().size() == 2);
×
1122

1123
        std::vector<data_flow::AccessNode*> input_nodes;
×
1124
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1125
        for (auto& arg : and_expr->get_container()) {
×
1126
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1127
            input_nodes.push_back(&input_node);
×
1128
            input_types.push_back(
×
1129
                {"_in" + std::to_string(input_types.size() + 1),
×
1130
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1131
        }
1132

1133
        // Add new container for intermediate result
1134
        auto tmp = this->find_new_name();
×
1135
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1136

1137
        auto& output_node = this->add_access(parent, tmp);
×
1138
        auto& tasklet =
×
1139
            this->add_tasklet(parent, data_flow::TaskletCode::logical_and,
×
1140
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1141
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1142
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1143
                             {symbolic::integer(0)});
×
1144
        }
×
1145
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1146
        return output_node;
×
1147
    } else {
×
1148
        throw std::runtime_error("Unsupported expression type");
×
1149
    }
1150
};
×
1151

1152
}  // namespace builder
1153
}  // 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