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

daisytuner / docc / 27981272983

22 Jun 2026 08:18PM UTC coverage: 61.754% (-0.03%) from 61.782%
27981272983

Pull #781

github

web-flow
Merge bddaa3724 into fe87d162b
Pull Request #781: Extend Segformer benchmarks setup

987 of 1432 new or added lines in 62 files covered. (68.92%)

9 existing lines in 7 files now uncovered.

38121 of 61730 relevant lines covered (61.75%)

993.19 hits per line

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

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

3
#include <cstddef>
4

5
#include "sdfg/data_flow/library_node.h"
6
#include "sdfg/structured_control_flow/map.h"
7
#include "sdfg/structured_control_flow/sequence.h"
8
#include "sdfg/structured_control_flow/structured_loop.h"
9
#include "sdfg/types/utils.h"
10

11
#define TRAVERSE_CUTOFF 30
100✔
12

13
using namespace sdfg::control_flow;
14
using namespace sdfg::structured_control_flow;
15

16
namespace sdfg {
17
namespace builder {
18
std::unordered_set<const control_flow::State*> StructuredSDFGBuilder::
19
    determine_loop_nodes(SDFG& sdfg, const control_flow::State& start, const control_flow::State& end) const {
13✔
20
    std::unordered_set<const control_flow::State*> nodes;
13✔
21
    std::unordered_set<const control_flow::State*> visited;
13✔
22
    std::list<const control_flow::State*> queue = {&start};
13✔
23
    while (!queue.empty()) {
56✔
24
        auto curr = queue.front();
43✔
25
        queue.pop_front();
43✔
26
        if (visited.find(curr) != visited.end()) {
43✔
27
            continue;
1✔
28
        }
1✔
29
        visited.insert(curr);
42✔
30

31
        nodes.insert(curr);
42✔
32
        if (curr == &end) {
42✔
33
            continue;
13✔
34
        }
13✔
35

36
        for (auto& iedge : sdfg.in_edges(*curr)) {
30✔
37
            queue.push_back(&iedge.src());
30✔
38
        }
30✔
39
    }
29✔
40

41
    // Iteratively expand nodes to reduce frontier size
42
    auto dom_tree = sdfg.dominator_tree();
13✔
43
    auto dominates = [&](const control_flow::State* a, const control_flow::State* b) {
13✔
44
        const control_flow::State* curr = b;
12✔
45
        while (curr != nullptr) {
42✔
46
            if (curr == a) return true;
42✔
47
            if (dom_tree.find(curr) == dom_tree.end()) break;
30✔
48
            curr = dom_tree.at(curr);
30✔
49
        }
30✔
50
        return false;
×
51
    };
12✔
52

53
    // Identify header exits
54
    std::unordered_set<const control_flow::State*> stop_nodes;
13✔
55
    for (auto& edge : sdfg.out_edges(end)) {
24✔
56
        if (nodes.find(&edge.dst()) == nodes.end()) {
24✔
57
            stop_nodes.insert(&edge.dst());
11✔
58
        }
11✔
59
    }
24✔
60

61
    // If no header exits, check latch exits (Do-While)
62
    if (stop_nodes.empty()) {
13✔
63
        for (auto& edge : sdfg.out_edges(start)) {
4✔
64
            if (nodes.find(&edge.dst()) == nodes.end()) {
4✔
65
                stop_nodes.insert(&edge.dst());
2✔
66
            }
2✔
67
        }
4✔
68
    }
2✔
69

70
    // If still no exits, check any natural loop exit (e.g. infinite loop with break)
71
    if (stop_nodes.empty()) {
13✔
72
        for (auto node : nodes) {
×
73
            for (auto& edge : sdfg.out_edges(*node)) {
×
74
                if (nodes.find(&edge.dst()) == nodes.end()) {
×
75
                    stop_nodes.insert(&edge.dst());
×
76
                }
×
77
            }
×
78
        }
×
79
    }
×
80

81
    while (true) {
21✔
82
        std::unordered_set<const control_flow::State*> frontier;
21✔
83
        for (auto node : nodes) {
85✔
84
            for (auto& edge : sdfg.out_edges(*node)) {
139✔
85
                if (nodes.find(&edge.dst()) == nodes.end()) {
139✔
86
                    frontier.insert(&edge.dst());
40✔
87
                }
40✔
88
            }
139✔
89
        }
85✔
90

91
        bool changed = false;
21✔
92
        for (auto f : frontier) {
33✔
93
            // If f is a stop node, do not include it
94
            if (stop_nodes.find(f) != stop_nodes.end()) {
33✔
95
                continue;
21✔
96
            }
21✔
97
            // If f is dominated by the header, it belongs to the loop body (extended)
98
            if (dominates(&end, f)) {
12✔
99
                nodes.insert(f);
12✔
100
                changed = true;
12✔
101
            }
12✔
102
        }
12✔
103

104
        if (!changed) break;
21✔
105
    }
21✔
106

107
    return nodes;
13✔
108
};
13✔
109

110
bool post_dominates(
111
    const State* pdom,
112
    const State* node,
113
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree
114
) {
21✔
115
    if (pdom == node) {
21✔
116
        return true;
12✔
117
    }
12✔
118

119
    auto current = pdom_tree.at(node);
9✔
120
    while (current != nullptr) {
9✔
121
        if (current == pdom) {
3✔
122
            return true;
3✔
123
        }
3✔
124
        current = pdom_tree.at(current);
×
125
    }
×
126

127
    return false;
6✔
128
}
9✔
129

130

131
void StructuredSDFGBuilder::traverse(SDFG& sdfg) {
16✔
132
    // Start of SDFGS
133
    Sequence& root = *structured_sdfg_->root_;
16✔
134
    const State* start_state = &sdfg.start_state();
16✔
135

136
    auto pdom_tree = sdfg.post_dominator_tree();
16✔
137

138
    std::unordered_set<const InterstateEdge*> breaks;
16✔
139
    std::unordered_set<const InterstateEdge*> continues;
16✔
140
    for (auto& edge : sdfg.back_edges()) {
16✔
141
        continues.insert(edge);
13✔
142
    }
13✔
143

144
    this->current_traverse_loop_ = nullptr;
16✔
145
    std::unordered_set<const control_flow::State*> visited;
16✔
146
    this->structure_region(sdfg, root, start_state, nullptr, continues, breaks, pdom_tree, visited);
16✔
147
};
16✔
148

149
void StructuredSDFGBuilder::structure_region(
150
    SDFG& sdfg,
151
    Sequence& scope,
152
    const State* entry,
153
    const State* exit,
154
    const std::unordered_set<const InterstateEdge*>& continues,
155
    const std::unordered_set<const InterstateEdge*>& breaks,
156
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
157
    std::unordered_set<const control_flow::State*>& visited,
158
    bool is_loop_body
159
) {
64✔
160
    const State* current = entry;
64✔
161
    while (current != exit) {
138✔
162
        if (current == nullptr) {
100✔
163
            break;
×
164
        }
×
165

166

167
        // Cutoff
168
        if (this->function().element_counter_ > sdfg.states().size() * TRAVERSE_CUTOFF) {
100✔
169
            throw UnstructuredControlFlowException();
×
170
        }
×
171

172
        if (visited.find(current) != visited.end()) {
100✔
173
            throw UnstructuredControlFlowException();
×
174
        }
×
175
        visited.insert(current);
100✔
176

177
        // Loop detection
178
        bool is_loop_header = false;
100✔
179
        if (!is_loop_body || current != entry) {
100✔
180
            for (auto& iedge : sdfg.in_edges(*current)) {
100✔
181
                if (continues.find(&iedge) != continues.end()) {
100✔
182
                    is_loop_header = true;
9✔
183
                    break;
9✔
184
                }
9✔
185
            }
100✔
186
        }
91✔
187

188
        if (is_loop_header) {
100✔
189
            // 1. Determine nodes of loop body
190
            std::unordered_set<const InterstateEdge*> loop_edges;
9✔
191
            for (auto& iedge : sdfg.in_edges(*current)) {
22✔
192
                if (continues.find(&iedge) != continues.end()) {
22✔
193
                    loop_edges.insert(&iedge);
13✔
194
                }
13✔
195
            }
22✔
196

197
            std::unordered_set<const control_flow::State*> body;
9✔
198
            for (auto back_edge : loop_edges) {
13✔
199
                auto loop_nodes = this->determine_loop_nodes(sdfg, back_edge->src(), back_edge->dst());
13✔
200
                body.insert(loop_nodes.begin(), loop_nodes.end());
13✔
201
            }
13✔
202

203
            // 2. Determine exit states and exit edges
204
            std::unordered_set<const control_flow::State*> exit_states;
9✔
205
            std::unordered_set<const control_flow::InterstateEdge*> exit_edges;
9✔
206
            for (auto node : body) {
34✔
207
                for (auto& edge : sdfg.out_edges(*node)) {
52✔
208
                    if (body.find(&edge.dst()) == body.end()) {
52✔
209
                        if (continues.find(&edge) != continues.end()) {
12✔
210
                            continue;
×
211
                        }
×
212
                        exit_edges.insert(&edge);
12✔
213
                        exit_states.insert(&edge.dst());
12✔
214
                    }
12✔
215
                }
52✔
216
            }
34✔
217

218
            if (exit_states.size() > 1) {
9✔
219
                std::unordered_set<const control_flow::State*> non_return_exits;
×
220
                for (auto s : exit_states) {
×
221
                    if (dynamic_cast<const control_flow::ReturnState*>(s)) {
×
222
                        continue;
×
223
                    }
×
224
                    if (sdfg.out_degree(*s) > 0) {
×
225
                        non_return_exits.insert(s);
×
226
                    }
×
227
                }
×
228
                if (non_return_exits.size() == 1) {
×
229
                    exit_states = non_return_exits;
×
230
                }
×
231
            }
×
232

233
            if (exit_states.size() != 1) {
9✔
234
                throw UnstructuredControlFlowException();
×
235
            }
×
236
            const control_flow::State* exit_state = *exit_states.begin();
9✔
237

238
            for (auto& edge : breaks) {
9✔
239
                exit_edges.insert(edge);
1✔
240
            }
1✔
241

242
            // Collect debug information
243
            DebugInfo dbg_info = current->debug_info();
9✔
244
            for (auto& edge : sdfg.in_edges(*current)) {
22✔
245
                dbg_info = DebugInfo::merge(dbg_info, edge.debug_info());
22✔
246
            }
22✔
247
            for (auto node : body) {
34✔
248
                dbg_info = DebugInfo::merge(dbg_info, node->debug_info());
34✔
249
            }
34✔
250
            for (auto edge : exit_edges) {
13✔
251
                dbg_info = DebugInfo::merge(dbg_info, edge->debug_info());
13✔
252
            }
13✔
253

254
            // 3. Add while loop
255
            While& loop = this->add_while(scope, {}, dbg_info);
9✔
256
            auto last_loop_ = this->current_traverse_loop_;
9✔
257
            this->current_traverse_loop_ = &loop;
9✔
258

259
            std::unordered_set<const control_flow::State*> loop_visited(visited);
9✔
260
            loop_visited.erase(current);
9✔
261

262
            this->structure_region(
9✔
263
                sdfg, loop.root(), current, exit_state, continues, exit_edges, pdom_tree, loop_visited, true
9✔
264
            );
9✔
265
            this->current_traverse_loop_ = last_loop_;
9✔
266

267
            current = exit_state;
9✔
268
            continue;
9✔
269
        }
9✔
270

271
        auto out_edges = sdfg.out_edges(*current);
91✔
272
        auto out_degree = sdfg.out_degree(*current);
91✔
273

274
        // Case 1: Sink node
275
        if (out_degree == 0) {
91✔
276
            if (!std::ranges::empty(current->dataflow().nodes())) {
17✔
277
                this->add_block(scope, current->dataflow(), {}, current->debug_info());
×
278
            }
×
279

280
            auto return_state = dynamic_cast<const control_flow::ReturnState*>(current);
17✔
281
            assert(return_state != nullptr);
17✔
282
            if (return_state->is_data()) {
17✔
283
                this->add_return(scope, return_state->data(), {}, return_state->debug_info());
17✔
284
            } else if (return_state->is_constant()) {
17✔
285
                this->add_constant_return(
×
286
                    scope, return_state->data(), return_state->type(), {}, return_state->debug_info()
×
287
                );
×
288
            } else {
×
289
                assert(false && "Unknown return state type");
×
290
            }
×
291

292
            break;
17✔
293
        }
17✔
294

295
        // Case 2: Transition
296
        if (out_degree == 1) {
74✔
297
            auto& oedge = *out_edges.begin();
45✔
298
            if (!oedge.is_unconditional()) {
45✔
299
                throw UnstructuredControlFlowException();
×
300
            }
×
301

302
            if (!std::ranges::empty(current->dataflow().nodes()) || !oedge.assignments().empty()) {
45✔
303
                this->add_block(scope, current->dataflow(), oedge.assignments(), current->debug_info());
10✔
304
            }
10✔
305

306
            if (continues.find(&oedge) != continues.end()) {
45✔
307
                if (this->current_traverse_loop_ == nullptr) {
7✔
308
                    throw UnstructuredControlFlowException();
×
309
                }
×
310
                this->add_continue(scope, {}, oedge.debug_info());
7✔
311
                break;
7✔
312
            } else if (breaks.find(&oedge) != breaks.end()) {
38✔
313
                if (this->current_traverse_loop_ == nullptr) {
1✔
314
                    throw UnstructuredControlFlowException();
×
315
                }
×
316
                this->add_break(scope, {}, oedge.debug_info());
1✔
317
                break;
1✔
318
            } else {
37✔
319
                current = &oedge.dst();
37✔
320
            }
37✔
321
            continue;
37✔
322
        }
45✔
323

324
        // Case 3: Branches
325
        if (out_degree > 1) {
29✔
326
            if (!std::ranges::empty(current->dataflow().nodes())) {
29✔
327
                this->add_block(scope, current->dataflow(), {}, current->debug_info());
×
328
            }
×
329

330
            // Determine Merge Point
331
            const State* merge = nullptr;
29✔
332
            if (pdom_tree.find(current) != pdom_tree.end()) {
29✔
333
                merge = pdom_tree.at(current);
29✔
334
            }
29✔
335

336

337
            // If merge is beyond exit, clamp to exit
338
            if (exit != nullptr && merge != nullptr) {
29✔
339
                if (post_dominates(merge, exit, pdom_tree)) {
21✔
340
                    merge = exit;
15✔
341
                }
15✔
342
            }
21✔
343

344
            if (merge != nullptr && visited.find(merge) != visited.end()) {
29✔
345
                merge = exit;
4✔
346
            }
4✔
347

348
            if (merge == nullptr && exit != nullptr) {
29✔
349
                merge = exit;
×
350
            }
×
351

352
            auto& if_else = this->add_if_else(scope, {}, current->debug_info());
29✔
353
            for (auto& out_edge : out_edges) {
57✔
354
                auto& branch = this->add_case(if_else, out_edge.condition(), out_edge.debug_info());
57✔
355
                if (!out_edge.assignments().empty()) {
57✔
356
                    this->add_block(branch, out_edge.assignments(), out_edge.debug_info());
5✔
357
                }
5✔
358
                if (continues.find(&out_edge) != continues.end()) {
57✔
359
                    if (this->current_traverse_loop_ == nullptr) {
7✔
360
                        throw UnstructuredControlFlowException();
1✔
361
                    }
1✔
362
                    this->add_continue(branch, {}, out_edge.debug_info());
6✔
363
                } else if (breaks.find(&out_edge) != breaks.end()) {
50✔
364
                    if (this->current_traverse_loop_ == nullptr) {
11✔
365
                        throw UnstructuredControlFlowException();
×
366
                    }
×
367
                    this->add_break(branch, {}, out_edge.debug_info());
11✔
368
                } else {
39✔
369
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
39✔
370
                    this->structure_region(
39✔
371
                        sdfg, branch, &out_edge.dst(), merge, continues, breaks, pdom_tree, branch_visited
39✔
372
                    );
39✔
373
                }
39✔
374
            }
57✔
375

376
            current = merge;
28✔
377
            continue;
28✔
378
        }
29✔
379
    }
29✔
380
}
64✔
381

382
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
55,703✔
383

384
StructuredSDFGBuilder::StructuredSDFGBuilder(StructuredSDFG& sdfg)
385
    : FunctionBuilder(), structured_sdfg_(&sdfg, owned(false)) {};
×
386

387
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
388
    : FunctionBuilder(), structured_sdfg_(sdfg.release(), owned(true)) {};
278✔
389

390
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
391
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type), owned(true)) {};
1,823✔
392

393
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
394
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type, return_type), owned(true)) {};
38✔
395

396
StructuredSDFGBuilder::StructuredSDFGBuilder(SDFG& sdfg)
397
    : FunctionBuilder(),
16✔
398
      structured_sdfg_(new StructuredSDFG(sdfg.name(), sdfg.type(), sdfg.return_type()), owned(true)) {
16✔
399
    for (auto& entry : sdfg.structures_) {
16✔
400
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
401
    }
×
402

403
    for (auto& entry : sdfg.containers_) {
27✔
404
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
27✔
405
    }
27✔
406

407
    for (auto& arg : sdfg.arguments_) {
16✔
408
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
409
    }
2✔
410

411
    for (auto& ext : sdfg.externals_) {
16✔
412
        this->structured_sdfg_->externals_.push_back(ext);
1✔
413
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
1✔
414
    }
1✔
415

416
    for (auto& entry : sdfg.assumptions_) {
25✔
417
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
25✔
418
    }
25✔
419

420
    for (auto& entry : sdfg.metadata_) {
16✔
421
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
422
    }
2✔
423

424
    this->traverse(sdfg);
16✔
425
};
16✔
426

427
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
6,879✔
428

429
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
537✔
430
#ifndef NDEBUG
537✔
431
    this->structured_sdfg_->validate();
537✔
432
#endif
537✔
433

434
    if (!structured_sdfg_.get_deleter().should_delete_) {
537✔
435
        throw InvalidSDFGException("StructuredSDFGBuilder: Cannot move a non-owned SDFG");
×
436
    }
×
437

438
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
537✔
439
};
537✔
440

441
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
442
    FunctionBuilder::rename_container(old_name, new_name);
×
443

444
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
445
};
×
446

447
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
69✔
448
    auto& sdfg = this->subject();
69✔
449
    std::list<Element*> queue = {&sdfg.root()};
69✔
450
    while (!queue.empty()) {
295✔
451
        auto current = queue.front();
292✔
452
        queue.pop_front();
292✔
453

454
        if (current->element_id() == element_id) {
292✔
455
            return current;
66✔
456
        }
66✔
457

458
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
226✔
459
            auto& dataflow = block_stmt->dataflow();
13✔
460
            for (auto& node : dataflow.nodes()) {
44✔
461
                queue.push_back(&node);
44✔
462
            }
44✔
463
            for (auto& edge : dataflow.edges()) {
31✔
464
                queue.push_back(&edge);
31✔
465
            }
31✔
466
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
213✔
467
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
217✔
468
                queue.push_back(&sequence_stmt->at(i).first);
109✔
469
                queue.push_back(&sequence_stmt->at(i).second);
109✔
470
            }
109✔
471
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
108✔
472
            // Do nothing
473
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
105✔
474
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
475
                queue.push_back(&if_else_stmt->at(i).first);
×
476
            }
×
477
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
105✔
478
            queue.push_back(&for_stmt->root());
7✔
479
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
98✔
480
            queue.push_back(&while_stmt->root());
×
481
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
98✔
482
            // Do nothing
483
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
98✔
484
            // Do nothing
485
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
98✔
486
            queue.push_back(&map_stmt->root());
35✔
487
        }
35✔
488
    }
226✔
489

490
    return nullptr;
3✔
491
};
69✔
492

493
Sequence& StructuredSDFGBuilder::
494
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
28✔
495
    return insert_node_internal<Sequence>(parent, INSERT_AT_END, assignments, debug_info).first;
28✔
496
}
28✔
497

498
Sequence& StructuredSDFGBuilder::add_sequence_before(
499
    Sequence& parent,
500
    ControlFlowNode& child,
501
    const sdfg::control_flow::Assignments& assignments,
502
    const DebugInfo& debug_info
503
) {
616✔
504
    int index = parent.index(child);
616✔
505
    if (index == -1) {
616✔
506
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
507
    }
×
508

509
    return insert_node_internal<Sequence>(parent, index, assignments, debug_info).first;
616✔
510
}
616✔
511

512
Sequence& StructuredSDFGBuilder::add_sequence_after(
513
    Sequence& parent,
514
    ControlFlowNode& child,
515
    const sdfg::control_flow::Assignments& assignments,
516
    const DebugInfo& debug_info
517
) {
24✔
518
    int index = parent.index(child);
24✔
519
    if (index == -1) {
24✔
520
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
521
    }
×
522

523
    return insert_node_internal<Sequence>(parent, index + 1, assignments, debug_info).first;
24✔
524
}
24✔
525

526
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
527
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
528
    int index = parent.index(child);
×
529
    if (index == -1) {
×
530
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
531
    }
×
532

533
    return insert_node_internal<Sequence>(parent, index, {}, debug_info);
×
534
}
×
535

536
void StructuredSDFGBuilder::remove_from_parent(ControlFlowNode& child) {
4✔
537
    auto* parent = dynamic_cast<structured_control_flow::Sequence*>(child.get_parent());
4✔
538
    if (parent == nullptr) {
4✔
NEW
539
        throw InvalidSDFGException(
×
NEW
540
            "StructuredSDFGBuilder: Child has no sequence parent: #" + std::to_string(child.element_id())
×
NEW
541
        );
×
NEW
542
    }
×
543
    auto idx = parent->index(child);
4✔
544
    if (idx < 0) {
4✔
NEW
545
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found in parent");
×
NEW
546
    }
×
547
    remove_child(*parent, idx);
4✔
548
}
4✔
549

550
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
886✔
551
    parent.children_.erase(parent.children_.begin() + index);
886✔
552
    parent.transitions_.erase(parent.transitions_.begin() + index);
886✔
553
};
886✔
554

555
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
556
    parent.children_.clear();
×
557
    parent.transitions_.clear();
×
558
};
×
559

560
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
128✔
561
    size_t target_index = target.size();
128✔
562
    if (&source == &target) {
128✔
563
        target_index--;
×
564
    }
×
565
    this->move_child(source, source_index, target, target_index);
128✔
566
};
128✔
567

568
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
157✔
569
    auto node_ptr = std::move(source.children_.at(source_index));
157✔
570
    auto trans_ptr = std::move(source.transitions_.at(source_index));
157✔
571
    source.children_.erase(source.children_.begin() + source_index);
157✔
572
    source.transitions_.erase(source.transitions_.begin() + source_index);
157✔
573

574
    node_ptr->parent_ = &target;
157✔
575
    trans_ptr->parent_ = &target;
157✔
576
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
157✔
577
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
157✔
578
};
157✔
579

580
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
223✔
581
    this->move_children(source, target, target.size());
223✔
582
};
223✔
583

584
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
290✔
585
    target.children_.insert(
290✔
586
        target.children_.begin() + target_index,
290✔
587
        std::make_move_iterator(source.children_.begin()),
290✔
588
        std::make_move_iterator(source.children_.end())
290✔
589
    );
290✔
590
    target.transitions_.insert(
290✔
591
        target.transitions_.begin() + target_index,
290✔
592
        std::make_move_iterator(source.transitions_.begin()),
290✔
593
        std::make_move_iterator(source.transitions_.end())
290✔
594
    );
290✔
595
    for (auto& child : target.children_) {
621✔
596
        child->parent_ = &target;
621✔
597
    }
621✔
598
    for (auto& trans : target.transitions_) {
621✔
599
        trans->parent_ = &target;
621✔
600
    }
621✔
601
    source.children_.clear();
290✔
602
    source.transitions_.clear();
290✔
603
};
290✔
604

605
Sequence& StructuredSDFGBuilder::hoist_root() {
×
606
    auto current_root = std::move(this->structured_sdfg_->root_);
×
607

608
    this->structured_sdfg_->root_ =
×
609
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), current_root->debug_info(), nullptr));
×
610

611
    current_root->parent_ = this->structured_sdfg_->root_.get();
×
612
    this->structured_sdfg_->root_->children_.push_back(std::move(current_root));
×
613
    this->structured_sdfg_->root_->transitions_.push_back(std::unique_ptr<Transition>(
×
614
        new Transition(this->new_element_id(), current_root->debug_info(), *this->structured_sdfg_->root_)
×
615
    ));
×
616
    return *this->structured_sdfg_->root_;
×
617
};
×
618

619
Block& StructuredSDFGBuilder::
620
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
3,207✔
621
    return insert_block_internal(parent, INSERT_AT_END, nullptr, assignments, debug_info).first;
3,207✔
622
}
3,207✔
623

624
Block& StructuredSDFGBuilder::add_block(
625
    Sequence& parent,
626
    const data_flow::DataFlowGraph& data_flow_graph,
627
    const sdfg::control_flow::Assignments& assignments,
628
    const DebugInfo& debug_info
629
) {
19✔
630
    return insert_block_internal(parent, INSERT_AT_END, &data_flow_graph, assignments, debug_info).first;
19✔
631
}
19✔
632

633
std::pair<Block&, Transition&> StructuredSDFGBuilder::insert_block_internal(
634
    Sequence& parent,
635
    int32_t insert_idx,
636
    const data_flow::DataFlowGraph* import_from,
637
    const sdfg::control_flow::Assignments& assignments,
638
    const DebugInfo& debug_info
639
) {
3,581✔
640
    auto new_pair = insert_node_internal<Block>(parent, insert_idx, assignments, debug_info);
3,581✔
641

642
    if (import_from) {
3,581✔
643
        this->add_dataflow(*import_from, new_pair.first);
19✔
644
    }
19✔
645

646
    return new_pair;
3,581✔
647
}
3,581✔
648

649
Block& StructuredSDFGBuilder::add_block_before(
650
    Sequence& parent,
651
    ControlFlowNode& child,
652
    const sdfg::control_flow::Assignments& assignments,
653
    const DebugInfo& debug_info
654
) {
183✔
655
    int index = parent.index(child);
183✔
656
    if (index == -1) {
183✔
657
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
658
    }
×
659

660
    return insert_block_internal(parent, index, nullptr, assignments, debug_info).first;
183✔
661
};
183✔
662

663
Block& StructuredSDFGBuilder::add_block_before(
664
    Sequence& parent,
665
    ControlFlowNode& child,
666
    data_flow::DataFlowGraph& data_flow_graph,
667
    const sdfg::control_flow::Assignments& assignments,
668
    const DebugInfo& debug_info
669
) {
×
670
    int index = parent.index(child);
×
671
    if (index == -1) {
×
672
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
673
    }
×
674

675
    return insert_block_internal(parent, index, &data_flow_graph, assignments, debug_info).first;
×
676
};
×
677

678
Block& StructuredSDFGBuilder::add_block_after(
679
    Sequence& parent,
680
    ControlFlowNode& child,
681
    const sdfg::control_flow::Assignments& assignments,
682
    const DebugInfo& debug_info
683
) {
172✔
684
    int index = parent.index(child);
172✔
685
    if (index == -1) {
172✔
686
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
687
    }
×
688

689
    return insert_block_internal(parent, index + 1, nullptr, assignments, debug_info).first;
172✔
690
}
172✔
691

692
Block& StructuredSDFGBuilder::add_block_after(
693
    Sequence& parent,
694
    ControlFlowNode& child,
695
    data_flow::DataFlowGraph& data_flow_graph,
696
    const sdfg::control_flow::Assignments& assignments,
697
    const DebugInfo& debug_info
698
) {
×
699
    int index = parent.index(child);
×
700
    if (index == -1) {
×
701
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
702
    }
×
703

704
    return insert_block_internal(parent, index + 1, &data_flow_graph, assignments, debug_info).first;
×
705
}
×
706

707
std::pair<Block&, Transition&> StructuredSDFGBuilder::
708
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
709
    int index = parent.index(child);
×
710
    if (index == -1) {
×
711
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
712
    }
×
713

714
    return insert_block_internal(parent, index, nullptr, {}, debug_info);
×
715
}
×
716

717
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
718
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
719
) {
×
720
    int index = parent.index(child);
×
721
    if (index == -1) {
×
722
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
723
    }
×
724

725
    return insert_block_internal(parent, index, &data_flow_graph, {}, debug_info);
×
726
}
×
727

728
std::pair<Block&, Transition&> StructuredSDFGBuilder::
729
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
730
    int index = parent.index(child);
×
731
    if (index == -1) {
×
732
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
733
    }
×
734

735
    return insert_block_internal(parent, index + 1, nullptr, {}, debug_info);
×
736
}
×
737

738
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
739
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
740
) {
×
741
    int index = parent.index(child);
×
742
    if (index == -1) {
×
743
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
744
    }
×
745

746
    return insert_block_internal(parent, index + 1, &data_flow_graph, {}, debug_info);
×
747
}
×
748

749
IfElse& StructuredSDFGBuilder::
750
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
143✔
751
    return insert_node_internal<IfElse>(parent, INSERT_AT_END, assignments, debug_info).first;
143✔
752
}
143✔
753

754
IfElse& StructuredSDFGBuilder::add_if_else_before(
755
    Sequence& parent,
756
    ControlFlowNode& child,
757
    const sdfg::control_flow::Assignments& assignments,
758
    const DebugInfo& debug_info
759
) {
18✔
760
    int index = parent.index(child);
18✔
761
    if (index == -1) {
18✔
762
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
763
    }
×
764

765
    return insert_node_internal<IfElse>(parent, index, assignments, debug_info).first;
18✔
766
}
18✔
767

768
IfElse& StructuredSDFGBuilder::add_if_else_after(
769
    Sequence& parent,
770
    ControlFlowNode& child,
771
    const sdfg::control_flow::Assignments& assignments,
772
    const DebugInfo& debug_info
773
) {
×
774
    int index = parent.index(child);
×
775
    if (index == -1) {
×
776
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
777
    }
×
778

779
    return insert_node_internal<IfElse>(parent, index + 1, assignments, debug_info).first;
×
780
}
×
781

782
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
783
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
784
    int index = parent.index(child);
×
785
    if (index == -1) {
×
786
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
787
    }
×
788

789
    return insert_node_internal<IfElse>(parent, INSERT_AT_END, {}, debug_info);
×
790
};
×
791

792
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
259✔
793
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info, &scope)));
259✔
794

795
    scope.conditions_.push_back(cond);
259✔
796
    return *scope.cases_.back();
259✔
797
};
259✔
798

799
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
800
    scope.cases_.erase(scope.cases_.begin() + index);
×
801
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
802
};
×
803

804
While& StructuredSDFGBuilder::
805
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
53✔
806
    return insert_node_internal<While>(parent, INSERT_AT_END, assignments, debug_info).first;
53✔
807
};
53✔
808

809
For& StructuredSDFGBuilder::add_for(
810
    Sequence& parent,
811
    const symbolic::Symbol indvar,
812
    const symbolic::Condition condition,
813
    const symbolic::Expression init,
814
    const symbolic::Expression update,
815
    const sdfg::control_flow::Assignments& assignments,
816
    const DebugInfo& debug_info
817
) {
783✔
818
    return insert_node_internal<For>(parent, INSERT_AT_END, assignments, debug_info, indvar, init, update, condition)
783✔
819
        .first;
783✔
820
}
783✔
821

822
For& StructuredSDFGBuilder::add_for_before(
823
    Sequence& parent,
824
    ControlFlowNode& child,
825
    const symbolic::Symbol indvar,
826
    const symbolic::Condition condition,
827
    const symbolic::Expression init,
828
    const symbolic::Expression update,
829
    const sdfg::control_flow::Assignments& assignments,
830
    const DebugInfo& debug_info
831
) {
40✔
832
    int index = parent.index(child);
40✔
833
    if (index == -1) {
40✔
834
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
835
    }
×
836

837
    return insert_node_internal<For>(parent, index, assignments, debug_info, indvar, init, update, condition).first;
40✔
838
}
40✔
839

840
For& StructuredSDFGBuilder::add_for_after(
841
    Sequence& parent,
842
    ControlFlowNode& child,
843
    const symbolic::Symbol indvar,
844
    const symbolic::Condition condition,
845
    const symbolic::Expression init,
846
    const symbolic::Expression update,
847
    const sdfg::control_flow::Assignments& assignments,
848
    const DebugInfo& debug_info
849
) {
66✔
850
    int index = parent.index(child);
66✔
851
    if (index == -1) {
66✔
852
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
853
    }
×
854

855
    return insert_node_internal<For>(parent, index + 1, assignments, debug_info, indvar, init, update, condition).first;
66✔
856
}
66✔
857

858
Map& StructuredSDFGBuilder::add_map(
859
    Sequence& parent,
860
    const symbolic::Symbol indvar,
861
    const symbolic::Condition condition,
862
    const symbolic::Expression init,
863
    const symbolic::Expression update,
864
    const ScheduleType& schedule_type,
865
    const sdfg::control_flow::Assignments& assignments,
866
    const DebugInfo& debug_info
867
) {
2,213✔
868
    return insert_node_internal<
2,213✔
869
               Map>(parent, INSERT_AT_END, assignments, debug_info, indvar, init, update, condition, schedule_type)
2,213✔
870
        .first;
2,213✔
871
}
2,213✔
872

873
Map& StructuredSDFGBuilder::add_map_before(
874
    Sequence& parent,
875
    ControlFlowNode& child,
876
    const symbolic::Symbol indvar,
877
    const symbolic::Condition condition,
878
    const symbolic::Expression init,
879
    const symbolic::Expression update,
880
    const ScheduleType& schedule_type,
881
    const sdfg::control_flow::Assignments& assignments,
882
    const DebugInfo& debug_info
883
) {
63✔
884
    int index = parent.index(child);
63✔
885
    if (index == -1) {
63✔
886
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
887
    }
×
888

889
    return insert_node_internal<
63✔
890
               Map>(parent, index, assignments, debug_info, indvar, init, update, condition, schedule_type)
63✔
891
        .first;
63✔
892
}
63✔
893

894
Map& StructuredSDFGBuilder::add_map_after(
895
    Sequence& parent,
896
    ControlFlowNode& child,
897
    const symbolic::Symbol indvar,
898
    const symbolic::Condition condition,
899
    const symbolic::Expression init,
900
    const symbolic::Expression update,
901
    const ScheduleType& schedule_type,
902
    const sdfg::control_flow::Assignments& assignments,
903
    const DebugInfo& debug_info
904
) {
85✔
905
    int index = parent.index(child);
85✔
906
    if (index == -1) {
85✔
907
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
908
    }
×
909

910
    return insert_node_internal<
85✔
911
               Map>(parent, index + 1, assignments, debug_info, indvar, init, update, condition, schedule_type)
85✔
912
        .first;
85✔
913
}
85✔
914

915
Continue& StructuredSDFGBuilder::
916
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
27✔
917
    return insert_node_internal<Continue>(parent, INSERT_AT_END, assignments, debug_info).first;
27✔
918
}
27✔
919

920
Break& StructuredSDFGBuilder::
921
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
28✔
922
    return insert_node_internal<Break>(parent, INSERT_AT_END, assignments, debug_info).first;
28✔
923
}
28✔
924

925
Return& StructuredSDFGBuilder::add_return(
926
    Sequence& parent,
927
    const std::string& data,
928
    const sdfg::control_flow::Assignments& assignments,
929
    const DebugInfo& debug_info
930
) {
56✔
931
    return insert_node_internal<Return>(parent, INSERT_AT_END, assignments, debug_info, data).first;
56✔
932
}
56✔
933

934
Return& StructuredSDFGBuilder::add_constant_return(
935
    Sequence& parent,
936
    const std::string& data,
937
    const types::IType& type,
938
    const sdfg::control_flow::Assignments& assignments,
939
    const DebugInfo& debug_info
940
) {
×
941
    return insert_node_internal<Return>(parent, INSERT_AT_END, assignments, debug_info, data, type).first;
×
942
}
×
943

944
For& StructuredSDFGBuilder::convert_while(
945
    Sequence& parent,
946
    While& loop,
947
    const symbolic::Symbol indvar,
948
    const symbolic::Condition condition,
949
    const symbolic::Expression init,
950
    const symbolic::Expression update
951
) {
×
952
    int index = parent.index(loop);
×
953
    if (index == -1) {
×
954
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
955
    }
×
956

957
    auto iter = parent.children_.begin() + index;
×
958
    auto& new_iter = *parent.children_.insert(
×
959
        iter + 1,
×
960
        std::unique_ptr<For>(new For(
×
961
            this->new_element_id_batch(For::REQUIRED_ELEMENT_IDS),
×
962
            loop.debug_info(),
×
963
            &parent,
×
964
            indvar,
×
965
            init,
×
966
            update,
×
967
            condition
×
968
        ))
×
969
    );
×
970

971
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
972
    this->move_children(loop.root(), for_loop.root());
×
973

974
    // Remove while loop
975
    parent.children_.erase(parent.children_.begin() + index);
×
976

977
    return for_loop;
×
978
};
×
979

980
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
77✔
981
    int index = parent.index(loop);
77✔
982
    if (index == -1) {
77✔
983
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
984
    }
×
985

986
    auto iter = parent.children_.begin() + index;
77✔
987
    auto& new_iter = *parent.children_.insert(
77✔
988
        iter + 1,
77✔
989
        std::unique_ptr<Map>(new Map(
77✔
990
            this->new_element_id_batch(Map::REQUIRED_ELEMENT_IDS),
77✔
991
            loop.debug_info(),
77✔
992
            &parent,
77✔
993
            loop.indvar(),
77✔
994
            loop.init(),
77✔
995
            loop.update(),
77✔
996
            loop.condition(),
77✔
997
            ScheduleType_Sequential::create()
77✔
998
        ))
77✔
999
    );
77✔
1000

1001
    auto& map = dynamic_cast<Map&>(*new_iter);
77✔
1002
    this->move_children(loop.root(), map.root());
77✔
1003

1004
    // Remove for loop
1005
    parent.children_.erase(parent.children_.begin() + index);
77✔
1006

1007
    return map;
77✔
1008
};
77✔
1009

1010
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1011
    if (index >= if_else.conditions_.size()) {
×
1012
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1013
    }
×
1014
    if_else.conditions_.at(index) = condition;
×
1015
};
×
1016

1017
void StructuredSDFGBuilder::update_loop(
1018
    StructuredLoop& loop,
1019
    const symbolic::Symbol indvar,
1020
    const symbolic::Condition condition,
1021
    const symbolic::Expression init,
1022
    const symbolic::Expression update
1023
) {
119✔
1024
    loop.indvar_ = indvar;
119✔
1025
    loop.condition_ = condition;
119✔
1026
    loop.init_ = init;
119✔
1027
    loop.update_ = update;
119✔
1028
};
119✔
1029

1030
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
36✔
1031
    map.schedule_type_ = schedule_type;
36✔
1032
}
36✔
1033

1034
/***** Section: Dataflow Graph *****/
1035

1036
data_flow::AccessNode& StructuredSDFGBuilder::
1037
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
7,051✔
1038
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
7,051✔
1039
    auto res = block.dataflow_->nodes_.insert(
7,051✔
1040
        {vertex,
7,051✔
1041
         std::unique_ptr<data_flow::AccessNode>(
7,051✔
1042
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
7,051✔
1043
         )}
7,051✔
1044
    );
7,051✔
1045

1046
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
7,051✔
1047
};
7,051✔
1048

1049
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
1050
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1051
) {
424✔
1052
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
424✔
1053
    auto res = block.dataflow_->nodes_.insert(
424✔
1054
        {vertex,
424✔
1055
         std::unique_ptr<data_flow::ConstantNode>(
424✔
1056
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
424✔
1057
         )}
424✔
1058
    );
424✔
1059

1060
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
424✔
1061
};
424✔
1062

1063

1064
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
1065
    structured_control_flow::Block& block,
1066
    const data_flow::TaskletCode code,
1067
    const std::string& output,
1068
    const std::vector<std::string>& inputs,
1069
    const DebugInfo& debug_info
1070
) {
1,581✔
1071
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
1,581✔
1072
    auto res = block.dataflow_->nodes_.insert(
1,581✔
1073
        {vertex,
1,581✔
1074
         std::unique_ptr<data_flow::Tasklet>(
1,581✔
1075
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
1,581✔
1076
         )}
1,581✔
1077
    );
1,581✔
1078

1079
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
1,581✔
1080
};
1,581✔
1081

1082
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
1083
    structured_control_flow::Block& block,
1084
    data_flow::DataFlowNode& src,
1085
    const std::string& src_conn,
1086
    data_flow::DataFlowNode& dst,
1087
    const std::string& dst_conn,
1088
    const data_flow::Subset& subset,
1089
    const types::IType& base_type,
1090
    const DebugInfo& debug_info
1091
) {
7,751✔
1092
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
7,751✔
1093
    auto res = block.dataflow_->edges_.insert(
7,751✔
1094
        {edge.first,
7,751✔
1095
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
7,751✔
1096
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
7,751✔
1097
         ))}
7,751✔
1098
    );
7,751✔
1099

1100
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
7,751✔
1101
#ifndef NDEBUG
7,751✔
1102
    memlet.validate(*this->structured_sdfg_);
7,751✔
1103
#endif
7,751✔
1104

1105
    return memlet;
7,751✔
1106
};
7,751✔
1107

1108
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1109
    structured_control_flow::Block& block,
1110
    data_flow::AccessNode& src,
1111
    data_flow::CodeNode& dst,
1112
    const std::string& dst_conn,
1113
    const data_flow::Subset& subset,
1114
    const types::IType& base_type,
1115
    const DebugInfo& debug_info
1116
) {
4,122✔
1117
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
4,122✔
1118
};
4,122✔
1119

1120
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1121
    structured_control_flow::Block& block,
1122
    data_flow::CodeNode& src,
1123
    const std::string& src_conn,
1124
    data_flow::AccessNode& dst,
1125
    const data_flow::Subset& subset,
1126
    const types::IType& base_type,
1127
    const DebugInfo& debug_info
1128
) {
1,424✔
1129
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
1,424✔
1130
};
1,424✔
1131

1132
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1133
    structured_control_flow::Block& block,
1134
    data_flow::AccessNode& src,
1135
    data_flow::Tasklet& dst,
1136
    const std::string& dst_conn,
1137
    const data_flow::Subset& subset,
1138
    const DebugInfo& debug_info
1139
) {
1,009✔
1140
    const types::IType* src_type = nullptr;
1,009✔
1141
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
1,009✔
1142
        src_type = &cnode->type();
235✔
1143
    } else {
774✔
1144
        src_type = &this->structured_sdfg_->type(src.data());
774✔
1145
    }
774✔
1146
    auto base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
1,009✔
1147
    if (base_type->type_id() != types::TypeID::Scalar) {
1,009✔
1148
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1149
    }
×
1150
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
1,009✔
1151
};
1,009✔
1152

1153
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1154
    structured_control_flow::Block& block,
1155
    data_flow::Tasklet& src,
1156
    const std::string& src_conn,
1157
    data_flow::AccessNode& dst,
1158
    const data_flow::Subset& subset,
1159
    const DebugInfo& debug_info
1160
) {
626✔
1161
    auto& dst_type = this->structured_sdfg_->type(dst.data());
626✔
1162
    auto base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
626✔
1163
    if (base_type->type_id() != types::TypeID::Scalar) {
626✔
1164
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1165
    }
×
1166
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
626✔
1167
};
626✔
1168

1169
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
1170
    structured_control_flow::Block& block,
1171
    data_flow::AccessNode& src,
1172
    data_flow::AccessNode& dst,
1173
    const data_flow::Subset& subset,
1174
    const types::IType& base_type,
1175
    const DebugInfo& debug_info
1176
) {
120✔
1177
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
120✔
1178
};
120✔
1179

1180
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
1181
    structured_control_flow::Block& block,
1182
    data_flow::AccessNode& src,
1183
    data_flow::AccessNode& dst,
1184
    bool derefs_src,
1185
    const types::IType& base_type,
1186
    const DebugInfo& debug_info
1187
) {
23✔
1188
    if (derefs_src) {
23✔
1189
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
14✔
1190
    } else {
14✔
1191
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
9✔
1192
    }
9✔
1193
};
23✔
1194

1195
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
236✔
1196
    auto& graph = block.dataflow();
236✔
1197
    auto e = edge.edge();
236✔
1198
    boost::remove_edge(e, graph.graph_);
236✔
1199
    graph.edges_.erase(e);
236✔
1200
};
236✔
1201

1202
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
194✔
1203
    auto& graph = block.dataflow();
194✔
1204
    auto v = node.vertex();
194✔
1205
    boost::remove_vertex(v, graph.graph_);
194✔
1206
    graph.nodes_.erase(v);
194✔
1207
};
194✔
1208

1209
void StructuredSDFGBuilder::clear_code_node_legacy(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
602✔
1210
    auto& graph = block.dataflow();
602✔
1211

1212
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
602✔
1213

1214
    // Delete incoming
1215
    std::list<const data_flow::Memlet*> iedges;
602✔
1216
    for (auto& iedge : graph.in_edges(node)) {
1,492✔
1217
        iedges.push_back(&iedge);
1,492✔
1218
    }
1,492✔
1219
    for (auto iedge : iedges) {
1,492✔
1220
        auto& src = iedge->src();
1,492✔
1221
        to_delete.insert(&src);
1,492✔
1222

1223
        auto edge = iedge->edge();
1,492✔
1224
        graph.edges_.erase(edge);
1,492✔
1225
        boost::remove_edge(edge, graph.graph_);
1,492✔
1226
    }
1,492✔
1227

1228
    // Delete outgoing
1229
    std::list<const data_flow::Memlet*> oedges;
602✔
1230
    for (auto& oedge : graph.out_edges(node)) {
602✔
1231
        oedges.push_back(&oedge);
39✔
1232
    }
39✔
1233
    for (auto oedge : oedges) {
602✔
1234
        auto& dst = oedge->dst();
39✔
1235
        to_delete.insert(&dst);
39✔
1236

1237
        auto edge = oedge->edge();
39✔
1238
        graph.edges_.erase(edge);
39✔
1239
        boost::remove_edge(edge, graph.graph_);
39✔
1240
    }
39✔
1241

1242
    // Delete nodes
1243
    for (auto obsolete_node : to_delete) {
2,133✔
1244
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
2,133✔
1245
            auto vertex = obsolete_node->vertex();
2,133✔
1246
            graph.nodes_.erase(vertex);
2,133✔
1247
            boost::remove_vertex(vertex, graph.graph_);
2,133✔
1248
        }
2,133✔
1249
    }
2,133✔
1250
}
602✔
1251

1252
void StructuredSDFGBuilder::
1253
    clear_access_node_legacy(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
3✔
1254
    auto& graph = block.dataflow();
3✔
1255

1256
    std::list<const data_flow::Memlet*> tmp;
3✔
1257
    std::list<const data_flow::DataFlowNode*> queue = {&node};
3✔
1258
    while (!queue.empty()) {
9✔
1259
        auto current = queue.front();
6✔
1260
        queue.pop_front();
6✔
1261
        if (current != &node) {
6✔
1262
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
3✔
1263
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
×
1264
                    continue;
×
1265
                }
×
1266
            }
×
1267
        }
3✔
1268

1269
        tmp.clear();
6✔
1270
        for (auto& iedge : graph.in_edges(*current)) {
6✔
1271
            tmp.push_back(&iedge);
3✔
1272
        }
3✔
1273
        for (auto iedge : tmp) {
6✔
1274
            auto& src = iedge->src();
3✔
1275
            queue.push_back(&src);
3✔
1276

1277
            auto edge = iedge->edge();
3✔
1278
            graph.edges_.erase(edge);
3✔
1279
            boost::remove_edge(edge, graph.graph_);
3✔
1280
        }
3✔
1281

1282
        if (current != &node || graph.out_degree(*current) == 0) {
6✔
1283
            auto vertex = current->vertex();
6✔
1284
            graph.nodes_.erase(vertex);
6✔
1285
            boost::remove_vertex(vertex, graph.graph_);
6✔
1286
        }
6✔
1287
    }
6✔
1288
}
3✔
1289

1290
int StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
13✔
1291
    return clear_node(block, node, {&node});
13✔
1292
}
13✔
1293

1294
int StructuredSDFGBuilder::clear_node(
1295
    structured_control_flow::Block& block,
1296
    const data_flow::DataFlowNode& node,
1297
    const std::unordered_set<const data_flow::DataFlowNode*>& ignore_side_effects
1298
) {
13✔
1299
    auto& graph = block.dataflow();
13✔
1300

1301
    std::list<const data_flow::Memlet*> tmp;
13✔
1302
    std::list<const data_flow::DataFlowNode*> queue = {&node};
13✔
1303
    std::unordered_set<const data_flow::DataFlowNode*> remove_once_set;
13✔
1304
    std::unordered_set<const data_flow::DataFlowNode*> force_remove_set;
13✔
1305
    int removed_nodes = 0;
13✔
1306

1307
    do {
36✔
1308
        auto current = queue.front();
36✔
1309
        queue.pop_front();
36✔
1310

1311
        if (!remove_once_set.contains(current)) {
36✔
1312
            bool no_more_consumers = graph.out_degree(*current) == 0; // cannot remove nodes still in use
35✔
1313

1314
            auto* access_node = dynamic_cast<const data_flow::AccessNode*>(current);
35✔
1315

1316
            bool ignore_side_effects_on_current = ignore_side_effects.contains(current);
35✔
1317
            bool force_remove = force_remove_set.contains(current);
35✔
1318

1319
            // we can remove nodes without out-edges & side effects.
1320
            if ((no_more_consumers && !current->side_effect()) ||
35✔
1321
                ((ignore_side_effects_on_current || force_remove) && (no_more_consumers || access_node))) {
35✔
1322
                // Or for access-nodes on the ignore list, we can remove the write side (will not remove the node, only
1323
                // inputs) For any other node on the ignore list, we can ignore if it has side effects or not
1324
                tmp.clear();
28✔
1325
                for (auto& iedge : graph.in_edges(*current)) {
28✔
1326
                    tmp.push_back(&iedge);
25✔
1327
                }
25✔
1328
                bool no_in_edges = true;
28✔
1329
                for (auto iedge : tmp) {
28✔
1330
                    auto& src = iedge->src();
25✔
1331

1332
                    auto edge_rem = src.can_remove_out_edge(graph, iedge);
25✔
1333
                    if (edge_rem != data_flow::EdgeRemoveOption::NotRemovable) {
25✔
1334
                        auto src_conn = iedge->src_conn();
23✔
1335
                        queue.push_back(&src);
23✔
1336
                        auto edge = iedge->edge();
23✔
1337
                        graph.edges_.erase(edge);
23✔
1338
                        boost::remove_edge(edge, graph.graph_);
23✔
1339
                        if (edge_rem == data_flow::EdgeRemoveOption::RequiresUpdate) {
23✔
1340
                            const_cast<data_flow::DataFlowNode&>(src).update_edge_removed(src_conn);
×
1341
                        } else if (edge_rem == data_flow::EdgeRemoveOption::RemoveNodeAfter) {
23✔
1342
                            force_remove_set.insert(&src);
7✔
1343
                        }
7✔
1344
                    } else {
23✔
1345
                        no_in_edges = false;
2✔
1346
                    }
2✔
1347
                }
25✔
1348

1349
                if (no_more_consumers && no_in_edges) {
28✔
1350
                    remove_once_set.insert(current);
25✔
1351
                    auto vertex = current->vertex();
25✔
1352
                    graph.nodes_.erase(vertex);
25✔
1353
                    boost::remove_vertex(vertex, graph.graph_);
25✔
1354
                    ++removed_nodes;
25✔
1355
                } else if (!no_more_consumers && force_remove) {
25✔
1356
                    throw std::runtime_error(
×
1357
                        "Not yet supported: RemoveNodeAfter with more than 1 edge: #" +
×
1358
                        std::to_string(current->element_id())
×
1359
                    );
×
1360
                }
×
1361
            }
28✔
1362
        }
35✔
1363
    } while (!queue.empty());
36✔
1364

1365
    return removed_nodes;
13✔
1366
}
13✔
1367

1368
int StructuredSDFGBuilder::clear_ptr_borrow_edge(Block& block, const data_flow::Memlet& edge) {
1✔
1369
    auto& graph = block.dataflow();
1✔
1370
    auto& src = edge.src();
1✔
1371
    auto& dst = edge.dst();
1✔
1372

1373
    auto edge_removal = dst.can_remove_in_edge(graph, &edge);
1✔
1374
    int removed = 0;
1✔
1375
    if (edge_removal == data_flow::EdgeRemoveOption::Trivially) {
1✔
1376
        remove_memlet(block, edge);
×
1377
        ++removed;
×
1378
    } else if (edge_removal == data_flow::EdgeRemoveOption::RemoveNodeAfter) {
1✔
1379
        removed = 1 + clear_node(block, dst);
1✔
1380
    } else if (edge_removal == data_flow::EdgeRemoveOption::RequiresUpdate) {
1✔
1381
        remove_memlet(block, edge);
×
1382
        const_cast<data_flow::DataFlowNode&>(dst).update_edge_removed(edge.dst_conn());
×
1383
    } else if (edge_removal == data_flow::EdgeRemoveOption::NotRemovable) {
×
1384
        return 0;
×
1385
    }
×
1386

1387
    return removed;
1✔
1388
}
1✔
1389

1390
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
19✔
1391
    auto& to_dataflow = to.dataflow();
19✔
1392

1393
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
19✔
1394
    for (auto& entry : from.nodes_) {
21✔
1395
        auto vertex = boost::add_vertex(to_dataflow.graph_);
21✔
1396
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
21✔
1397
        node_mapping.insert({entry.first, vertex});
21✔
1398
    }
21✔
1399

1400
    for (auto& entry : from.edges_) {
19✔
1401
        auto src = node_mapping[entry.second->src().vertex()];
14✔
1402
        auto dst = node_mapping[entry.second->dst().vertex()];
14✔
1403

1404
        auto edge = boost::add_edge(src, dst, to_dataflow.graph_);
14✔
1405

1406
        to_dataflow.edges_.insert(
14✔
1407
            {edge.first,
14✔
1408
             entry.second->clone(
14✔
1409
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
14✔
1410
             )}
14✔
1411
        );
14✔
1412
    }
14✔
1413
};
19✔
1414

1415
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
21✔
1416
    auto& user_graph = source_node.get_parent();
21✔
1417
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
21✔
1418
    if (!block) {
21✔
1419
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1420
    }
×
1421

1422
    // Merge access nodes if they access the same container on a code node
1423
    for (auto& oedge : user_graph.out_edges(source_node)) {
21✔
1424
        if (auto* code_node = dynamic_cast<data_flow::CodeNode*>(&oedge.dst())) {
15✔
1425
            std::unordered_set<data_flow::Memlet*> iedges;
8✔
1426
            for (auto& iedge : user_graph.in_edges(*code_node)) {
10✔
1427
                iedges.insert(&iedge);
10✔
1428
            }
10✔
1429
            for (auto* iedge : iedges) {
10✔
1430
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
10✔
1431
                    continue;
×
1432
                }
×
1433
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
10✔
1434
                if (access_node == &source_node || access_node->data() != source_node.data()) {
10✔
1435
                    continue;
9✔
1436
                }
9✔
1437
                this->add_memlet(
1✔
1438
                    *block,
1✔
1439
                    source_node,
1✔
1440
                    iedge->src_conn(),
1✔
1441
                    *code_node,
1✔
1442
                    iedge->dst_conn(),
1✔
1443
                    iedge->subset(),
1✔
1444
                    iedge->base_type(),
1✔
1445
                    iedge->debug_info()
1✔
1446
                );
1✔
1447
                this->remove_memlet(*block, *iedge);
1✔
1448
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
1✔
1449
            }
1✔
1450
        }
8✔
1451
    }
15✔
1452

1453
    // Also merge "output" access nodes if they access the same container on a library node
1454
    for (auto& iedge : user_graph.in_edges(source_node)) {
21✔
1455
        if (auto* libnode = dynamic_cast<data_flow::LibraryNode*>(&iedge.src())) {
7✔
1456
            std::unordered_set<data_flow::Memlet*> oedges;
×
1457
            for (auto& oedge : user_graph.out_edges(*libnode)) {
×
1458
                oedges.insert(&oedge);
×
1459
            }
×
1460
            for (auto* oedge : oedges) {
×
1461
                auto* access_node = static_cast<data_flow::AccessNode*>(&oedge->dst());
×
1462
                if (access_node == &source_node || access_node->data() != source_node.data()) {
×
1463
                    continue;
×
1464
                }
×
1465
                this->add_memlet(
×
1466
                    *block,
×
1467
                    *libnode,
×
1468
                    oedge->src_conn(),
×
1469
                    source_node,
×
1470
                    oedge->dst_conn(),
×
1471
                    oedge->subset(),
×
1472
                    oedge->base_type(),
×
1473
                    oedge->debug_info()
×
1474
                );
×
1475
                this->remove_memlet(*block, *oedge);
×
1476
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
×
1477
            }
×
1478
        }
×
1479
    }
7✔
1480
}
21✔
1481

1482
void StructuredSDFGBuilder::merge_sinks(structured_control_flow::Block& block) {
6✔
1483
    auto& graph = block.dataflow();
6✔
1484

1485
    // Collect sink access nodes (modifying the graph during iteration is not safe)
1486
    std::vector<data_flow::AccessNode*> sink_access_nodes;
6✔
1487
    for (auto node : graph.sinks()) {
9✔
1488
        if (auto* access_node = dynamic_cast<data_flow::AccessNode*>(node)) {
9✔
1489
            sink_access_nodes.push_back(access_node);
9✔
1490
        }
9✔
1491
    }
9✔
1492

1493
    // Merge sink access nodes that refer to the same container
1494
    std::unordered_map<std::string, data_flow::AccessNode*> representatives;
6✔
1495
    for (auto* access_node : sink_access_nodes) {
9✔
1496
        auto it = representatives.find(access_node->data());
9✔
1497
        if (it == representatives.end()) {
9✔
1498
            representatives.insert({access_node->data(), access_node});
8✔
1499
            continue;
8✔
1500
        }
8✔
1501

1502
        auto& rep = *it->second;
1✔
1503

1504
        // Redirect all incoming memlets of this node onto the representative
1505
        std::unordered_set<data_flow::Memlet*> iedges;
1✔
1506
        for (auto& iedge : graph.in_edges(*access_node)) {
1✔
1507
            iedges.insert(&iedge);
1✔
1508
        }
1✔
1509
        for (auto* iedge : iedges) {
1✔
1510
            this->add_memlet(
1✔
1511
                block,
1✔
1512
                iedge->src(),
1✔
1513
                iedge->src_conn(),
1✔
1514
                rep,
1✔
1515
                iedge->dst_conn(),
1✔
1516
                iedge->subset(),
1✔
1517
                iedge->base_type(),
1✔
1518
                iedge->debug_info()
1✔
1519
            );
1✔
1520
            this->remove_memlet(block, *iedge);
1✔
1521
        }
1✔
1522

1523
        rep.set_debug_info(DebugInfo::merge(rep.debug_info(), access_node->debug_info()));
1✔
1524

1525
        // The node is now isolated and can be removed
1526
        this->remove_node(block, *access_node);
1✔
1527
    }
1✔
1528
}
6✔
1529

1530
} // namespace builder
1531
} // 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