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

daisytuner / sdfglib / 15133758385

20 May 2025 09:19AM UTC coverage: 60.543% (-3.0%) from 63.542%
15133758385

push

github

web-flow
Merge pull request #22 from daisytuner/normalization

Removes normalization passes

7922 of 13085 relevant lines covered (60.54%)

104.24 hits per line

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

71.24
/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
    std::unordered_set<const control_flow::State*> visited;
4✔
84
    this->traverse_with_loop_detection(sdfg, root, start_state, nullptr, continues, breaks,
4✔
85
                                       pdom_tree, visited);
86
};
4✔
87

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

98
    auto in_edges = sdfg.in_edges(*current);
8✔
99

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

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

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

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

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

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

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

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

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

180
        auto out_edges = sdfg.out_edges(*curr);
15✔
181
        auto out_degree = sdfg.out_degree(*curr);
15✔
182

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

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

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

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

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

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

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

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

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

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

281
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
313✔
282
    : FunctionBuilder(), structured_sdfg_(std::move(sdfg)) {};
313✔
283

284
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name)
460✔
285
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name)) {};
460✔
286

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

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

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

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

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

309
    this->traverse(sdfg);
4✔
310
};
4✔
311

312
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
2,539✔
313

314
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
427✔
315
    return std::move(this->structured_sdfg_);
427✔
316
};
317

318
Sequence& StructuredSDFGBuilder::add_sequence(Sequence& parent,
34✔
319
                                              const sdfg::symbolic::Assignments& assignments,
320
                                              const DebugInfo& debug_info) {
321
    parent.children_.push_back(
34✔
322
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
34✔
323
    this->element_counter_++;
34✔
324
    parent.transitions_.push_back(std::unique_ptr<Transition>(
34✔
325
        new Transition(this->element_counter_, debug_info, assignments)));
34✔
326
    this->element_counter_++;
34✔
327

328
    return static_cast<Sequence&>(*parent.children_.back().get());
34✔
329
};
×
330

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

343
    parent.children_.insert(
4✔
344
        parent.children_.begin() + index,
4✔
345
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
4✔
346
    this->element_counter_++;
4✔
347
    parent.transitions_.insert(
4✔
348
        parent.transitions_.begin() + index,
4✔
349
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
4✔
350
    this->element_counter_++;
4✔
351
    auto new_entry = parent.at(index);
4✔
352
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
4✔
353

354
    return {new_block, new_entry.second};
4✔
355
};
×
356

357
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t i) {
7✔
358
    parent.children_.erase(parent.children_.begin() + i);
7✔
359
    parent.transitions_.erase(parent.transitions_.begin() + i);
7✔
360
};
7✔
361

362
void StructuredSDFGBuilder::remove_child(Sequence& parent, ControlFlowNode& child) {
3✔
363
    int index = -1;
3✔
364
    for (size_t i = 0; i < parent.children_.size(); i++) {
3✔
365
        if (parent.children_.at(i).get() == &child) {
3✔
366
            index = i;
3✔
367
            break;
3✔
368
        }
369
    }
×
370

371
    parent.children_.erase(parent.children_.begin() + index);
3✔
372
    parent.transitions_.erase(parent.transitions_.begin() + index);
3✔
373
};
3✔
374

375
void StructuredSDFGBuilder::insert_children(Sequence& parent, Sequence& other, size_t i) {
10✔
376
    parent.children_.insert(parent.children_.begin() + i,
20✔
377
                            std::make_move_iterator(other.children_.begin()),
10✔
378
                            std::make_move_iterator(other.children_.end()));
10✔
379
    parent.transitions_.insert(parent.transitions_.begin() + i,
20✔
380
                               std::make_move_iterator(other.transitions_.begin()),
10✔
381
                               std::make_move_iterator(other.transitions_.end()));
10✔
382
    other.children_.clear();
10✔
383
    other.transitions_.clear();
10✔
384
};
10✔
385

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

398
    return new_block;
472✔
399
};
×
400

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

414
    return new_block;
28✔
415
};
×
416

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

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

440
    return {new_block, new_entry.second};
12✔
441
};
×
442

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

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

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

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

484
    parent.children_.insert(parent.children_.begin() + index + 1,
2✔
485
                            std::unique_ptr<Block>(new Block(this->element_counter_, debug_info)));
2✔
486
    this->element_counter_++;
2✔
487
    parent.transitions_.insert(
2✔
488
        parent.transitions_.begin() + index + 1,
2✔
489
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
2✔
490
    this->element_counter_++;
2✔
491
    auto new_entry = parent.at(index + 1);
2✔
492
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
2✔
493
    (*new_block.dataflow_).parent_ = &new_block;
2✔
494

495
    return {new_block, new_entry.second};
2✔
496
};
×
497

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

510
    parent.children_.insert(
×
511
        parent.children_.begin() + index + 1,
×
512
        std::unique_ptr<Block>(new Block(this->element_counter_, debug_info, data_flow_graph)));
×
513
    this->element_counter_++;
×
514
    parent.transitions_.insert(
×
515
        parent.transitions_.begin() + index + 1,
×
516
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
×
517
    this->element_counter_++;
×
518
    auto new_entry = parent.at(index + 1);
×
519
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
520
    (*new_block.dataflow_).parent_ = &new_block;
×
521

522
    return {new_block, new_entry.second};
×
523
};
×
524

525
For& StructuredSDFGBuilder::add_for(Sequence& parent, const symbolic::Symbol& indvar,
116✔
526
                                    const symbolic::Condition& condition,
527
                                    const symbolic::Expression& init,
528
                                    const symbolic::Expression& update,
529
                                    const sdfg::symbolic::Assignments& assignments,
530
                                    const DebugInfo& debug_info) {
531
    parent.children_.push_back(std::unique_ptr<For>(
232✔
532
        new For(this->element_counter_, debug_info, indvar, init, update, condition)));
116✔
533
    this->element_counter_ = this->element_counter_ + 2;
116✔
534
    parent.transitions_.push_back(std::unique_ptr<Transition>(
116✔
535
        new Transition(this->element_counter_, debug_info, assignments)));
116✔
536
    this->element_counter_++;
116✔
537

538
    return static_cast<For&>(*parent.children_.back().get());
116✔
539
};
×
540

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

555
    parent.children_.insert(parent.children_.begin() + index,
8✔
556
                            std::unique_ptr<For>(new For(this->element_counter_, debug_info, indvar,
8✔
557
                                                         init, update, condition)));
4✔
558
    this->element_counter_ = this->element_counter_ + 2;
4✔
559
    parent.transitions_.insert(
4✔
560
        parent.transitions_.begin() + index,
4✔
561
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
4✔
562
    this->element_counter_++;
4✔
563
    auto new_entry = parent.at(index);
4✔
564
    auto& new_block = dynamic_cast<structured_control_flow::For&>(new_entry.first);
4✔
565

566
    return {new_block, new_entry.second};
4✔
567
};
×
568

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

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

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

597
IfElse& StructuredSDFGBuilder::add_if_else(Sequence& parent, const DebugInfo& debug_info) {
35✔
598
    return this->add_if_else(parent, symbolic::Assignments{}, debug_info);
35✔
599
};
×
600

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

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

625
    parent.children_.insert(
1✔
626
        parent.children_.begin() + index,
1✔
627
        std::unique_ptr<IfElse>(new IfElse(this->element_counter_, debug_info)));
1✔
628
    this->element_counter_++;
1✔
629
    parent.transitions_.insert(
1✔
630
        parent.transitions_.begin() + index,
1✔
631
        std::unique_ptr<Transition>(new Transition(this->element_counter_, debug_info)));
1✔
632
    this->element_counter_++;
1✔
633
    auto new_entry = parent.at(index);
1✔
634
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
1✔
635

636
    return {new_block, new_entry.second};
1✔
637
};
×
638

639
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond,
63✔
640
                                          const DebugInfo& debug_info) {
641
    scope.cases_.push_back(
63✔
642
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, debug_info)));
63✔
643
    this->element_counter_++;
63✔
644
    scope.conditions_.push_back(cond);
63✔
645
    return *scope.cases_.back();
63✔
646
};
×
647

648
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t i, const DebugInfo& debug_info) {
1✔
649
    scope.cases_.erase(scope.cases_.begin() + i);
1✔
650
    scope.conditions_.erase(scope.conditions_.begin() + i);
1✔
651
};
1✔
652

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

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

684
Continue& StructuredSDFGBuilder::add_continue(Sequence& parent, const DebugInfo& debug_info) {
14✔
685
    return this->add_continue(parent, symbolic::Assignments{}, debug_info);
14✔
686
};
×
687

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

700
Break& StructuredSDFGBuilder::add_break(Sequence& parent, const DebugInfo& debug_info) {
15✔
701
    return this->add_break(parent, symbolic::Assignments{}, debug_info);
15✔
702
};
×
703

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

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

728
For& StructuredSDFGBuilder::convert_while(Sequence& parent, While& loop,
×
729
                                          const symbolic::Symbol& indvar,
730
                                          const symbolic::Condition& condition,
731
                                          const symbolic::Expression& init,
732
                                          const symbolic::Expression& update) {
733
    // Insert for loop
734
    size_t index = 0;
×
735
    for (auto& entry : parent.children_) {
×
736
        if (entry.get() == &loop) {
×
737
            break;
×
738
        }
739
        index++;
×
740
    }
741
    auto iter = parent.children_.begin() + index;
×
742
    auto& new_iter = *parent.children_.insert(
×
743
        iter + 1, std::unique_ptr<For>(new For(this->element_counter_, loop.debug_info(), indvar,
×
744
                                               init, update, condition)));
×
745
    this->element_counter_ = this->element_counter_ + 2;
×
746
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
747
    this->insert_children(for_loop.root(), loop.root(), 0);
×
748

749
    // Remove while loop
750
    parent.children_.erase(parent.children_.begin() + index);
×
751

752
    return for_loop;
×
753
};
×
754

755
void StructuredSDFGBuilder::clear_sequence(Sequence& parent) {
2✔
756
    parent.children_.clear();
2✔
757
    parent.transitions_.clear();
2✔
758
};
2✔
759

760
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
7✔
761
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
7✔
762
    while (!queue.empty()) {
7✔
763
        auto current = queue.front();
7✔
764
        queue.pop_front();
7✔
765

766
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
7✔
767
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
7✔
768
                if (&sequence_stmt->at(i).first == &node) {
7✔
769
                    return *sequence_stmt;
7✔
770
                }
771
                queue.push_back(&sequence_stmt->at(i).first);
×
772
            }
×
773
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
774
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
775
                queue.push_back(&if_else_stmt->at(i).first);
×
776
            }
×
777
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
778
            queue.push_back(&while_stmt->root());
×
779
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
×
780
            queue.push_back(&for_stmt->root());
×
781
        } else if (auto kern_stmt = dynamic_cast<const structured_control_flow::Kernel*>(current)) {
×
782
            queue.push_back(&kern_stmt->root());
×
783
        }
×
784
    }
785

786
    return this->structured_sdfg_->root();
×
787
};
7✔
788

789
Kernel& StructuredSDFGBuilder::convert_into_kernel() {
6✔
790
    auto old_root = std::move(this->structured_sdfg_->root_);
6✔
791
    this->structured_sdfg_->root_ =
6✔
792
        std::unique_ptr<Sequence>(new Sequence(this->element_counter_, old_root->debug_info()));
6✔
793
    this->element_counter_++;
6✔
794
    auto& new_root = this->structured_sdfg_->root();
6✔
795
    auto& kernel = this->add_kernel(new_root, this->function().name());
6✔
796

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

799
    types::Scalar gridDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
800
    add_container(kernel.gridDim_x()->get_name(), gridDim_x);
6✔
801
    types::Scalar gridDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
802
    add_container(kernel.gridDim_y()->get_name(), gridDim_y);
6✔
803
    types::Scalar gridDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
804
    add_container(kernel.gridDim_z()->get_name(), gridDim_z);
6✔
805
    types::Scalar blockDim_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
806
    add_container(kernel.blockDim_x()->get_name(), blockDim_x);
6✔
807
    types::Scalar blockDim_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
808
    add_container(kernel.blockDim_y()->get_name(), blockDim_y);
6✔
809
    types::Scalar blockDim_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
810
    add_container(kernel.blockDim_z()->get_name(), blockDim_z);
6✔
811
    types::Scalar blockIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
812
    add_container(kernel.blockIdx_x()->get_name(), blockIdx_x);
6✔
813
    types::Scalar blockIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
814
    add_container(kernel.blockIdx_y()->get_name(), blockIdx_y);
6✔
815
    types::Scalar blockIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
816
    add_container(kernel.blockIdx_z()->get_name(), blockIdx_z);
6✔
817
    types::Scalar threadIdx_x(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
818
    add_container(kernel.threadIdx_x()->get_name(), threadIdx_x);
6✔
819
    types::Scalar threadIdx_y(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
820
    add_container(kernel.threadIdx_y()->get_name(), threadIdx_y);
6✔
821
    types::Scalar threadIdx_z(types::PrimitiveType::Int32, types::DeviceLocation::nvptx, 0);
6✔
822
    add_container(kernel.threadIdx_z()->get_name(), threadIdx_z);
6✔
823

824
    kernel.root().replace(symbolic::symbol("gridDim.x"), kernel.gridDim_x());
6✔
825
    kernel.root().replace(symbolic::symbol("gridDim.y"), kernel.gridDim_y());
6✔
826
    kernel.root().replace(symbolic::symbol("gridDim.z"), kernel.gridDim_z());
6✔
827

828
    kernel.root().replace(symbolic::symbol("blockDim.x"), kernel.blockDim_x());
6✔
829
    kernel.root().replace(symbolic::symbol("blockDim.y"), kernel.blockDim_y());
6✔
830
    kernel.root().replace(symbolic::symbol("blockDim.z"), kernel.blockDim_z());
6✔
831

832
    kernel.root().replace(symbolic::symbol("blockIdx.x"), kernel.blockIdx_x());
6✔
833
    kernel.root().replace(symbolic::symbol("blockIdx.y"), kernel.blockIdx_y());
6✔
834
    kernel.root().replace(symbolic::symbol("blockIdx.z"), kernel.blockIdx_z());
6✔
835

836
    kernel.root().replace(symbolic::symbol("threadIdx.x"), kernel.threadIdx_x());
6✔
837
    kernel.root().replace(symbolic::symbol("threadIdx.y"), kernel.threadIdx_y());
6✔
838
    kernel.root().replace(symbolic::symbol("threadIdx.z"), kernel.threadIdx_z());
6✔
839

840
    return kernel;
6✔
841
};
6✔
842

843
/***** Section: Dataflow Graph *****/
844

845
data_flow::AccessNode& StructuredSDFGBuilder::add_access(structured_control_flow::Block& block,
571✔
846
                                                         const std::string& data,
847
                                                         const DebugInfo& debug_info) {
848
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
571✔
849
    auto res = block.dataflow_->nodes_.insert(
1,142✔
850
        {vertex, std::unique_ptr<data_flow::AccessNode>(new data_flow::AccessNode(
571✔
851
                     this->element_counter_, debug_info, vertex, block.dataflow(), data))});
571✔
852
    this->element_counter_++;
571✔
853
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
571✔
854
};
×
855

856
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
361✔
857
    structured_control_flow::Block& block, const data_flow::TaskletCode code,
858
    const std::pair<std::string, sdfg::types::Scalar>& output,
859
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
860
    const DebugInfo& debug_info) {
861
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
361✔
862
    auto res = block.dataflow_->nodes_.insert(
722✔
863
        {vertex, std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
722✔
864
                     this->element_counter_, debug_info, vertex, block.dataflow(), code, output,
361✔
865
                     inputs, symbolic::__true__()))});
361✔
866
    this->element_counter_++;
361✔
867
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
361✔
868
};
×
869

870
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
581✔
871
    structured_control_flow::Block& block, data_flow::DataFlowNode& src,
872
    const std::string& src_conn, data_flow::DataFlowNode& dst, const std::string& dst_conn,
873
    const data_flow::Subset& subset, const DebugInfo& debug_info) {
874
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
581✔
875
    auto res = block.dataflow_->edges_.insert(
1,162✔
876
        {edge.first, std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
581✔
877
                         this->element_counter_, debug_info, edge.first, block.dataflow(), src,
581✔
878
                         src_conn, dst, dst_conn, subset))});
581✔
879
    this->element_counter_++;
581✔
880
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
581✔
881
};
×
882

883
data_flow::LibraryNode& StructuredSDFGBuilder::add_library_node(
10✔
884
    structured_control_flow::Block& block, const data_flow::LibraryNodeType& call,
885
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& outputs,
886
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
887
    const bool has_side_effect, const DebugInfo& debug_info) {
888
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
10✔
889
    auto res = block.dataflow_->nodes_.insert(
20✔
890
        {vertex, std::unique_ptr<data_flow::LibraryNode>(new data_flow::LibraryNode(
10✔
891
                     this->element_counter_, debug_info, vertex, block.dataflow(), outputs, inputs,
10✔
892
                     call, has_side_effect))});
10✔
893
    this->element_counter_++;
10✔
894
    return dynamic_cast<data_flow::LibraryNode&>(*(res.first->second));
10✔
895
}
×
896

897
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block,
×
898
                                          const data_flow::Memlet& edge) {
899
    auto& graph = block.dataflow();
×
900
    auto e = edge.edge();
×
901
    boost::remove_edge(e, graph.graph_);
×
902
    graph.edges_.erase(e);
×
903
};
×
904

905
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block,
×
906
                                        const data_flow::DataFlowNode& node) {
907
    auto& graph = block.dataflow();
×
908
    auto v = node.vertex();
×
909
    boost::remove_vertex(v, graph.graph_);
×
910
    graph.nodes_.erase(v);
×
911
};
×
912

913
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
8✔
914
                                       const data_flow::Tasklet& node) {
915
    auto& graph = block.dataflow();
8✔
916

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

919
    // Delete incoming
920
    std::list<const data_flow::Memlet*> iedges;
8✔
921
    for (auto& iedge : graph.in_edges(node)) {
15✔
922
        iedges.push_back(&iedge);
7✔
923
    }
924
    for (auto iedge : iedges) {
15✔
925
        auto& src = iedge->src();
7✔
926
        to_delete.insert(&src);
7✔
927

928
        auto edge = iedge->edge();
7✔
929
        graph.edges_.erase(edge);
7✔
930
        boost::remove_edge(edge, graph.graph_);
7✔
931
    }
932

933
    // Delete outgoing
934
    std::list<const data_flow::Memlet*> oedges;
8✔
935
    for (auto& oedge : graph.out_edges(node)) {
16✔
936
        oedges.push_back(&oedge);
8✔
937
    }
938
    for (auto oedge : oedges) {
16✔
939
        auto& dst = oedge->dst();
8✔
940
        to_delete.insert(&dst);
8✔
941

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

947
    // Delete nodes
948
    for (auto obsolete_node : to_delete) {
31✔
949
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
23✔
950
            auto vertex = obsolete_node->vertex();
23✔
951
            graph.nodes_.erase(vertex);
23✔
952
            boost::remove_vertex(vertex, graph.graph_);
23✔
953
        }
23✔
954
    }
955
};
8✔
956

957
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block,
1✔
958
                                       const data_flow::AccessNode& node) {
959
    auto& graph = block.dataflow();
1✔
960
    assert(graph.out_degree(node) == 0);
1✔
961

962
    std::list<const data_flow::Memlet*> tmp;
1✔
963
    std::list<const data_flow::DataFlowNode*> queue = {&node};
1✔
964
    while (!queue.empty()) {
3✔
965
        auto current = queue.front();
2✔
966
        queue.pop_front();
2✔
967
        if (current != &node) {
2✔
968
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
1✔
969
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
970
                    continue;
×
971
                }
972
            }
×
973
        }
1✔
974

975
        tmp.clear();
2✔
976
        for (auto& iedge : graph.in_edges(*current)) {
3✔
977
            tmp.push_back(&iedge);
1✔
978
        }
979
        for (auto iedge : tmp) {
3✔
980
            auto& src = iedge->src();
1✔
981
            queue.push_back(&src);
1✔
982

983
            auto edge = iedge->edge();
1✔
984
            graph.edges_.erase(edge);
1✔
985
            boost::remove_edge(edge, graph.graph_);
1✔
986
        }
987

988
        auto vertex = current->vertex();
2✔
989
        graph.nodes_.erase(vertex);
2✔
990
        boost::remove_vertex(vertex, graph.graph_);
2✔
991
    }
992
};
1✔
993

994
data_flow::AccessNode& StructuredSDFGBuilder::symbolic_expression_to_dataflow(
×
995
    structured_control_flow::Block& parent, const symbolic::Expression& expr) {
996
    auto& sdfg = this->subject();
×
997

998
    codegen::CPPLanguageExtension language_extension;
×
999

1000
    // Base cases
1001
    if (SymEngine::is_a<SymEngine::Symbol>(*expr)) {
×
1002
        auto sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(expr);
×
1003

1004
        // Determine type
1005
        types::Scalar sym_type = types::Scalar(types::PrimitiveType::Void);
×
1006
        if (symbolic::is_nvptx(sym)) {
×
1007
            sym_type = types::Scalar(types::PrimitiveType::Int32);
×
1008
        } else {
×
1009
            sym_type = static_cast<const types::Scalar&>(sdfg.type(sym->get_name()));
×
1010
        }
1011

1012
        // Add new container for intermediate result
1013
        auto tmp = this->find_new_name();
×
1014
        this->add_container(tmp, sym_type);
×
1015

1016
        // Create dataflow graph
1017
        auto& input_node = this->add_access(parent, sym->get_name());
×
1018
        auto& output_node = this->add_access(parent, tmp);
×
1019
        auto& tasklet = this->add_tasklet(parent, data_flow::TaskletCode::assign,
×
1020
                                          {"_out", sym_type}, {{"_in", sym_type}});
×
1021
        this->add_memlet(parent, input_node, "void", tasklet, "_in", {symbolic::integer(0)});
×
1022
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1023

1024
        return output_node;
×
1025
    } else if (SymEngine::is_a<SymEngine::Integer>(*expr)) {
×
1026
        auto tmp = this->find_new_name();
×
1027
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Int64));
×
1028

1029
        auto& output_node = this->add_access(parent, tmp);
×
1030
        auto& tasklet = this->add_tasklet(
×
1031
            parent, data_flow::TaskletCode::assign,
×
1032
            {"_out", types::Scalar(types::PrimitiveType::Int64)},
×
1033
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Int64)}});
×
1034
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1035
        return output_node;
×
1036
    } else if (SymEngine::is_a<SymEngine::BooleanAtom>(*expr)) {
×
1037
        auto tmp = this->find_new_name();
×
1038
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1039

1040
        auto& output_node = this->add_access(parent, tmp);
×
1041
        auto& tasklet = this->add_tasklet(
×
1042
            parent, data_flow::TaskletCode::assign,
×
1043
            {"_out", types::Scalar(types::PrimitiveType::Bool)},
×
1044
            {{language_extension.expression(expr), types::Scalar(types::PrimitiveType::Bool)}});
×
1045
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1046
        return output_node;
×
1047
    } else if (SymEngine::is_a<SymEngine::Or>(*expr)) {
×
1048
        auto or_expr = SymEngine::rcp_static_cast<const SymEngine::Or>(expr);
×
1049
        assert(or_expr->get_container().size() == 2);
×
1050

1051
        std::vector<data_flow::AccessNode*> input_nodes;
×
1052
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1053
        for (auto& arg : or_expr->get_container()) {
×
1054
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1055
            input_nodes.push_back(&input_node);
×
1056
            input_types.push_back(
×
1057
                {"_in" + std::to_string(input_types.size() + 1),
×
1058
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1059
        }
1060

1061
        // Add new container for intermediate result
1062
        auto tmp = this->find_new_name();
×
1063
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1064

1065
        auto& output_node = this->add_access(parent, tmp);
×
1066
        auto& tasklet =
×
1067
            this->add_tasklet(parent, data_flow::TaskletCode::logical_or,
×
1068
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1069
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1070
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1071
                             {symbolic::integer(0)});
×
1072
        }
×
1073
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1074
        return output_node;
×
1075
    } else if (SymEngine::is_a<SymEngine::And>(*expr)) {
×
1076
        auto and_expr = SymEngine::rcp_static_cast<const SymEngine::And>(expr);
×
1077
        assert(and_expr->get_container().size() == 2);
×
1078

1079
        std::vector<data_flow::AccessNode*> input_nodes;
×
1080
        std::vector<std::pair<std::string, types::Scalar>> input_types;
×
1081
        for (auto& arg : and_expr->get_container()) {
×
1082
            auto& input_node = symbolic_expression_to_dataflow(parent, arg);
×
1083
            input_nodes.push_back(&input_node);
×
1084
            input_types.push_back(
×
1085
                {"_in" + std::to_string(input_types.size() + 1),
×
1086
                 static_cast<const types::Scalar&>(sdfg.type(input_node.data()))});
×
1087
        }
1088

1089
        // Add new container for intermediate result
1090
        auto tmp = this->find_new_name();
×
1091
        this->add_container(tmp, types::Scalar(types::PrimitiveType::Bool));
×
1092

1093
        auto& output_node = this->add_access(parent, tmp);
×
1094
        auto& tasklet =
×
1095
            this->add_tasklet(parent, data_flow::TaskletCode::logical_and,
×
1096
                              {"_out", types::Scalar(types::PrimitiveType::Bool)}, input_types);
×
1097
        for (size_t i = 0; i < input_nodes.size(); i++) {
×
1098
            this->add_memlet(parent, *input_nodes.at(i), "void", tasklet, input_types.at(i).first,
×
1099
                             {symbolic::integer(0)});
×
1100
        }
×
1101
        this->add_memlet(parent, tasklet, "_out", output_node, "void", {symbolic::integer(0)});
×
1102
        return output_node;
×
1103
    } else {
×
1104
        throw std::runtime_error("Unsupported expression type");
×
1105
    }
1106
};
×
1107

1108
}  // namespace builder
1109
}  // 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