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

daisytuner / sdfglib / 15099123388

18 May 2025 07:05PM UTC coverage: 63.603% (-0.005%) from 63.608%
15099123388

push

github

web-flow
Merge pull request #18 from daisytuner/structured-control-flow

reduce recursion depth for structured control flow conversion

68 of 83 new or added lines in 2 files covered. (81.93%)

2 existing lines in 2 files now uncovered.

8643 of 13589 relevant lines covered (63.6%)

480.94 hits per line

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

74.77
/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;
×
22
        }
23
        visited.insert(curr);
3✔
24

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

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

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

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

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

53
    return false;
×
54
}
6✔
55

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

67
    return pdom;
3✔
68
}
3✔
69

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

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

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

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

87
void StructuredSDFGBuilder::traverse_with_loop_detection(
9✔
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) {
9✔
93
        return;
1✔
94
    }
95

96
    auto in_edges = sdfg.in_edges(*current);
8✔
97

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

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

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

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

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

149
        this->traverse_with_loop_detection(sdfg, scope, exit_state, end, continues, breaks,
2✔
150
                                           pdom_tree);
1✔
151
    } else {
1✔
152
        this->traverse_without_loop_detection(sdfg, scope, current, end, continues, breaks,
14✔
153
                                              pdom_tree);
7✔
154
    }
155
};
9✔
156

157
void StructuredSDFGBuilder::traverse_without_loop_detection(
8✔
158
    const SDFG& sdfg, Sequence& scope, const State* current, const State* end,
159
    const std::unordered_set<const InterstateEdge*>& continues,
160
    const std::unordered_set<const InterstateEdge*>& breaks,
161
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree) {
162
    std::list<const State*> queue = {current};
8✔
163
    while (!queue.empty()) {
26✔
164
        auto curr = queue.front();
18✔
165
        queue.pop_front();
18✔
166
        if (curr == end) {
18✔
167
            continue;
3✔
168
        }
169

170
        auto out_edges = sdfg.out_edges(*curr);
15✔
171
        auto out_degree = sdfg.out_degree(*curr);
15✔
172

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

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

187
            if (continues.find(&oedge) != continues.end()) {
8✔
NEW
188
                this->add_continue(scope, oedge.debug_info());
×
189
            } else if (breaks.find(&oedge) != breaks.end()) {
8✔
NEW
190
                this->add_break(scope, oedge.debug_info());
×
NEW
191
            } else {
×
192
                bool starts_loop = false;
8✔
193
                for (auto& iedge : sdfg.in_edges(oedge.dst())) {
19✔
194
                    if (continues.find(&iedge) != continues.end()) {
11✔
NEW
195
                        starts_loop = true;
×
NEW
196
                        break;
×
197
                    }
198
                }
199
                if (!starts_loop) {
8✔
200
                    queue.push_back(&oedge.dst());
8✔
201
                } else {
8✔
NEW
202
                    this->traverse_with_loop_detection(sdfg, scope, &oedge.dst(), end, continues,
×
NEW
203
                                                       breaks, pdom_tree);
×
204
                }
205
            }
206
            continue;
8✔
207
        }
208

209
        // Case 3: Branches
210
        if (out_degree > 1) {
3✔
211
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
3✔
212

213
            std::vector<const InterstateEdge*> out_edges_vec;
3✔
214
            for (auto& edge : out_edges) {
9✔
215
                out_edges_vec.push_back(&edge);
6✔
216
            }
217

218
            // Best-effort approach: Find end of if-else
219
            // If not found, the branches may repeat paths yielding a large SDFG
220
            const control_flow::State* local_end =
3✔
221
                this->find_end_of_if_else(sdfg, curr, out_edges_vec, pdom_tree);
3✔
222
            if (local_end == nullptr) {
3✔
NEW
223
                local_end = end;
×
UNCOV
224
            }
×
225

226
            auto& if_else = this->add_if_else(scope, curr->debug_info());
3✔
227
            for (size_t i = 0; i < out_degree; i++) {
9✔
228
                auto& out_edge = out_edges_vec[i];
6✔
229

230
                auto& branch =
6✔
231
                    this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
232
                if (!out_edge->assignments().empty()) {
6✔
233
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
234
                }
2✔
235
                if (continues.find(out_edge) != continues.end()) {
6✔
236
                    this->add_continue(branch, out_edge->debug_info());
1✔
237
                } else if (breaks.find(out_edge) != breaks.end()) {
6✔
238
                    this->add_break(branch, out_edge->debug_info());
1✔
239
                } else {
1✔
240
                    this->traverse_with_loop_detection(sdfg, branch, &out_edge->dst(), local_end,
4✔
241
                                                       continues, breaks, pdom_tree);
4✔
242
                }
243
            }
6✔
244

245
            if (local_end != end) {
3✔
246
                bool starts_loop = false;
2✔
247
                for (auto& iedge : sdfg.in_edges(*local_end)) {
6✔
248
                    if (continues.find(&iedge) != continues.end()) {
4✔
NEW
249
                        starts_loop = true;
×
NEW
250
                        break;
×
251
                    }
252
                }
253
                if (!starts_loop) {
2✔
254
                    queue.push_back(local_end);
2✔
255
                } else {
2✔
NEW
256
                    this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues,
×
NEW
257
                                                       breaks, pdom_tree);
×
258
                }
259
            }
2✔
260
            continue;
261
        }
3✔
262
    }
263
}
8✔
264

265
Function& StructuredSDFGBuilder::function() const {
2,688✔
266
    return static_cast<Function&>(*this->structured_sdfg_);
2,688✔
267
};
268

269
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
352✔
270
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
352✔
271

272
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name)
499✔
273
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name)) {};
499✔
274

275
StructuredSDFGBuilder::StructuredSDFGBuilder(const SDFG& sdfg)
4✔
276
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(sdfg.name())) {
4✔
277
    for (auto& entry : sdfg.structures_) {
4✔
278
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
279
    }
280

281
    for (auto& entry : sdfg.containers_) {
11✔
282
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
283
    }
284

285
    for (auto& arg : sdfg.arguments_) {
6✔
286
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
287
    }
288

289
    for (auto& ext : sdfg.externals_) {
5✔
290
        this->structured_sdfg_->externals_.push_back(ext);
1✔
291
    }
292

293
    for (auto& entry : sdfg.assumptions_) {
9✔
294
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
295
    }
296

297
    this->traverse(sdfg);
4✔
298
};
4✔
299

300
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
2,888✔
301

302
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
469✔
303
    return std::move(this->structured_sdfg_);
469✔
304
};
305

306
Sequence& StructuredSDFGBuilder::add_sequence(Sequence& parent,
39✔
307
                                              const sdfg::symbolic::Assignments& assignments,
308
                                              const DebugInfo& debug_info) {
309
    parent.children_.push_back(
39✔
310
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
39✔
311
    this->element_counter_++;
39✔
312
    parent.transitions_.push_back(std::unique_ptr<Transition>(
39✔
313
        new Transition(this->element_counter_, debug_info, assignments)));
39✔
314
    this->element_counter_++;
39✔
315

316
    return static_cast<Sequence&>(*parent.children_.back().get());
39✔
317
};
×
318

319
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::add_sequence_before(
7✔
320
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
321
    // Insert block before current block
322
    int index = -1;
7✔
323
    for (size_t i = 0; i < parent.children_.size(); i++) {
7✔
324
        if (parent.children_.at(i).get() == &block) {
7✔
325
            index = i;
7✔
326
            break;
7✔
327
        }
328
    }
×
329
    assert(index > -1);
7✔
330

331
    parent.children_.insert(
7✔
332
        parent.children_.begin() + index,
7✔
333
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
7✔
334
    this->element_counter_++;
7✔
335
    parent.transitions_.insert(
7✔
336
        parent.transitions_.begin() + index,
7✔
337
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
7✔
338
    this->element_counter_++;
7✔
339
    auto new_entry = parent.at(index);
7✔
340
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
7✔
341

342
    return {new_block, new_entry.second};
7✔
343
};
×
344

345
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t i) {
9✔
346
    parent.children_.erase(parent.children_.begin() + i);
9✔
347
    parent.transitions_.erase(parent.transitions_.begin() + i);
9✔
348
};
9✔
349

350
void StructuredSDFGBuilder::remove_child(Sequence& parent, ControlFlowNode& child) {
50✔
351
    int index = -1;
50✔
352
    for (size_t i = 0; i < parent.children_.size(); i++) {
51✔
353
        if (parent.children_.at(i).get() == &child) {
51✔
354
            index = i;
50✔
355
            break;
50✔
356
        }
357
    }
1✔
358

359
    parent.children_.erase(parent.children_.begin() + index);
50✔
360
    parent.transitions_.erase(parent.transitions_.begin() + index);
50✔
361
};
50✔
362

363
void StructuredSDFGBuilder::insert_children(Sequence& parent, Sequence& other, size_t i) {
10✔
364
    parent.children_.insert(parent.children_.begin() + i,
20✔
365
                            std::make_move_iterator(other.children_.begin()),
10✔
366
                            std::make_move_iterator(other.children_.end()));
10✔
367
    parent.transitions_.insert(parent.transitions_.begin() + i,
20✔
368
                               std::make_move_iterator(other.transitions_.begin()),
10✔
369
                               std::make_move_iterator(other.transitions_.end()));
10✔
370
    other.children_.clear();
10✔
371
    other.transitions_.clear();
10✔
372
};
10✔
373

374
Block& StructuredSDFGBuilder::add_block(Sequence& parent,
648✔
375
                                        const sdfg::symbolic::Assignments& assignments,
376
                                        const DebugInfo& debug_info) {
377
    parent.children_.push_back(
648✔
378
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
648✔
379
    this->element_counter_++;
648✔
380
    parent.transitions_.push_back(std::unique_ptr<Transition>(
648✔
381
        new Transition(this->element_counter_, debug_info, assignments)));
648✔
382
    this->element_counter_++;
648✔
383
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(*parent.children_.back().get());
648✔
384
    (*new_block.dataflow_).parent_ = &new_block;
648✔
385

386
    return new_block;
648✔
387
};
×
388

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

402
    return new_block;
82✔
403
};
×
404

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

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

428
    return {new_block, new_entry.second};
12✔
429
};
×
430

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

444
    parent.children_.insert(
×
445
        parent.children_.begin() + index,
×
446
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
447
    this->element_counter_++;
×
448
    parent.transitions_.insert(
×
449
        parent.transitions_.begin() + index,
×
450
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
451
    this->element_counter_++;
×
452
    auto new_entry = parent.at(index);
×
453
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
454
    (*new_block.dataflow_).parent_ = &new_block;
×
455

456
    return {new_block, new_entry.second};
×
457
};
×
458

459
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(Sequence& parent,
2✔
460
                                                                      ControlFlowNode& block,
461
                                                                      const DebugInfo& debug_info) {
462
    // Insert block before current block
463
    int index = -1;
2✔
464
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
465
        if (parent.children_.at(i).get() == &block) {
3✔
466
            index = i;
2✔
467
            break;
2✔
468
        }
469
    }
1✔
470
    assert(index > -1);
2✔
471

472
    parent.children_.insert(parent.children_.begin() + index + 1,
2✔
473
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
2✔
474
    this->element_counter_++;
2✔
475
    parent.transitions_.insert(
2✔
476
        parent.transitions_.begin() + index + 1,
2✔
477
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
478
    this->element_counter_++;
2✔
479
    auto new_entry = parent.at(index + 1);
2✔
480
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
2✔
481
    (*new_block.dataflow_).parent_ = &new_block;
2✔
482

483
    return {new_block, new_entry.second};
2✔
484
};
×
485

486
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
487
    Sequence& parent, ControlFlowNode& block, data_flow::DataFlowGraph& data_flow_graph,
488
    const DebugInfo& debug_info) {
489
    int index = -1;
×
490
    for (size_t i = 0; i < parent.children_.size(); i++) {
×
491
        if (parent.children_.at(i).get() == &block) {
×
492
            index = i;
×
493
            break;
×
494
        }
495
    }
×
496
    assert(index > -1);
×
497

498
    parent.children_.insert(
×
499
        parent.children_.begin() + index + 1,
×
500
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
501
    this->element_counter_++;
×
502
    parent.transitions_.insert(
×
503
        parent.transitions_.begin() + index + 1,
×
504
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
505
    this->element_counter_++;
×
506
    auto new_entry = parent.at(index + 1);
×
507
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
508
    (*new_block.dataflow_).parent_ = &new_block;
×
509

510
    return {new_block, new_entry.second};
×
511
};
×
512

513
For& StructuredSDFGBuilder::add_for(Sequence& parent, const symbolic::Symbol& indvar,
278✔
514
                                    const symbolic::Condition& condition,
515
                                    const symbolic::Expression& init,
516
                                    const symbolic::Expression& update,
517
                                    const sdfg::symbolic::Assignments& assignments,
518
                                    const DebugInfo& debug_info) {
519
    parent.children_.push_back(std::unique_ptr<For>(
556✔
520
        new For(this->element_counter_, debug_info, indvar, init, update, condition)));
278✔
521
    this->element_counter_ = this->element_counter_ + 2;
278✔
522
    parent.transitions_.push_back(std::unique_ptr<Transition>(
278✔
523
        new Transition(this->element_counter_, debug_info, assignments)));
278✔
524
    this->element_counter_++;
278✔
525

526
    return static_cast<For&>(*parent.children_.back().get());
278✔
527
};
×
528

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

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

554
    return {new_block, new_entry.second};
51✔
555
};
×
556

557
std::pair<For&, Transition&> StructuredSDFGBuilder::add_for_after(
2✔
558
    Sequence& parent, ControlFlowNode& block, const symbolic::Symbol& indvar,
559
    const symbolic::Condition& condition, const symbolic::Expression& init,
560
    const symbolic::Expression& update, const DebugInfo& debug_info) {
561
    // Insert block before current block
562
    int index = -1;
2✔
563
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
564
        if (parent.children_.at(i).get() == &block) {
3✔
565
            index = i;
2✔
566
            break;
2✔
567
        }
568
    }
1✔
569
    assert(index > -1);
2✔
570

571
    parent.children_.insert(parent.children_.begin() + index + 1,
4✔
572
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
4✔
573
                                                         init, update, condition)));
2✔
574
    this->element_counter_ = this->element_counter_ + 2;
2✔
575
    parent.transitions_.insert(
2✔
576
        parent.transitions_.begin() + index + 1,
2✔
577
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
578
    this->element_counter_++;
2✔
579
    auto new_entry = parent.at(index + 1);
2✔
580
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
2✔
581

582
    return {new_block, new_entry.second};
2✔
583
};
×
584

585
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent, const DebugInfo& debug_info) {
41✔
586
    return this->add_if_else(parent, symbolic::Assignments{}, debug_info);
41✔
587
};
×
588

589
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent,
43✔
590
                                           const sdfg::symbolic::Assignments& assignments,
591
                                           const DebugInfo& debug_info) {
592
    parent.children_.push_back(
43✔
593
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
43✔
594
    this->element_counter_++;
43✔
595
    parent.transitions_.push_back(std::unique_ptr<Transition>(
43✔
596
        new Transition(this->element_counter_, debug_info, assignments)));
43✔
597
    this->element_counter_++;
43✔
598
    return static_cast<IfElse&>(*parent.children_.back().get());
43✔
599
};
×
600

601
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::add_if_else_before(
2✔
602
    Sequence& parent, ControlFlowNode& block, const DebugInfo& debug_info) {
603
    // Insert block before current block
604
    int index = -1;
2✔
605
    for (size_t i = 0; i < parent.children_.size(); i++) {
2✔
606
        if (parent.children_.at(i).get() == &block) {
2✔
607
            index = i;
2✔
608
            break;
2✔
609
        }
610
    }
×
611
    assert(index > -1);
2✔
612

613
    parent.children_.insert(
2✔
614
        parent.children_.begin() + index,
2✔
615
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
2✔
616
    this->element_counter_++;
2✔
617
    parent.transitions_.insert(
2✔
618
        parent.transitions_.begin() + index,
2✔
619
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
620
    this->element_counter_++;
2✔
621
    auto new_entry = parent.at(index);
2✔
622
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
2✔
623

624
    return {new_block, new_entry.second};
2✔
625
};
×
626

627
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond,
73✔
628
                                          const DebugInfo& debug_info) {
629
    scope.cases_.push_back(
73✔
630
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
73✔
631
    this->element_counter_++;
73✔
632
    scope.conditions_.push_back(cond);
73✔
633
    return *scope.cases_.back();
73✔
634
};
×
635

636
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t i, const DebugInfo& debug_info) {
3✔
637
    scope.cases_.erase(scope.cases_.begin() + i);
3✔
638
    scope.conditions_.erase(scope.conditions_.begin() + i);
3✔
639
};
3✔
640

641
While& StructuredSDFGBuilder::add_while(Sequence& parent,
38✔
642
                                        const sdfg::symbolic::Assignments& assignments,
643
                                        const DebugInfo& debug_info) {
644
    parent.children_.push_back(
38✔
645
        std::unique_ptr<While>(new While(this->element_counter_, debug_info)));
38✔
646
    this->element_counter_ = this->element_counter_ + 2;
38✔
647
    parent.transitions_.push_back(std::unique_ptr<Transition>(
38✔
648
        new Transition(this->element_counter_, debug_info, assignments)));
38✔
649
    this->element_counter_++;
38✔
650
    return static_cast<While&>(*parent.children_.back().get());
38✔
651
};
×
652

653
Kernel& StructuredSDFGBuilder::add_kernel(
18✔
654
    Sequence& parent, const std::string& suffix, const DebugInfo& debug_info,
655
    const symbolic::Expression& gridDim_x_init, const symbolic::Expression& gridDim_y_init,
656
    const symbolic::Expression& gridDim_z_init, const symbolic::Expression& blockDim_x_init,
657
    const symbolic::Expression& blockDim_y_init, const symbolic::Expression& blockDim_z_init,
658
    const symbolic::Expression& blockIdx_x_init, const symbolic::Expression& blockIdx_y_init,
659
    const symbolic::Expression& blockIdx_z_init, const symbolic::Expression& threadIdx_x_init,
660
    const symbolic::Expression& threadIdx_y_init, const symbolic::Expression& threadIdx_z_init) {
661
    parent.children_.push_back(std::unique_ptr<Kernel>(new Kernel(
36✔
662
        this->element_counter_, debug_info, suffix, gridDim_x_init, gridDim_y_init, gridDim_z_init,
18✔
663
        blockDim_x_init, blockDim_y_init, blockDim_z_init, blockIdx_x_init, blockIdx_y_init,
18✔
664
        blockIdx_z_init, threadIdx_x_init, threadIdx_y_init, threadIdx_z_init)));
18✔
665
    this->element_counter_ = this->element_counter_ + 2;
18✔
666
    parent.transitions_.push_back(
18✔
667
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
18✔
668
    this->element_counter_++;
18✔
669
    return static_cast<Kernel&>(*parent.children_.back().get());
18✔
670
};
×
671

672
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent, const DebugInfo& debug_info) {
14✔
673
    return this->add_continue(parent, symbolic::Assignments{}, debug_info);
14✔
674
};
×
675

676
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent,
15✔
677
                                              const sdfg::symbolic::Assignments& assignments,
678
                                              const DebugInfo& debug_info) {
679
    parent.children_.push_back(
15✔
680
        std::unique_ptr<Continue>(new Continue(this->element_counter_, debug_info)));
15✔
681
    this->element_counter_++;
15✔
682
    parent.transitions_.push_back(std::unique_ptr<Transition>(
15✔
683
        new Transition(this->element_counter_, debug_info, assignments)));
15✔
684
    this->element_counter_++;
15✔
685
    return static_cast<Continue&>(*parent.children_.back().get());
15✔
686
};
×
687

688
Break& StructuredSDFGBuilder::add_break(Sequence& parent, const DebugInfo& debug_info) {
15✔
689
    return this->add_break(parent, symbolic::Assignments{}, debug_info);
15✔
690
};
×
691

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

704
Return& StructuredSDFGBuilder::add_return(Sequence& parent,
14✔
705
                                          const sdfg::symbolic::Assignments& assignments,
706
                                          const DebugInfo& debug_info) {
707
    parent.children_.push_back(
14✔
708
        std::unique_ptr<Return>(new Return(this->element_counter_, debug_info)));
14✔
709
    this->element_counter_++;
14✔
710
    parent.transitions_.push_back(std::unique_ptr<Transition>(
14✔
711
        new Transition(this->element_counter_, debug_info, assignments)));
14✔
712
    this->element_counter_++;
14✔
713
    return static_cast<Return&>(*parent.children_.back().get());
14✔
714
};
×
715

716
For& StructuredSDFGBuilder::convert_while(Sequence& parent, While& loop,
×
717
                                          const symbolic::Symbol& indvar,
718
                                          const symbolic::Condition& condition,
719
                                          const symbolic::Expression& init,
720
                                          const symbolic::Expression& update) {
721
    // Insert for loop
722
    size_t index = 0;
×
723
    for (auto& entry : parent.children_) {
×
724
        if (entry.get() == &loop) {
×
725
            break;
×
726
        }
727
        index++;
×
728
    }
729
    auto iter = parent.children_.begin() + index;
×
730
    auto& new_iter = *parent.children_.insert(
×
731
        iter + 1, std::unique_ptr<For>(new For(this->element_counter_, loop.debug_info(), indvar,
×
732
                                               init, update, condition)));
×
733
    this->element_counter_ = this->element_counter_ + 2;
×
734
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
735
    this->insert_children(for_loop.root(), loop.root(), 0);
×
736

737
    // Remove while loop
738
    parent.children_.erase(parent.children_.begin() + index);
×
739

740
    return for_loop;
×
741
};
×
742

743
void StructuredSDFGBuilder::clear_sequence(Sequence& parent) {
2✔
744
    parent.children_.clear();
2✔
745
    parent.transitions_.clear();
2✔
746
};
2✔
747

748
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
98✔
749
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
98✔
750
    while (!queue.empty()) {
210✔
751
        auto current = queue.front();
210✔
752
        queue.pop_front();
210✔
753

754
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
210✔
755
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
286✔
756
                if (&sequence_stmt->at(i).first == &node) {
233✔
757
                    return *sequence_stmt;
98✔
758
                }
759
                queue.push_back(&sequence_stmt->at(i).first);
135✔
760
            }
135✔
761
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
112✔
762
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
763
                queue.push_back(&if_else_stmt->at(i).first);
×
764
            }
×
765
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
59✔
766
            queue.push_back(&while_stmt->root());
×
767
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
59✔
768
            queue.push_back(&for_stmt->root());
59✔
769
        } else if (auto kern_stmt = dynamic_cast<const structured_control_flow::Kernel*>(current)) {
59✔
770
            queue.push_back(&kern_stmt->root());
×
771
        }
×
772
    }
773

774
    return this->structured_sdfg_->root();
×
775
};
98✔
776

777
Kernel& StructuredSDFGBuilder::convert_into_kernel() {
6✔
778
    auto old_root = std::move(this->structured_sdfg_->root_);
6✔
779
    this->structured_sdfg_->root_ =
6✔
780
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, old_root->debug_info()));
6✔
781
    this->element_counter_++;
6✔
782
    auto& new_root = this->structured_sdfg_->root();
6✔
783
    auto& kernel = this->add_kernel(new_root, this->function().name());
6✔
784

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

787
    types::Scalar gridDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
788
    add_container(kernel.gridDim_x()->get_name(), gridDim_x);
6✔
789
    types::Scalar gridDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
790
    add_container(kernel.gridDim_y()->get_name(), gridDim_y);
6✔
791
    types::Scalar gridDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
792
    add_container(kernel.gridDim_z()->get_name(), gridDim_z);
6✔
793
    types::Scalar blockDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
794
    add_container(kernel.blockDim_x()->get_name(), blockDim_x);
6✔
795
    types::Scalar blockDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
796
    add_container(kernel.blockDim_y()->get_name(), blockDim_y);
6✔
797
    types::Scalar blockDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
798
    add_container(kernel.blockDim_z()->get_name(), blockDim_z);
6✔
799
    types::Scalar blockIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
800
    add_container(kernel.blockIdx_x()->get_name(), blockIdx_x);
6✔
801
    types::Scalar blockIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
802
    add_container(kernel.blockIdx_y()->get_name(), blockIdx_y);
6✔
803
    types::Scalar blockIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
804
    add_container(kernel.blockIdx_z()->get_name(), blockIdx_z);
6✔
805
    types::Scalar threadIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
806
    add_container(kernel.threadIdx_x()->get_name(), threadIdx_x);
6✔
807
    types::Scalar threadIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
808
    add_container(kernel.threadIdx_y()->get_name(), threadIdx_y);
6✔
809
    types::Scalar threadIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
810
    add_container(kernel.threadIdx_z()->get_name(), threadIdx_z);
6✔
811

812
    kernel.root().replace(symbolic::symbol("gridDim.x"), kernel.gridDim_x());
6✔
813
    kernel.root().replace(symbolic::symbol("gridDim.y"), kernel.gridDim_y());
6✔
814
    kernel.root().replace(symbolic::symbol("gridDim.z"), kernel.gridDim_z());
6✔
815

816
    kernel.root().replace(symbolic::symbol("blockDim.x"), kernel.blockDim_x());
6✔
817
    kernel.root().replace(symbolic::symbol("blockDim.y"), kernel.blockDim_y());
6✔
818
    kernel.root().replace(symbolic::symbol("blockDim.z"), kernel.blockDim_z());
6✔
819

820
    kernel.root().replace(symbolic::symbol("blockIdx.x"), kernel.blockIdx_x());
6✔
821
    kernel.root().replace(symbolic::symbol("blockIdx.y"), kernel.blockIdx_y());
6✔
822
    kernel.root().replace(symbolic::symbol("blockIdx.z"), kernel.blockIdx_z());
6✔
823

824
    kernel.root().replace(symbolic::symbol("threadIdx.x"), kernel.threadIdx_x());
6✔
825
    kernel.root().replace(symbolic::symbol("threadIdx.y"), kernel.threadIdx_y());
6✔
826
    kernel.root().replace(symbolic::symbol("threadIdx.z"), kernel.threadIdx_z());
6✔
827

828
    return kernel;
6✔
829
};
6✔
830

831
/***** Section: Dataflow Graph *****/
832

833
data_flow::AccessNode& StructuredSDFGBuilder::add_access(structured_control_flow::Block& block,
1,039✔
834
                                                         const std::string& data,
835
                                                         const DebugInfo& debug_info) {
836
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
1,039✔
837
    auto res = block.dataflow_->nodes_.insert(
2,078✔
838
        {vertex, std::unique_ptr<data_flow::AccessNode>(new data_flow::AccessNode(
1,039✔
839
                     this->element_counter_, debug_info, vertex, block.dataflow(), data))});
1,039✔
840
    this->element_counter_++;
1,039✔
841
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
1,039✔
842
};
×
843

844
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
550✔
845
    structured_control_flow::Block& block, const data_flow::TaskletCode code,
846
    const std::pair<std::string, sdfg::types::Scalar>& output,
847
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
848
    const DebugInfo& debug_info) {
849
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
550✔
850
    auto res = block.dataflow_->nodes_.insert(
1,100✔
851
        {vertex, std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
1,100✔
852
                     this->element_counter_, debug_info, vertex, block.dataflow(), code, output,
550✔
853
                     inputs, symbolic::__true__()))});
550✔
854
    this->element_counter_++;
550✔
855
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
550✔
856
};
×
857

858
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
1,090✔
859
    structured_control_flow::Block& block, data_flow::DataFlowNode& src,
860
    const std::string& src_conn, data_flow::DataFlowNode& dst, const std::string& dst_conn,
861
    const data_flow::Subset& subset, const DebugInfo& debug_info) {
862
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
1,090✔
863
    auto res = block.dataflow_->edges_.insert(
2,180✔
864
        {edge.first, std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,090✔
865
                         this->element_counter_, debug_info, edge.first, block.dataflow(), src,
1,090✔
866
                         src_conn, dst, dst_conn, subset))});
1,090✔
867
    this->element_counter_++;
1,090✔
868
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
1,090✔
869
};
×
870

871
data_flow::LibraryNode& StructuredSDFGBuilder::add_library_node(
10✔
872
    structured_control_flow::Block& block, const data_flow::LibraryNodeType& call,
873
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& outputs,
874
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
875
    const bool has_side_effect, const DebugInfo& debug_info) {
876
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
10✔
877
    auto res = block.dataflow_->nodes_.insert(
20✔
878
        {vertex, std::unique_ptr<data_flow::LibraryNode>(new data_flow::LibraryNode(
10✔
879
                     this->element_counter_, debug_info, vertex, block.dataflow(), outputs, inputs,
10✔
880
                     call, has_side_effect))});
10✔
881
    this->element_counter_++;
10✔
882
    return dynamic_cast<data_flow::LibraryNode&>(*(res.first->second));
10✔
883
}
×
884

885
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block,
×
886
                                          const data_flow::Memlet& edge) {
887
    auto& graph = block.dataflow();
×
888
    auto e = edge.edge();
×
889
    boost::remove_edge(e, graph.graph_);
×
890
    graph.edges_.erase(e);
×
891
};
×
892

893
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block,
×
894
                                        const data_flow::DataFlowNode& node) {
895
    auto& graph = block.dataflow();
×
896
    auto v = node.vertex();
×
897
    boost::remove_vertex(v, graph.graph_);
×
898
    graph.nodes_.erase(v);
×
899
};
×
900

901
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
8✔
902
                                       const data_flow::Tasklet& node) {
903
    auto& graph = block.dataflow();
8✔
904

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

907
    // Delete incoming
908
    std::list<const data_flow::Memlet*> iedges;
8✔
909
    for (auto& iedge : graph.in_edges(node)) {
15✔
910
        iedges.push_back(&iedge);
7✔
911
    }
912
    for (auto iedge : iedges) {
15✔
913
        auto& src = iedge->src();
7✔
914
        to_delete.insert(&src);
7✔
915

916
        auto edge = iedge->edge();
7✔
917
        graph.edges_.erase(edge);
7✔
918
        boost::remove_edge(edge, graph.graph_);
7✔
919
    }
920

921
    // Delete outgoing
922
    std::list<const data_flow::Memlet*> oedges;
8✔
923
    for (auto& oedge : graph.out_edges(node)) {
16✔
924
        oedges.push_back(&oedge);
8✔
925
    }
926
    for (auto oedge : oedges) {
16✔
927
        auto& dst = oedge->dst();
8✔
928
        to_delete.insert(&dst);
8✔
929

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

935
    // Delete nodes
936
    for (auto obsolete_node : to_delete) {
31✔
937
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
938
            auto vertex = obsolete_node->vertex();
23✔
939
            graph.nodes_.erase(vertex);
23✔
940
            boost::remove_vertex(vertex, graph.graph_);
23✔
941
        }
23✔
942
    }
943
};
8✔
944

945
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
1✔
946
                                       const data_flow::AccessNode& node) {
947
    auto& graph = block.dataflow();
1✔
948
    assert(graph.out_degree(node) == 0);
1✔
949

950
    std::list<const data_flow::Memlet*> tmp;
1✔
951
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
952
    while (!queue.empty()) {
3✔
953
        auto current = queue.front();
2✔
954
        queue.pop_front();
2✔
955
        if (current != &node) {
2✔
956
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
957
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
958
                    continue;
×
959
                }
960
            }
×
961
        }
1✔
962

963
        tmp.clear();
2✔
964
        for (auto& iedge : graph.in_edges(*current)) {
3✔
965
            tmp.push_back(&iedge);
1✔
966
        }
967
        for (auto iedge : tmp) {
3✔
968
            auto& src = iedge->src();
1✔
969
            queue.push_back(&src);
1✔
970

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

976
        auto vertex = current->vertex();
2✔
977
        graph.nodes_.erase(vertex);
2✔
978
        boost::remove_vertex(vertex, graph.graph_);
2✔
979
    }
980
};
1✔
981

982
data_flow::AccessNode& StructuredSDFGBuilder::symbolic_expression_to_dataflow(
1✔
983
    structured_control_flow::Block& parent, const symbolic::Expression& expr) {
984
    auto& sdfg = this->subject();
1✔
985

986
    codegen::CPPLanguageExtension language_extension;
1✔
987

988
    // Base cases
989
    if (SymEngine::is_a<SymEngine::Symbol>(*expr)) {
1✔
990
        auto sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(expr);
1✔
991

992
        // Determine type
993
        types::Scalar sym_type = types::Scalar(types::PrimitiveType::Void);
1✔
994
        if (symbolic::is_nvptx(sym)) {
1✔
995
            sym_type = types::Scalar(types::PrimitiveType::Int32);
×
996
        } else {
×
997
            sym_type = static_cast<const types::Scalar&>(sdfg.type(sym->get_name()));
1✔
998
        }
999

1000
        // Add new container for intermediate result
1001
        auto tmp = this->find_new_name();
1✔
1002
        this->add_container(tmp, sym_type);
1✔
1003

1004
        // Create dataflow graph
1005
        auto& input_node = this->add_access(parent, sym->get_name());
1✔
1006
        auto& output_node = this->add_access(parent, tmp);
1✔
1007
        auto& tasklet = this->add_tasklet(parent, data_flow::TaskletCode::assign,
2✔
1008
                                          {"_out", sym_type}, {{"_in", sym_type}});
1✔
1009
        this->add_memlet(parent, input_node, "void", tasklet, "_in", {symbolic::integer(0)});
1✔
1010
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
1✔
1011

1012
        return output_node;
1✔
1013
    } else if (SymEngine::is_a<SymEngine::Integer>(*expr)) {
1✔
1014
        auto tmp = this->find_new_name();
×
1015
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Int64));
×
1016

1017
        auto& output_node = this->add_access(parent, tmp);
×
1018
        auto& tasklet = this->add_tasklet(
×
1019
            parent, data_flow::TaskletCode::assign,
×
1020
            {"_out", types::Scalar(types::PrimitiveType::Int64)},
×
1021
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Int64)}});
×
1022
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1023
        return output_node;
×
1024
    } else if (SymEngine::is_a<SymEngine::BooleanAtom>(*expr)) {
×
1025
        auto tmp = this->find_new_name();
×
1026
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1027

1028
        auto& output_node = this->add_access(parent, tmp);
×
1029
        auto& tasklet = this->add_tasklet(
×
1030
            parent, data_flow::TaskletCode::assign,
×
1031
            {"_out", types::Scalar(types::PrimitiveType::Bool)},
×
1032
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Bool)}});
×
1033
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1034
        return output_node;
×
1035
    } else if (SymEngine::is_a<SymEngine::Or>(*expr)) {
×
1036
        auto or_expr = SymEngine::rcp_static_cast<const SymEngine::Or>(expr);
×
1037
        assert(or_expr->get_container().size() == 2);
×
1038

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

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

1053
        auto& output_node = this->add_access(parent, tmp);
×
1054
        auto& tasklet =
×
1055
            this->add_tasklet(parent, data_flow::TaskletCode::logical_or,
×
1056
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1057
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1058
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1059
                             {symbolic::integer(0)});
×
1060
        }
×
1061
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1062
        return output_node;
×
1063
    } else if (SymEngine::is_a<SymEngine::And>(*expr)) {
×
1064
        auto and_expr = SymEngine::rcp_static_cast<const SymEngine::And>(expr);
×
1065
        assert(and_expr->get_container().size() == 2);
×
1066

1067
        std::vector<data_flow::AccessNode*> input_nodes;
×
1068
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1069
        for (auto& arg : and_expr->get_container()) {
×
1070
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1071
            input_nodes.push_back(&input_node);
×
1072
            input_types.push_back(
×
1073
                {"_in" + std::to_string(input_types.size() + 1),
×
1074
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1075
        }
1076

1077
        // Add new container for intermediate result
1078
        auto tmp = this->find_new_name();
×
1079
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1080

1081
        auto& output_node = this->add_access(parent, tmp);
×
1082
        auto& tasklet =
×
1083
            this->add_tasklet(parent, data_flow::TaskletCode::logical_and,
×
1084
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1085
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1086
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1087
                             {symbolic::integer(0)});
×
1088
        }
×
1089
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1090
        return output_node;
×
1091
    } else {
×
1092
        throw std::runtime_error("Unsupported expression type");
×
1093
    }
1094
};
1✔
1095

1096
}  // namespace builder
1097
}  // 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