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

daisytuner / sdfglib / 21098544716

17 Jan 2026 05:57PM UTC coverage: 64.664% (-0.06%) from 64.728%
21098544716

push

github

web-flow
Merge pull request #459 from daisytuner/isl-tiling

Adds OMPScheduler and PollyScheduler

220 of 375 new or added lines in 13 files covered. (58.67%)

44 existing lines in 2 files now uncovered.

19129 of 29582 relevant lines covered (64.66%)

788.2 hits per line

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

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

3
#include <cstddef>
4

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

12
#define TRAVERSE_CUTOFF 30
200✔
13

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

17
namespace sdfg {
18
namespace builder {
19

20
std::unordered_set<const control_flow::State*> StructuredSDFGBuilder::
21
    determine_loop_nodes(SDFG& sdfg, const control_flow::State& start, const control_flow::State& end) const {
26✔
22
    std::unordered_set<const control_flow::State*> nodes;
26✔
23
    std::unordered_set<const control_flow::State*> visited;
26✔
24
    std::list<const control_flow::State*> queue = {&start};
26✔
25
    while (!queue.empty()) {
112✔
26
        auto curr = queue.front();
86✔
27
        queue.pop_front();
86✔
28
        if (visited.find(curr) != visited.end()) {
86✔
29
            continue;
2✔
30
        }
2✔
31
        visited.insert(curr);
84✔
32

33
        nodes.insert(curr);
84✔
34
        if (curr == &end) {
84✔
35
            continue;
26✔
36
        }
26✔
37

38
        for (auto& iedge : sdfg.in_edges(*curr)) {
60✔
39
            queue.push_back(&iedge.src());
60✔
40
        }
60✔
41
    }
58✔
42

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

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

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

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

83
    while (true) {
42✔
84
        std::unordered_set<const control_flow::State*> frontier;
42✔
85
        for (auto node : nodes) {
170✔
86
            for (auto& edge : sdfg.out_edges(*node)) {
278✔
87
                if (nodes.find(&edge.dst()) == nodes.end()) {
278✔
88
                    frontier.insert(&edge.dst());
80✔
89
                }
80✔
90
            }
278✔
91
        }
170✔
92

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

106
        if (!changed) break;
42✔
107
    }
42✔
108

109
    return nodes;
26✔
110
};
26✔
111

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

121
    auto current = pdom_tree.at(node);
18✔
122
    while (current != nullptr) {
18✔
123
        if (current == pdom) {
6✔
124
            return true;
6✔
125
        }
6✔
126
        current = pdom_tree.at(current);
×
127
    }
×
128

129
    return false;
12✔
130
}
18✔
131

132

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

138
    auto pdom_tree = sdfg.post_dominator_tree();
32✔
139

140
    std::unordered_set<const InterstateEdge*> breaks;
32✔
141
    std::unordered_set<const InterstateEdge*> continues;
32✔
142
    for (auto& edge : sdfg.back_edges()) {
32✔
143
        continues.insert(edge);
26✔
144
    }
26✔
145

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

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

168

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

174
        if (visited.find(current) != visited.end()) {
200✔
175
            throw UnstructuredControlFlowException();
×
176
        }
×
177
        visited.insert(current);
200✔
178

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

190
        if (is_loop_header) {
200✔
191
            // 1. Determine nodes of loop body
192
            std::unordered_set<const InterstateEdge*> loop_edges;
18✔
193
            for (auto& iedge : sdfg.in_edges(*current)) {
44✔
194
                if (continues.find(&iedge) != continues.end()) {
44✔
195
                    loop_edges.insert(&iedge);
26✔
196
                }
26✔
197
            }
44✔
198

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

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

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

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

240
            for (auto& edge : breaks) {
18✔
241
                exit_edges.insert(edge);
2✔
242
            }
2✔
243

244
            // Collect debug information
245
            DebugInfo dbg_info = current->debug_info();
18✔
246
            for (auto& edge : sdfg.in_edges(*current)) {
44✔
247
                dbg_info = DebugInfo::merge(dbg_info, edge.debug_info());
44✔
248
            }
44✔
249
            for (auto node : body) {
68✔
250
                dbg_info = DebugInfo::merge(dbg_info, node->debug_info());
68✔
251
            }
68✔
252
            for (auto edge : exit_edges) {
26✔
253
                dbg_info = DebugInfo::merge(dbg_info, edge->debug_info());
26✔
254
            }
26✔
255

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

261
            std::unordered_set<const control_flow::State*> loop_visited(visited);
18✔
262
            loop_visited.erase(current);
18✔
263

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

269
            current = exit_state;
18✔
270
            continue;
18✔
271
        }
18✔
272

273
        auto out_edges = sdfg.out_edges(*current);
182✔
274
        auto out_degree = sdfg.out_degree(*current);
182✔
275

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

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

294
            break;
34✔
295
        }
34✔
296

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

304
            if (!std::ranges::empty(current->dataflow().nodes()) || !oedge.assignments().empty()) {
90✔
305
                this->add_block(scope, current->dataflow(), oedge.assignments(), current->debug_info());
20✔
306
            }
20✔
307

308
            if (continues.find(&oedge) != continues.end()) {
90✔
309
                if (this->current_traverse_loop_ == nullptr) {
14✔
310
                    throw UnstructuredControlFlowException();
×
311
                }
×
312
                this->add_continue(scope, {}, oedge.debug_info());
14✔
313
                break;
14✔
314
            } else if (breaks.find(&oedge) != breaks.end()) {
76✔
315
                if (this->current_traverse_loop_ == nullptr) {
2✔
316
                    throw UnstructuredControlFlowException();
×
317
                }
×
318
                this->add_break(scope, {}, oedge.debug_info());
2✔
319
                break;
2✔
320
            } else {
74✔
321
                current = &oedge.dst();
74✔
322
            }
74✔
323
            continue;
74✔
324
        }
90✔
325

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

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

338

339
            // If merge is beyond exit, clamp to exit
340
            if (exit != nullptr && merge != nullptr) {
58✔
341
                if (post_dominates(merge, exit, pdom_tree)) {
42✔
342
                    merge = exit;
30✔
343
                }
30✔
344
            }
42✔
345

346
            if (merge != nullptr && visited.find(merge) != visited.end()) {
58✔
347
                merge = exit;
8✔
348
            }
8✔
349

350
            if (merge == nullptr && exit != nullptr) {
58✔
351
                merge = exit;
×
352
            }
×
353

354
            auto& if_else = this->add_if_else(scope, {}, current->debug_info());
58✔
355
            for (auto& out_edge : out_edges) {
114✔
356
                auto& branch = this->add_case(if_else, out_edge.condition(), out_edge.debug_info());
114✔
357
                if (!out_edge.assignments().empty()) {
114✔
358
                    this->add_block(branch, out_edge.assignments(), out_edge.debug_info());
10✔
359
                }
10✔
360
                if (continues.find(&out_edge) != continues.end()) {
114✔
361
                    if (this->current_traverse_loop_ == nullptr) {
14✔
362
                        throw UnstructuredControlFlowException();
2✔
363
                    }
2✔
364
                    this->add_continue(branch, {}, out_edge.debug_info());
12✔
365
                } else if (breaks.find(&out_edge) != breaks.end()) {
100✔
366
                    if (this->current_traverse_loop_ == nullptr) {
22✔
367
                        throw UnstructuredControlFlowException();
×
368
                    }
×
369
                    this->add_break(branch, {}, out_edge.debug_info());
22✔
370
                } else {
78✔
371
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
78✔
372
                    this->structure_region(
78✔
373
                        sdfg, branch, &out_edge.dst(), merge, continues, breaks, pdom_tree, branch_visited
78✔
374
                    );
78✔
375
                }
78✔
376
            }
114✔
377

378
            current = merge;
56✔
379
            continue;
56✔
380
        }
58✔
381
    }
58✔
382
}
128✔
383

384
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
37,184✔
385

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

389
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
390
    : FunctionBuilder(), structured_sdfg_(sdfg.release(), owned(true)) {};
314✔
391

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

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

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

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

409
    for (auto& arg : sdfg.arguments_) {
32✔
410
        this->structured_sdfg_->arguments_.push_back(arg);
4✔
411
    }
4✔
412

413
    for (auto& ext : sdfg.externals_) {
32✔
414
        this->structured_sdfg_->externals_.push_back(ext);
2✔
415
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
2✔
416
    }
2✔
417

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

422
    for (auto& entry : sdfg.metadata_) {
32✔
423
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
4✔
424
    }
4✔
425

426
    this->traverse(sdfg);
32✔
427
};
32✔
428

429
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
6,410✔
430

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

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

440
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
760✔
441
};
760✔
442

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

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

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

456
        if (current->element_id() == element_id) {
140✔
457
            return current;
38✔
458
        }
38✔
459

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

492
    return nullptr;
×
493
};
38✔
494

495
Sequence& StructuredSDFGBuilder::
496
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
56✔
497
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
56✔
498

499
    parent.transitions_
56✔
500
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
56✔
501
        );
56✔
502

503
    return static_cast<Sequence&>(*parent.children_.back().get());
56✔
504
};
56✔
505

506
Sequence& StructuredSDFGBuilder::add_sequence_before(
507
    Sequence& parent,
508
    ControlFlowNode& child,
509
    const sdfg::control_flow::Assignments& assignments,
510
    const DebugInfo& debug_info
511
) {
248✔
512
    int index = parent.index(child);
248✔
513
    if (index == -1) {
248✔
514
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
515
    }
×
516

517
    parent.children_.insert(
248✔
518
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
248✔
519
    );
248✔
520

521
    parent.transitions_.insert(
248✔
522
        parent.transitions_.begin() + index,
248✔
523
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
248✔
524
    );
248✔
525

526
    return static_cast<Sequence&>(*parent.children_.at(index).get());
248✔
527
};
248✔
528

529
Sequence& StructuredSDFGBuilder::add_sequence_after(
530
    Sequence& parent,
531
    ControlFlowNode& child,
532
    const sdfg::control_flow::Assignments& assignments,
533
    const DebugInfo& debug_info
534
) {
×
535
    int index = parent.index(child);
×
536
    if (index == -1) {
×
537
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
538
    }
×
539

540
    parent.children_.insert(
×
541
        parent.children_.begin() + index + 1,
×
542
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
543
    );
×
544

545
    parent.transitions_.insert(
×
546
        parent.transitions_.begin() + index + 1,
×
547
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
548
    );
×
549

550
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
551
};
×
552

553
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
554
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
555
    int index = parent.index(child);
×
556
    if (index == -1) {
×
557
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
558
    }
×
559

560
    parent.children_.insert(
×
561
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
562
    );
×
563

564
    parent.transitions_.insert(
×
565
        parent.transitions_.begin() + index,
×
566
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
567
    );
×
568

569
    auto new_entry = parent.at(index);
×
570
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
571

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

575
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
338✔
576
    parent.children_.erase(parent.children_.begin() + index);
338✔
577
    parent.transitions_.erase(parent.transitions_.begin() + index);
338✔
578
};
338✔
579

580
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
581
    parent.children_.clear();
×
582
    parent.transitions_.clear();
×
583
};
×
584

585
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
68✔
586
    size_t target_index = target.size();
68✔
587
    if (&source == &target) {
68✔
588
        target_index--;
×
589
    }
×
590
    this->move_child(source, source_index, target, target_index);
68✔
591
};
68✔
592

593
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
114✔
594
    auto node_ptr = std::move(source.children_.at(source_index));
114✔
595
    auto trans_ptr = std::move(source.transitions_.at(source_index));
114✔
596
    source.children_.erase(source.children_.begin() + source_index);
114✔
597
    source.transitions_.erase(source.transitions_.begin() + source_index);
114✔
598

599
    trans_ptr->parent_ = &target;
114✔
600
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
114✔
601
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
114✔
602
};
114✔
603

604
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
200✔
605
    this->move_children(source, target, target.size());
200✔
606
};
200✔
607

608
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
200✔
609
    target.children_.insert(
200✔
610
        target.children_.begin() + target_index,
200✔
611
        std::make_move_iterator(source.children_.begin()),
200✔
612
        std::make_move_iterator(source.children_.end())
200✔
613
    );
200✔
614
    target.transitions_.insert(
200✔
615
        target.transitions_.begin() + target_index,
200✔
616
        std::make_move_iterator(source.transitions_.begin()),
200✔
617
        std::make_move_iterator(source.transitions_.end())
200✔
618
    );
200✔
619
    for (auto& trans : target.transitions_) {
312✔
620
        trans->parent_ = &target;
312✔
621
    }
312✔
622
    source.children_.clear();
200✔
623
    source.transitions_.clear();
200✔
624
};
200✔
625

NEW
626
Sequence& StructuredSDFGBuilder::hoist_root() {
×
NEW
627
    auto current_root = std::move(this->structured_sdfg_->root_);
×
628

NEW
629
    this->structured_sdfg_->root_ =
×
NEW
630
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), current_root->debug_info()));
×
631

NEW
632
    this->structured_sdfg_->root_->children_.push_back(std::move(current_root));
×
NEW
633
    this->structured_sdfg_->root_->transitions_.push_back(std::unique_ptr<Transition>(
×
NEW
634
        new Transition(this->new_element_id(), current_root->debug_info(), *this->structured_sdfg_->root_)
×
NEW
635
    ));
×
NEW
636
    return *this->structured_sdfg_->root_;
×
NEW
637
};
×
638

639
Block& StructuredSDFGBuilder::
640
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
2,380✔
641
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
2,380✔
642

643
    parent.transitions_
2,380✔
644
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2,380✔
645
        );
2,380✔
646

647
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
2,380✔
648
    (*new_block.dataflow_).parent_ = &new_block;
2,380✔
649

650
    return new_block;
2,380✔
651
};
2,380✔
652

653
Block& StructuredSDFGBuilder::add_block(
654
    Sequence& parent,
655
    const data_flow::DataFlowGraph& data_flow_graph,
656
    const sdfg::control_flow::Assignments& assignments,
657
    const DebugInfo& debug_info
658
) {
26✔
659
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
26✔
660

661
    parent.transitions_
26✔
662
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
26✔
663
        );
26✔
664

665
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
26✔
666
    (*new_block.dataflow_).parent_ = &new_block;
26✔
667

668
    this->add_dataflow(data_flow_graph, new_block);
26✔
669

670
    return new_block;
26✔
671
};
26✔
672

673
Block& StructuredSDFGBuilder::add_block_before(
674
    Sequence& parent,
675
    ControlFlowNode& child,
676
    const sdfg::control_flow::Assignments& assignments,
677
    const DebugInfo& debug_info
678
) {
116✔
679
    int index = parent.index(child);
116✔
680
    if (index == -1) {
116✔
681
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
682
    }
×
683

684
    parent.children_
116✔
685
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
116✔
686

687
    parent.transitions_.insert(
116✔
688
        parent.transitions_.begin() + index,
116✔
689
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
116✔
690
    );
116✔
691

692
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
116✔
693
    (*new_block.dataflow_).parent_ = &new_block;
116✔
694

695
    return new_block;
116✔
696
};
116✔
697

698
Block& StructuredSDFGBuilder::add_block_before(
699
    Sequence& parent,
700
    ControlFlowNode& child,
701
    data_flow::DataFlowGraph& data_flow_graph,
702
    const sdfg::control_flow::Assignments& assignments,
703
    const DebugInfo& debug_info
704
) {
×
705
    int index = parent.index(child);
×
706
    if (index == -1) {
×
707
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
708
    }
×
709

710
    parent.children_
×
711
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
712

713
    parent.transitions_.insert(
×
714
        parent.transitions_.begin() + index,
×
715
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
716
    );
×
717

718
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
719
    (*new_block.dataflow_).parent_ = &new_block;
×
720
    this->add_dataflow(data_flow_graph, new_block);
×
721

722
    return new_block;
×
723
};
×
724

725
Block& StructuredSDFGBuilder::add_block_after(
726
    Sequence& parent,
727
    ControlFlowNode& child,
728
    const sdfg::control_flow::Assignments& assignments,
729
    const DebugInfo& debug_info
730
) {
44✔
731
    int index = parent.index(child);
44✔
732
    if (index == -1) {
44✔
733
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
734
    }
×
735

736
    parent.children_.insert(
44✔
737
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
44✔
738
    );
44✔
739

740
    parent.transitions_.insert(
44✔
741
        parent.transitions_.begin() + index + 1,
44✔
742
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
44✔
743
    );
44✔
744

745
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
44✔
746
    (*new_block.dataflow_).parent_ = &new_block;
44✔
747

748
    return new_block;
44✔
749
};
44✔
750

751
Block& StructuredSDFGBuilder::add_block_after(
752
    Sequence& parent,
753
    ControlFlowNode& child,
754
    data_flow::DataFlowGraph& data_flow_graph,
755
    const sdfg::control_flow::Assignments& assignments,
756
    const DebugInfo& debug_info
757
) {
×
758
    int index = parent.index(child);
×
759
    if (index == -1) {
×
760
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
761
    }
×
762

763
    parent.children_.insert(
×
764
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
765
    );
×
766

767
    parent.transitions_.insert(
×
768
        parent.transitions_.begin() + index + 1,
×
769
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
770
    );
×
771

772
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
773
    (*new_block.dataflow_).parent_ = &new_block;
×
774
    this->add_dataflow(data_flow_graph, new_block);
×
775

776
    return new_block;
×
777
};
×
778

779
std::pair<Block&, Transition&> StructuredSDFGBuilder::
780
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
781
    int index = parent.index(child);
×
782
    if (index == -1) {
×
783
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
784
    }
×
785

786
    parent.children_
×
787
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
788

789
    parent.transitions_.insert(
×
790
        parent.transitions_.begin() + index,
×
791
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
792
    );
×
793

794
    auto new_entry = parent.at(index);
×
795
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
796
    (*new_block.dataflow_).parent_ = &new_block;
×
797

798
    return {new_block, new_entry.second};
×
799
};
×
800

801
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
802
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
803
) {
×
804
    int index = parent.index(child);
×
805
    if (index == -1) {
×
806
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
807
    }
×
808

809
    parent.children_
×
810
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
811

812
    parent.transitions_.insert(
×
813
        parent.transitions_.begin() + index,
×
814
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
815
    );
×
816

817
    auto new_entry = parent.at(index);
×
818
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
819
    (*new_block.dataflow_).parent_ = &new_block;
×
820

821
    this->add_dataflow(data_flow_graph, new_block);
×
822

823
    return {new_block, new_entry.second};
×
824
};
×
825

826
std::pair<Block&, Transition&> StructuredSDFGBuilder::
827
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
828
    int index = parent.index(child);
×
829
    if (index == -1) {
×
830
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
831
    }
×
832

833
    parent.children_.insert(
×
834
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
835
    );
×
836

837
    parent.transitions_.insert(
×
838
        parent.transitions_.begin() + index + 1,
×
839
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
840
    );
×
841

842
    auto new_entry = parent.at(index + 1);
×
843
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
844
    (*new_block.dataflow_).parent_ = &new_block;
×
845

846
    return {new_block, new_entry.second};
×
847
};
×
848

849
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
850
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
851
) {
×
852
    int index = parent.index(child);
×
853
    if (index == -1) {
×
854
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
855
    }
×
856

857
    parent.children_.insert(
×
858
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
859
    );
×
860

861
    parent.transitions_.insert(
×
862
        parent.transitions_.begin() + index + 1,
×
863
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
864
    );
×
865

866
    auto new_entry = parent.at(index + 1);
×
867
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
868
    (*new_block.dataflow_).parent_ = &new_block;
×
869

870
    this->add_dataflow(data_flow_graph, new_block);
×
871

872
    return {new_block, new_entry.second};
×
873
};
×
874

875
IfElse& StructuredSDFGBuilder::
876
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
182✔
877
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
182✔
878

879
    parent.transitions_
182✔
880
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
182✔
881
        );
182✔
882

883
    return static_cast<IfElse&>(*parent.children_.back().get());
182✔
884
};
182✔
885

886
IfElse& StructuredSDFGBuilder::add_if_else_before(
887
    Sequence& parent,
888
    ControlFlowNode& child,
889
    const sdfg::control_flow::Assignments& assignments,
890
    const DebugInfo& debug_info
891
) {
2✔
892
    int index = parent.index(child);
2✔
893
    if (index == -1) {
2✔
894
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
895
    }
×
896

897
    parent.children_
2✔
898
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
2✔
899

900
    parent.transitions_.insert(
2✔
901
        parent.transitions_.begin() + index,
2✔
902
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2✔
903
    );
2✔
904

905
    return static_cast<IfElse&>(*parent.children_.at(index));
2✔
906
};
2✔
907

908
IfElse& StructuredSDFGBuilder::add_if_else_after(
909
    Sequence& parent,
910
    ControlFlowNode& child,
911
    const sdfg::control_flow::Assignments& assignments,
912
    const DebugInfo& debug_info
913
) {
×
914
    int index = parent.index(child);
×
915
    if (index == -1) {
×
916
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
917
    }
×
918

919
    parent.children_.insert(
×
920
        parent.children_.begin() + index + 1, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info))
×
921
    );
×
922

923
    parent.transitions_.insert(
×
924
        parent.transitions_.begin() + index + 1,
×
925
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
926
    );
×
927

928
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
929
};
×
930

931
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
932
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
933
    int index = parent.index(child);
×
934
    if (index == -1) {
×
935
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
936
    }
×
937

938
    parent.children_
×
939
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
×
940

941
    parent.transitions_.insert(
×
942
        parent.transitions_.begin() + index,
×
943
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
944
    );
×
945

946
    auto new_entry = parent.at(index);
×
947
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
948

949
    return {new_block, new_entry.second};
×
950
};
×
951

952
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
326✔
953
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
326✔
954

955
    scope.conditions_.push_back(cond);
326✔
956
    return *scope.cases_.back();
326✔
957
};
326✔
958

959
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
960
    scope.cases_.erase(scope.cases_.begin() + index);
×
961
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
962
};
×
963

964
While& StructuredSDFGBuilder::
965
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
102✔
966
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
102✔
967

968
    // Increment element id for body node
969
    this->new_element_id();
102✔
970

971
    parent.transitions_
102✔
972
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
102✔
973
        );
102✔
974

975
    return static_cast<While&>(*parent.children_.back().get());
102✔
976
};
102✔
977

978
For& StructuredSDFGBuilder::add_for(
979
    Sequence& parent,
980
    const symbolic::Symbol indvar,
981
    const symbolic::Condition condition,
982
    const symbolic::Expression init,
983
    const symbolic::Expression update,
984
    const sdfg::control_flow::Assignments& assignments,
985
    const DebugInfo& debug_info
986
) {
810✔
987
    parent.children_
810✔
988
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
810✔
989

990
    // Increment element id for body node
991
    this->new_element_id();
810✔
992

993
    parent.transitions_
810✔
994
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
810✔
995
        );
810✔
996

997
    return static_cast<For&>(*parent.children_.back().get());
810✔
998
};
810✔
999

1000
For& StructuredSDFGBuilder::add_for_before(
1001
    Sequence& parent,
1002
    ControlFlowNode& child,
1003
    const symbolic::Symbol indvar,
1004
    const symbolic::Condition condition,
1005
    const symbolic::Expression init,
1006
    const symbolic::Expression update,
1007
    const sdfg::control_flow::Assignments& assignments,
1008
    const DebugInfo& debug_info
1009
) {
14✔
1010
    int index = parent.index(child);
14✔
1011
    if (index == -1) {
14✔
1012
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1013
    }
×
1014

1015
    parent.children_.insert(
14✔
1016
        parent.children_.begin() + index,
14✔
1017
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
14✔
1018
    );
14✔
1019

1020
    // Increment element id for body node
1021
    this->new_element_id();
14✔
1022

1023
    parent.transitions_.insert(
14✔
1024
        parent.transitions_.begin() + index,
14✔
1025
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
1026
    );
14✔
1027

1028
    return static_cast<For&>(*parent.children_.at(index).get());
14✔
1029
};
14✔
1030

1031
For& StructuredSDFGBuilder::add_for_after(
1032
    Sequence& parent,
1033
    ControlFlowNode& child,
1034
    const symbolic::Symbol indvar,
1035
    const symbolic::Condition condition,
1036
    const symbolic::Expression init,
1037
    const symbolic::Expression update,
1038
    const sdfg::control_flow::Assignments& assignments,
1039
    const DebugInfo& debug_info
1040
) {
16✔
1041
    int index = parent.index(child);
16✔
1042
    if (index == -1) {
16✔
1043
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1044
    }
×
1045

1046
    parent.children_.insert(
16✔
1047
        parent.children_.begin() + index + 1,
16✔
1048
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
16✔
1049
    );
16✔
1050

1051
    // Increment element id for body node
1052
    this->new_element_id();
16✔
1053

1054
    parent.transitions_.insert(
16✔
1055
        parent.transitions_.begin() + index + 1,
16✔
1056
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
16✔
1057
    );
16✔
1058

1059
    return static_cast<For&>(*parent.children_.at(index + 1).get());
16✔
1060
};
16✔
1061

1062
Map& StructuredSDFGBuilder::add_map(
1063
    Sequence& parent,
1064
    const symbolic::Symbol indvar,
1065
    const symbolic::Condition condition,
1066
    const symbolic::Expression init,
1067
    const symbolic::Expression update,
1068
    const ScheduleType& schedule_type,
1069
    const sdfg::control_flow::Assignments& assignments,
1070
    const DebugInfo& debug_info
1071
) {
720✔
1072
    parent.children_
720✔
1073
        .push_back(std::unique_ptr<
720✔
1074
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
720✔
1075

1076
    // Increment element id for body node
1077
    this->new_element_id();
720✔
1078

1079
    parent.transitions_
720✔
1080
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
720✔
1081
        );
720✔
1082

1083
    return static_cast<Map&>(*parent.children_.back().get());
720✔
1084
};
720✔
1085

1086
Map& StructuredSDFGBuilder::add_map_before(
1087
    Sequence& parent,
1088
    ControlFlowNode& child,
1089
    const symbolic::Symbol indvar,
1090
    const symbolic::Condition condition,
1091
    const symbolic::Expression init,
1092
    const symbolic::Expression update,
1093
    const ScheduleType& schedule_type,
1094
    const sdfg::control_flow::Assignments& assignments,
1095
    const DebugInfo& debug_info
1096
) {
58✔
1097
    int index = parent.index(child);
58✔
1098
    if (index == -1) {
58✔
1099
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1100
    }
×
1101

1102
    parent.children_.insert(
58✔
1103
        parent.children_.begin() + index,
58✔
1104
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
58✔
1105
        )
58✔
1106
    );
58✔
1107

1108
    // Increment element id for body node
1109
    this->new_element_id();
58✔
1110

1111
    parent.transitions_.insert(
58✔
1112
        parent.transitions_.begin() + index,
58✔
1113
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
58✔
1114
    );
58✔
1115

1116
    return static_cast<Map&>(*parent.children_.at(index).get());
58✔
1117
};
58✔
1118

1119
Map& StructuredSDFGBuilder::add_map_after(
1120
    Sequence& parent,
1121
    ControlFlowNode& child,
1122
    const symbolic::Symbol indvar,
1123
    const symbolic::Condition condition,
1124
    const symbolic::Expression init,
1125
    const symbolic::Expression update,
1126
    const ScheduleType& schedule_type,
1127
    const sdfg::control_flow::Assignments& assignments,
1128
    const DebugInfo& debug_info
1129
) {
40✔
1130
    int index = parent.index(child);
40✔
1131
    if (index == -1) {
40✔
1132
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1133
    }
×
1134

1135
    parent.children_.insert(
40✔
1136
        parent.children_.begin() + index + 1,
40✔
1137
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
40✔
1138
        )
40✔
1139
    );
40✔
1140

1141
    // Increment element id for body node
1142
    this->new_element_id();
40✔
1143

1144
    parent.transitions_.insert(
40✔
1145
        parent.transitions_.begin() + index + 1,
40✔
1146
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
40✔
1147
    );
40✔
1148

1149
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
40✔
1150
};
40✔
1151

1152
Continue& StructuredSDFGBuilder::
1153
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
54✔
1154
    parent.children_.push_back(std::unique_ptr<Continue>(new Continue(this->new_element_id(), debug_info)));
54✔
1155

1156
    parent.transitions_
54✔
1157
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
54✔
1158
        );
54✔
1159

1160
    return static_cast<Continue&>(*parent.children_.back().get());
54✔
1161
};
54✔
1162

1163
Break& StructuredSDFGBuilder::
1164
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
56✔
1165
    parent.children_.push_back(std::unique_ptr<Break>(new Break(this->new_element_id(), debug_info)));
56✔
1166

1167
    parent.transitions_
56✔
1168
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
56✔
1169
        );
56✔
1170

1171
    return static_cast<Break&>(*parent.children_.back().get());
56✔
1172
};
56✔
1173

1174
Return& StructuredSDFGBuilder::add_return(
1175
    Sequence& parent,
1176
    const std::string& data,
1177
    const sdfg::control_flow::Assignments& assignments,
1178
    const DebugInfo& debug_info
1179
) {
88✔
1180
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
88✔
1181

1182
    parent.transitions_
88✔
1183
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
88✔
1184
        );
88✔
1185

1186
    return static_cast<Return&>(*parent.children_.back().get());
88✔
1187
};
88✔
1188

1189
Return& StructuredSDFGBuilder::add_constant_return(
1190
    Sequence& parent,
1191
    const std::string& data,
1192
    const types::IType& type,
1193
    const sdfg::control_flow::Assignments& assignments,
1194
    const DebugInfo& debug_info
1195
) {
×
1196
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1197

1198
    parent.transitions_
×
1199
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1200
        );
×
1201

1202
    return static_cast<Return&>(*parent.children_.back().get());
×
1203
};
×
1204

1205
For& StructuredSDFGBuilder::convert_while(
1206
    Sequence& parent,
1207
    While& loop,
1208
    const symbolic::Symbol indvar,
1209
    const symbolic::Condition condition,
1210
    const symbolic::Expression init,
1211
    const symbolic::Expression update
1212
) {
×
1213
    int index = parent.index(loop);
×
1214
    if (index == -1) {
×
1215
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1216
    }
×
1217

1218
    auto iter = parent.children_.begin() + index;
×
1219
    auto& new_iter = *parent.children_.insert(
×
1220
        iter + 1,
×
1221
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1222
    );
×
1223

1224
    // Increment element id for body node
1225
    this->new_element_id();
×
1226

1227
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1228
    this->move_children(loop.root(), for_loop.root());
×
1229

1230
    // Remove while loop
1231
    parent.children_.erase(parent.children_.begin() + index);
×
1232

1233
    return for_loop;
×
1234
};
×
1235

1236
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
142✔
1237
    int index = parent.index(loop);
142✔
1238
    if (index == -1) {
142✔
1239
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1240
    }
×
1241

1242
    auto iter = parent.children_.begin() + index;
142✔
1243
    auto& new_iter = *parent.children_.insert(
142✔
1244
        iter + 1,
142✔
1245
        std::unique_ptr<Map>(new Map(
142✔
1246
            this->new_element_id(),
142✔
1247
            loop.debug_info(),
142✔
1248
            loop.indvar(),
142✔
1249
            loop.init(),
142✔
1250
            loop.update(),
142✔
1251
            loop.condition(),
142✔
1252
            ScheduleType_Sequential::create()
142✔
1253
        ))
142✔
1254
    );
142✔
1255

1256
    // Increment element id for body node
1257
    this->new_element_id();
142✔
1258

1259
    auto& map = dynamic_cast<Map&>(*new_iter);
142✔
1260
    this->move_children(loop.root(), map.root());
142✔
1261

1262
    // Remove for loop
1263
    parent.children_.erase(parent.children_.begin() + index);
142✔
1264

1265
    return map;
142✔
1266
};
142✔
1267

1268
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1269
    if (index >= if_else.conditions_.size()) {
×
1270
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1271
    }
×
1272
    if_else.conditions_.at(index) = condition;
×
1273
};
×
1274

1275
void StructuredSDFGBuilder::update_loop(
1276
    StructuredLoop& loop,
1277
    const symbolic::Symbol indvar,
1278
    const symbolic::Condition condition,
1279
    const symbolic::Expression init,
1280
    const symbolic::Expression update
1281
) {
50✔
1282
    loop.indvar_ = indvar;
50✔
1283
    loop.condition_ = condition;
50✔
1284
    loop.init_ = init;
50✔
1285
    loop.update_ = update;
50✔
1286
};
50✔
1287

1288
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
18✔
1289
    map.schedule_type_ = schedule_type;
18✔
1290
}
18✔
1291

1292
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
×
1293
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
×
1294
    while (!queue.empty()) {
×
1295
        auto current = queue.front();
×
1296
        queue.pop_front();
×
1297

1298
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
×
1299
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
×
1300
                if (&sequence_stmt->at(i).first == &node) {
×
1301
                    return *sequence_stmt;
×
1302
                }
×
1303
                queue.push_back(&sequence_stmt->at(i).first);
×
1304
            }
×
1305
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1306
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1307
                queue.push_back(&if_else_stmt->at(i).first);
×
1308
            }
×
1309
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1310
            queue.push_back(&while_stmt->root());
×
1311
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1312
            queue.push_back(&loop_stmt->root());
×
1313
        }
×
1314
    }
×
1315

1316
    return this->structured_sdfg_->root();
×
1317
};
×
1318

1319
/***** Section: Dataflow Graph *****/
1320

1321
data_flow::AccessNode& StructuredSDFGBuilder::
1322
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
4,550✔
1323
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
4,550✔
1324
    auto res = block.dataflow_->nodes_.insert(
4,550✔
1325
        {vertex,
4,550✔
1326
         std::unique_ptr<data_flow::AccessNode>(
4,550✔
1327
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
4,550✔
1328
         )}
4,550✔
1329
    );
4,550✔
1330

1331
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
4,550✔
1332
};
4,550✔
1333

1334
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
1335
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1336
) {
326✔
1337
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
326✔
1338
    auto res = block.dataflow_->nodes_.insert(
326✔
1339
        {vertex,
326✔
1340
         std::unique_ptr<data_flow::ConstantNode>(
326✔
1341
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
326✔
1342
         )}
326✔
1343
    );
326✔
1344

1345
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
326✔
1346
};
326✔
1347

1348

1349
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
1350
    structured_control_flow::Block& block,
1351
    const data_flow::TaskletCode code,
1352
    const std::string& output,
1353
    const std::vector<std::string>& inputs,
1354
    const DebugInfo& debug_info
1355
) {
1,424✔
1356
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
1,424✔
1357
    auto res = block.dataflow_->nodes_.insert(
1,424✔
1358
        {vertex,
1,424✔
1359
         std::unique_ptr<data_flow::Tasklet>(
1,424✔
1360
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
1,424✔
1361
         )}
1,424✔
1362
    );
1,424✔
1363

1364
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
1,424✔
1365
};
1,424✔
1366

1367
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
1368
    structured_control_flow::Block& block,
1369
    data_flow::DataFlowNode& src,
1370
    const std::string& src_conn,
1371
    data_flow::DataFlowNode& dst,
1372
    const std::string& dst_conn,
1373
    const data_flow::Subset& subset,
1374
    const types::IType& base_type,
1375
    const DebugInfo& debug_info
1376
) {
5,150✔
1377
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
5,150✔
1378
    auto res = block.dataflow_->edges_.insert(
5,150✔
1379
        {edge.first,
5,150✔
1380
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
5,150✔
1381
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
5,150✔
1382
         ))}
5,150✔
1383
    );
5,150✔
1384

1385
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
5,150✔
1386
#ifndef NDEBUG
5,150✔
1387
    memlet.validate(*this->structured_sdfg_);
5,150✔
1388
#endif
5,150✔
1389

1390
    return memlet;
5,150✔
1391
};
5,150✔
1392

1393
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1394
    structured_control_flow::Block& block,
1395
    data_flow::AccessNode& src,
1396
    data_flow::Tasklet& dst,
1397
    const std::string& dst_conn,
1398
    const data_flow::Subset& subset,
1399
    const types::IType& base_type,
1400
    const DebugInfo& debug_info
1401
) {
704✔
1402
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
704✔
1403
};
704✔
1404

1405
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1406
    structured_control_flow::Block& block,
1407
    data_flow::Tasklet& src,
1408
    const std::string& src_conn,
1409
    data_flow::AccessNode& dst,
1410
    const data_flow::Subset& subset,
1411
    const types::IType& base_type,
1412
    const DebugInfo& debug_info
1413
) {
580✔
1414
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
580✔
1415
};
580✔
1416

1417
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1418
    structured_control_flow::Block& block,
1419
    data_flow::AccessNode& src,
1420
    data_flow::Tasklet& dst,
1421
    const std::string& dst_conn,
1422
    const data_flow::Subset& subset,
1423
    const DebugInfo& debug_info
1424
) {
1,224✔
1425
    const types::IType* src_type = nullptr;
1,224✔
1426
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
1,224✔
1427
        src_type = &cnode->type();
222✔
1428
    } else {
1,002✔
1429
        src_type = &this->structured_sdfg_->type(src.data());
1,002✔
1430
    }
1,002✔
1431
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
1,224✔
1432
    if (base_type.type_id() != types::TypeID::Scalar) {
1,224✔
1433
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1434
    }
×
1435
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
1,224✔
1436
};
1,224✔
1437

1438
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1439
    structured_control_flow::Block& block,
1440
    data_flow::Tasklet& src,
1441
    const std::string& src_conn,
1442
    data_flow::AccessNode& dst,
1443
    const data_flow::Subset& subset,
1444
    const DebugInfo& debug_info
1445
) {
710✔
1446
    auto& dst_type = this->structured_sdfg_->type(dst.data());
710✔
1447
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
710✔
1448
    if (base_type.type_id() != types::TypeID::Scalar) {
710✔
1449
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1450
    }
×
1451
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
710✔
1452
};
710✔
1453

1454
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1455
    structured_control_flow::Block& block,
1456
    data_flow::AccessNode& src,
1457
    data_flow::LibraryNode& dst,
1458
    const std::string& dst_conn,
1459
    const data_flow::Subset& subset,
1460
    const types::IType& base_type,
1461
    const DebugInfo& debug_info
1462
) {
796✔
1463
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
796✔
1464
};
796✔
1465

1466
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
1467
    structured_control_flow::Block& block,
1468
    data_flow::LibraryNode& src,
1469
    const std::string& src_conn,
1470
    data_flow::AccessNode& dst,
1471
    const data_flow::Subset& subset,
1472
    const types::IType& base_type,
1473
    const DebugInfo& debug_info
1474
) {
612✔
1475
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
612✔
1476
};
612✔
1477

1478
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
1479
    structured_control_flow::Block& block,
1480
    data_flow::AccessNode& src,
1481
    data_flow::AccessNode& dst,
1482
    const data_flow::Subset& subset,
1483
    const types::IType& base_type,
1484
    const DebugInfo& debug_info
1485
) {
94✔
1486
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
94✔
1487
};
94✔
1488

1489
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
1490
    structured_control_flow::Block& block,
1491
    data_flow::AccessNode& src,
1492
    data_flow::AccessNode& dst,
1493
    bool derefs_src,
1494
    const types::IType& base_type,
1495
    const DebugInfo& debug_info
1496
) {
40✔
1497
    if (derefs_src) {
40✔
1498
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
26✔
1499
    } else {
26✔
1500
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
14✔
1501
    }
14✔
1502
};
40✔
1503

1504
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
596✔
1505
    auto& graph = block.dataflow();
596✔
1506
    auto e = edge.edge();
596✔
1507
    boost::remove_edge(e, graph.graph_);
596✔
1508
    graph.edges_.erase(e);
596✔
1509
};
596✔
1510

1511
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
824✔
1512
    auto& graph = block.dataflow();
824✔
1513
    auto v = node.vertex();
824✔
1514
    boost::remove_vertex(v, graph.graph_);
824✔
1515
    graph.nodes_.erase(v);
824✔
1516
};
824✔
1517

1518
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
58✔
1519
    auto& graph = block.dataflow();
58✔
1520

1521
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
58✔
1522

1523
    // Delete incoming
1524
    std::list<const data_flow::Memlet*> iedges;
58✔
1525
    for (auto& iedge : graph.in_edges(node)) {
100✔
1526
        iedges.push_back(&iedge);
100✔
1527
    }
100✔
1528
    for (auto iedge : iedges) {
100✔
1529
        auto& src = iedge->src();
100✔
1530
        to_delete.insert(&src);
100✔
1531

1532
        auto edge = iedge->edge();
100✔
1533
        graph.edges_.erase(edge);
100✔
1534
        boost::remove_edge(edge, graph.graph_);
100✔
1535
    }
100✔
1536

1537
    // Delete outgoing
1538
    std::list<const data_flow::Memlet*> oedges;
58✔
1539
    for (auto& oedge : graph.out_edges(node)) {
58✔
1540
        oedges.push_back(&oedge);
58✔
1541
    }
58✔
1542
    for (auto oedge : oedges) {
58✔
1543
        auto& dst = oedge->dst();
58✔
1544
        to_delete.insert(&dst);
58✔
1545

1546
        auto edge = oedge->edge();
58✔
1547
        graph.edges_.erase(edge);
58✔
1548
        boost::remove_edge(edge, graph.graph_);
58✔
1549
    }
58✔
1550

1551
    // Delete nodes
1552
    for (auto obsolete_node : to_delete) {
216✔
1553
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
216✔
1554
            auto vertex = obsolete_node->vertex();
216✔
1555
            graph.nodes_.erase(vertex);
216✔
1556
            boost::remove_vertex(vertex, graph.graph_);
216✔
1557
        }
216✔
1558
    }
216✔
1559
};
58✔
1560

1561
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
18✔
1562
    auto& graph = block.dataflow();
18✔
1563

1564
    std::list<const data_flow::Memlet*> tmp;
18✔
1565
    std::list<const data_flow::DataFlowNode*> queue = {&node};
18✔
1566
    while (!queue.empty()) {
66✔
1567
        auto current = queue.front();
48✔
1568
        queue.pop_front();
48✔
1569
        if (current != &node) {
48✔
1570
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
30✔
1571
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
12✔
1572
                    continue;
×
1573
                }
×
1574
            }
12✔
1575
        }
30✔
1576

1577
        tmp.clear();
48✔
1578
        for (auto& iedge : graph.in_edges(*current)) {
48✔
1579
            tmp.push_back(&iedge);
30✔
1580
        }
30✔
1581
        for (auto iedge : tmp) {
48✔
1582
            auto& src = iedge->src();
30✔
1583
            queue.push_back(&src);
30✔
1584

1585
            auto edge = iedge->edge();
30✔
1586
            graph.edges_.erase(edge);
30✔
1587
            boost::remove_edge(edge, graph.graph_);
30✔
1588
        }
30✔
1589

1590
        if (current != &node || graph.out_degree(*current) == 0) {
48✔
1591
            auto vertex = current->vertex();
46✔
1592
            graph.nodes_.erase(vertex);
46✔
1593
            boost::remove_vertex(vertex, graph.graph_);
46✔
1594
        }
46✔
1595
    }
48✔
1596
};
18✔
1597

1598
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
26✔
1599
    auto& to_dataflow = to.dataflow();
26✔
1600

1601
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
26✔
1602
    for (auto& entry : from.nodes_) {
26✔
1603
        auto vertex = boost::add_vertex(to_dataflow.graph_);
2✔
1604
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
2✔
1605
        node_mapping.insert({entry.first, vertex});
2✔
1606
    }
2✔
1607

1608
    for (auto& entry : from.edges_) {
26✔
1609
        auto src = node_mapping[entry.second->src().vertex()];
×
1610
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1611

1612
        auto edge = boost::add_edge(src, dst, to_dataflow.graph_);
×
1613

1614
        to_dataflow.edges_.insert(
×
1615
            {edge.first,
×
1616
             entry.second->clone(
×
1617
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1618
             )}
×
1619
        );
×
1620
    }
×
1621
};
26✔
1622

1623
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
40✔
1624
    auto& user_graph = source_node.get_parent();
40✔
1625
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
40✔
1626
    if (!block) {
40✔
1627
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1628
    }
×
1629

1630
    // Merge access nodes if they access the same container on a tasklet
1631
    for (auto& oedge : user_graph.out_edges(source_node)) {
40✔
1632
        if (auto* tasklet = dynamic_cast<data_flow::Tasklet*>(&oedge.dst())) {
28✔
1633
            std::unordered_set<data_flow::Memlet*> iedges;
14✔
1634
            for (auto& iedge : user_graph.in_edges(*tasklet)) {
18✔
1635
                iedges.insert(&iedge);
18✔
1636
            }
18✔
1637
            for (auto* iedge : iedges) {
18✔
1638
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
18✔
1639
                    continue;
×
1640
                }
×
1641
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
18✔
1642
                if (access_node == &source_node || access_node->data() != source_node.data()) {
18✔
1643
                    continue;
16✔
1644
                }
16✔
1645
                this->add_memlet(
2✔
1646
                    *block,
2✔
1647
                    source_node,
2✔
1648
                    iedge->src_conn(),
2✔
1649
                    *tasklet,
2✔
1650
                    iedge->dst_conn(),
2✔
1651
                    iedge->subset(),
2✔
1652
                    iedge->base_type(),
2✔
1653
                    iedge->debug_info()
2✔
1654
                );
2✔
1655
                this->remove_memlet(*block, *iedge);
2✔
1656
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
2✔
1657
            }
2✔
1658
        }
14✔
1659
    }
28✔
1660
}
40✔
1661

1662
} // namespace builder
1663
} // 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