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

daisytuner / sdfglib / 20192137438

13 Dec 2025 12:37PM UTC coverage: 40.251% (+0.07%) from 40.179%
20192137438

Pull #391

github

web-flow
Merge 216088a35 into 5583a0335
Pull Request #391: Improvements for unstructured control flow conversion

13648 of 43878 branches covered (31.1%)

Branch coverage included in aggregate %.

129 of 182 new or added lines in 2 files covered. (70.88%)

1 existing line in 1 file now uncovered.

11664 of 19008 relevant lines covered (61.36%)

94.79 hits per line

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

48.44
/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
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 {
13✔
22
    std::unordered_set<const control_flow::State*> nodes;
13✔
23
    std::unordered_set<const control_flow::State*> visited;
13✔
24
    std::list<const control_flow::State*> queue = {&start};
13!
25
    while (!queue.empty()) {
56✔
26
        auto curr = queue.front();
43✔
27
        queue.pop_front();
43✔
28
        if (visited.find(curr) != visited.end()) {
43!
29
            continue;
1✔
30
        }
31
        visited.insert(curr);
42!
32

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

38
        for (auto& iedge : sdfg.in_edges(*curr)) {
59!
39
            queue.push_back(&iedge.src());
30!
40
        }
41
    }
42

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

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

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

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

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

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

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

109
    return nodes;
13✔
110
};
13!
111

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

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

129
    return false;
6✔
130
}
21✔
131

132

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

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

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

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

151
void StructuredSDFGBuilder::structure_region(
64✔
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
) {
162
    const State* current = entry;
64✔
163
    while (current != exit) {
137✔
164
        if (current == nullptr) {
100!
NEW
165
            break;
×
166
        }
167

168

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

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

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

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

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

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

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

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

240
            for (auto& edge : breaks) {
10✔
241
                exit_edges.insert(edge);
1!
242
            }
243

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

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

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

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

269
            current = exit_state;
9✔
270
            continue;
271
        }
10✔
272

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

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

282
            auto return_state = dynamic_cast<const control_flow::ReturnState*>(current);
17!
283
            assert(return_state != nullptr);
17!
284
            if (return_state->is_data()) {
17!
285
                this->add_return(scope, return_state->data(), {}, return_state->debug_info());
17!
286
            } else if (return_state->is_constant()) {
17!
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;
17✔
295
        }
296

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

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

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

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

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

338

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

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

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

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

378
            current = merge;
27✔
379
            continue;
27✔
380
        }
381
    }
382
}
63✔
383

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

440
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
290✔
441
};
×
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 {
13✔
450
    auto& sdfg = this->subject();
13✔
451
    std::list<Element*> queue = {&sdfg.root()};
13!
452
    while (!queue.empty()) {
55!
453
        auto current = queue.front();
55✔
454
        queue.pop_front();
55✔
455

456
        if (current->element_id() == element_id) {
55!
457
            return current;
13✔
458
        }
459

460
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
42!
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)) {
42!
469
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
44!
470
                queue.push_back(&sequence_stmt->at(i).first);
22!
471
                queue.push_back(&sequence_stmt->at(i).second);
22!
472
            }
22✔
473
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
42!
474
            // Do nothing
475
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
20!
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)) {
20!
480
            queue.push_back(&for_stmt->root());
×
481
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
20!
482
            queue.push_back(&while_stmt->root());
×
483
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
20!
484
            // Do nothing
485
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
20!
486
            // Do nothing
487
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
20!
488
            queue.push_back(&map_stmt->root());
10!
489
        }
10✔
490
    }
491

492
    return nullptr;
×
493
};
13✔
494

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

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

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

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

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

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

526
    return static_cast<Sequence&>(*parent.children_.at(index).get());
5✔
527
};
×
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) {
31✔
576
    parent.children_.erase(parent.children_.begin() + index);
31✔
577
    parent.transitions_.erase(parent.transitions_.begin() + index);
31✔
578
};
31✔
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) {
10✔
586
    this->move_child(source, source_index, target, target.size());
10✔
587
};
10✔
588

589
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
33✔
590
    auto node_ptr = std::move(source.children_.at(source_index));
33✔
591
    auto trans_ptr = std::move(source.transitions_.at(source_index));
33!
592
    source.children_.erase(source.children_.begin() + source_index);
33!
593
    source.transitions_.erase(source.transitions_.begin() + source_index);
33!
594

595
    trans_ptr->parent_ = &target;
33✔
596
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
33!
597
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
33!
598
};
33✔
599

600
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
24✔
601
    this->move_children(source, target, target.size());
24✔
602
};
24✔
603

604
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
24✔
605
    target.children_.insert(
48✔
606
        target.children_.begin() + target_index,
24✔
607
        std::make_move_iterator(source.children_.begin()),
24✔
608
        std::make_move_iterator(source.children_.end())
24✔
609
    );
610
    target.transitions_.insert(
48✔
611
        target.transitions_.begin() + target_index,
24✔
612
        std::make_move_iterator(source.transitions_.begin()),
24✔
613
        std::make_move_iterator(source.transitions_.end())
24✔
614
    );
615
    for (auto& trans : target.transitions_) {
55✔
616
        trans->parent_ = &target;
31✔
617
    }
618
    source.children_.clear();
24✔
619
    source.transitions_.clear();
24✔
620
};
24✔
621

622
Block& StructuredSDFGBuilder::
623
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
555✔
624
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
555!
625

626
    parent.transitions_
1,110✔
627
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
555!
628
        );
629

630
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
555✔
631
    (*new_block.dataflow_).parent_ = &new_block;
555✔
632

633
    return new_block;
555✔
634
};
×
635

636
Block& StructuredSDFGBuilder::add_block(
13✔
637
    Sequence& parent,
638
    const data_flow::DataFlowGraph& data_flow_graph,
639
    const sdfg::control_flow::Assignments& assignments,
640
    const DebugInfo& debug_info
641
) {
642
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
13!
643

644
    parent.transitions_
26✔
645
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
13!
646
        );
647

648
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
13✔
649
    (*new_block.dataflow_).parent_ = &new_block;
13✔
650

651
    this->add_dataflow(data_flow_graph, new_block);
13✔
652

653
    return new_block;
13✔
654
};
×
655

656
Block& StructuredSDFGBuilder::add_block_before(
14✔
657
    Sequence& parent,
658
    ControlFlowNode& child,
659
    const sdfg::control_flow::Assignments& assignments,
660
    const DebugInfo& debug_info
661
) {
662
    int index = parent.index(child);
14✔
663
    if (index == -1) {
14!
664
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
665
    }
666

667
    parent.children_
28✔
668
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
14!
669

670
    parent.transitions_.insert(
28!
671
        parent.transitions_.begin() + index,
14✔
672
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14!
673
    );
674

675
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
14✔
676
    (*new_block.dataflow_).parent_ = &new_block;
14✔
677

678
    return new_block;
14✔
679
};
×
680

681
Block& StructuredSDFGBuilder::add_block_before(
×
682
    Sequence& parent,
683
    ControlFlowNode& child,
684
    data_flow::DataFlowGraph& data_flow_graph,
685
    const sdfg::control_flow::Assignments& assignments,
686
    const DebugInfo& debug_info
687
) {
688
    int index = parent.index(child);
×
689
    if (index == -1) {
×
690
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
691
    }
692

693
    parent.children_
×
694
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
695

696
    parent.transitions_.insert(
×
697
        parent.transitions_.begin() + index,
×
698
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
699
    );
700

701
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
702
    (*new_block.dataflow_).parent_ = &new_block;
×
703
    this->add_dataflow(data_flow_graph, new_block);
×
704

705
    return new_block;
×
706
};
×
707

708
Block& StructuredSDFGBuilder::add_block_after(
3✔
709
    Sequence& parent,
710
    ControlFlowNode& child,
711
    const sdfg::control_flow::Assignments& assignments,
712
    const DebugInfo& debug_info
713
) {
714
    int index = parent.index(child);
3✔
715
    if (index == -1) {
3!
716
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
717
    }
718

719
    parent.children_.insert(
6!
720
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3!
721
    );
722

723
    parent.transitions_.insert(
6!
724
        parent.transitions_.begin() + index + 1,
3✔
725
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3!
726
    );
727

728
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
3✔
729
    (*new_block.dataflow_).parent_ = &new_block;
3✔
730

731
    return new_block;
3✔
732
};
×
733

734
Block& StructuredSDFGBuilder::add_block_after(
×
735
    Sequence& parent,
736
    ControlFlowNode& child,
737
    data_flow::DataFlowGraph& data_flow_graph,
738
    const sdfg::control_flow::Assignments& assignments,
739
    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
    parent.children_.insert(
×
747
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
748
    );
749

750
    parent.transitions_.insert(
×
751
        parent.transitions_.begin() + index + 1,
×
752
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
753
    );
754

755
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
756
    (*new_block.dataflow_).parent_ = &new_block;
×
757
    this->add_dataflow(data_flow_graph, new_block);
×
758

759
    return new_block;
×
760
};
×
761

762
std::pair<Block&, Transition&> StructuredSDFGBuilder::
763
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
764
    int index = parent.index(child);
×
765
    if (index == -1) {
×
766
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
767
    }
768

769
    parent.children_
×
770
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
771

772
    parent.transitions_.insert(
×
773
        parent.transitions_.begin() + index,
×
774
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
775
    );
776

777
    auto new_entry = parent.at(index);
×
778
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
779
    (*new_block.dataflow_).parent_ = &new_block;
×
780

781
    return {new_block, new_entry.second};
×
782
};
×
783

784
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_before(
×
785
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
786
) {
787
    int index = parent.index(child);
×
788
    if (index == -1) {
×
789
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
790
    }
791

792
    parent.children_
×
793
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
794

795
    parent.transitions_.insert(
×
796
        parent.transitions_.begin() + index,
×
797
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
798
    );
799

800
    auto new_entry = parent.at(index);
×
801
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
802
    (*new_block.dataflow_).parent_ = &new_block;
×
803

804
    this->add_dataflow(data_flow_graph, new_block);
×
805

806
    return {new_block, new_entry.second};
×
807
};
×
808

809
std::pair<Block&, Transition&> StructuredSDFGBuilder::
810
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
811
    int index = parent.index(child);
×
812
    if (index == -1) {
×
813
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
814
    }
815

816
    parent.children_.insert(
×
817
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
818
    );
819

820
    parent.transitions_.insert(
×
821
        parent.transitions_.begin() + index + 1,
×
822
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
823
    );
824

825
    auto new_entry = parent.at(index + 1);
×
826
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
827
    (*new_block.dataflow_).parent_ = &new_block;
×
828

829
    return {new_block, new_entry.second};
×
830
};
×
831

832
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
833
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
834
) {
835
    int index = parent.index(child);
×
836
    if (index == -1) {
×
837
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
838
    }
839

840
    parent.children_.insert(
×
841
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
842
    );
843

844
    parent.transitions_.insert(
×
845
        parent.transitions_.begin() + index + 1,
×
846
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
847
    );
848

849
    auto new_entry = parent.at(index + 1);
×
850
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
851
    (*new_block.dataflow_).parent_ = &new_block;
×
852

853
    this->add_dataflow(data_flow_graph, new_block);
×
854

855
    return {new_block, new_entry.second};
×
856
};
×
857

858
IfElse& StructuredSDFGBuilder::
859
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
75✔
860
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
75!
861

862
    parent.transitions_
150✔
863
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
75!
864
        );
865

866
    return static_cast<IfElse&>(*parent.children_.back().get());
75✔
867
};
×
868

869
IfElse& StructuredSDFGBuilder::add_if_else_before(
1✔
870
    Sequence& parent,
871
    ControlFlowNode& child,
872
    const sdfg::control_flow::Assignments& assignments,
873
    const DebugInfo& debug_info
874
) {
875
    int index = parent.index(child);
1✔
876
    if (index == -1) {
1!
877
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
878
    }
879

880
    parent.children_
2✔
881
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
1!
882

883
    parent.transitions_.insert(
2!
884
        parent.transitions_.begin() + index,
1✔
885
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
1!
886
    );
887

888
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
889
};
×
890

891
IfElse& StructuredSDFGBuilder::add_if_else_after(
×
892
    Sequence& parent,
893
    ControlFlowNode& child,
894
    const sdfg::control_flow::Assignments& assignments,
895
    const DebugInfo& debug_info
896
) {
897
    int index = parent.index(child);
×
898
    if (index == -1) {
×
899
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
900
    }
901

902
    parent.children_.insert(
×
903
        parent.children_.begin() + index + 1, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info))
×
904
    );
905

906
    parent.transitions_.insert(
×
907
        parent.transitions_.begin() + index + 1,
×
908
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
909
    );
910

911
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
912
};
×
913

914
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
915
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
916
    int index = parent.index(child);
×
917
    if (index == -1) {
×
918
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
919
    }
920

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

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

929
    auto new_entry = parent.at(index);
×
930
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
931

932
    return {new_block, new_entry.second};
×
933
};
×
934

935
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
134✔
936
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
134!
937

938
    scope.conditions_.push_back(cond);
134✔
939
    return *scope.cases_.back();
134✔
940
};
×
941

942
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
943
    scope.cases_.erase(scope.cases_.begin() + index);
×
944
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
945
};
×
946

947
While& StructuredSDFGBuilder::
948
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
44✔
949
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
44!
950

951
    // Increment element id for body node
952
    this->new_element_id();
44✔
953

954
    parent.transitions_
88✔
955
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
44!
956
        );
957

958
    return static_cast<While&>(*parent.children_.back().get());
44✔
959
};
×
960

961
For& StructuredSDFGBuilder::add_for(
174✔
962
    Sequence& parent,
963
    const symbolic::Symbol indvar,
964
    const symbolic::Condition condition,
965
    const symbolic::Expression init,
966
    const symbolic::Expression update,
967
    const sdfg::control_flow::Assignments& assignments,
968
    const DebugInfo& debug_info
969
) {
970
    parent.children_
348!
971
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
174!
972

973
    // Increment element id for body node
974
    this->new_element_id();
174✔
975

976
    parent.transitions_
348✔
977
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
174!
978
        );
979

980
    return static_cast<For&>(*parent.children_.back().get());
174✔
981
};
×
982

983
For& StructuredSDFGBuilder::add_for_before(
6✔
984
    Sequence& parent,
985
    ControlFlowNode& child,
986
    const symbolic::Symbol indvar,
987
    const symbolic::Condition condition,
988
    const symbolic::Expression init,
989
    const symbolic::Expression update,
990
    const sdfg::control_flow::Assignments& assignments,
991
    const DebugInfo& debug_info
992
) {
993
    int index = parent.index(child);
6✔
994
    if (index == -1) {
6!
995
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
996
    }
997

998
    parent.children_.insert(
12!
999
        parent.children_.begin() + index,
6✔
1000
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6!
1001
    );
1002

1003
    // Increment element id for body node
1004
    this->new_element_id();
6✔
1005

1006
    parent.transitions_.insert(
12!
1007
        parent.transitions_.begin() + index,
6✔
1008
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6!
1009
    );
1010

1011
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
1012
};
×
1013

1014
For& StructuredSDFGBuilder::add_for_after(
2✔
1015
    Sequence& parent,
1016
    ControlFlowNode& child,
1017
    const symbolic::Symbol indvar,
1018
    const symbolic::Condition condition,
1019
    const symbolic::Expression init,
1020
    const symbolic::Expression update,
1021
    const sdfg::control_flow::Assignments& assignments,
1022
    const DebugInfo& debug_info
1023
) {
1024
    int index = parent.index(child);
2✔
1025
    if (index == -1) {
2!
1026
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1027
    }
1028

1029
    parent.children_.insert(
4!
1030
        parent.children_.begin() + index + 1,
2✔
1031
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
2!
1032
    );
1033

1034
    // Increment element id for body node
1035
    this->new_element_id();
2✔
1036

1037
    parent.transitions_.insert(
4!
1038
        parent.transitions_.begin() + index + 1,
2✔
1039
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2!
1040
    );
1041

1042
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
1043
};
×
1044

1045
Map& StructuredSDFGBuilder::add_map(
48✔
1046
    Sequence& parent,
1047
    const symbolic::Symbol indvar,
1048
    const symbolic::Condition condition,
1049
    const symbolic::Expression init,
1050
    const symbolic::Expression update,
1051
    const ScheduleType& schedule_type,
1052
    const sdfg::control_flow::Assignments& assignments,
1053
    const DebugInfo& debug_info
1054
) {
1055
    parent.children_
96!
1056
        .push_back(std::unique_ptr<
48!
1057
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
48!
1058

1059
    // Increment element id for body node
1060
    this->new_element_id();
48✔
1061

1062
    parent.transitions_
96✔
1063
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
48!
1064
        );
1065

1066
    return static_cast<Map&>(*parent.children_.back().get());
48✔
1067
};
×
1068

1069
Map& StructuredSDFGBuilder::add_map_before(
6✔
1070
    Sequence& parent,
1071
    ControlFlowNode& child,
1072
    const symbolic::Symbol indvar,
1073
    const symbolic::Condition condition,
1074
    const symbolic::Expression init,
1075
    const symbolic::Expression update,
1076
    const ScheduleType& schedule_type,
1077
    const sdfg::control_flow::Assignments& assignments,
1078
    const DebugInfo& debug_info
1079
) {
1080
    int index = parent.index(child);
6✔
1081
    if (index == -1) {
6!
1082
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1083
    }
1084

1085
    parent.children_.insert(
12!
1086
        parent.children_.begin() + index,
6✔
1087
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
6!
1088
        )
1089
    );
1090

1091
    // Increment element id for body node
1092
    this->new_element_id();
6✔
1093

1094
    parent.transitions_.insert(
12!
1095
        parent.transitions_.begin() + index,
6✔
1096
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6!
1097
    );
1098

1099
    return static_cast<Map&>(*parent.children_.at(index).get());
6✔
1100
};
×
1101

1102
Map& StructuredSDFGBuilder::add_map_after(
12✔
1103
    Sequence& parent,
1104
    ControlFlowNode& child,
1105
    const symbolic::Symbol indvar,
1106
    const symbolic::Condition condition,
1107
    const symbolic::Expression init,
1108
    const symbolic::Expression update,
1109
    const ScheduleType& schedule_type,
1110
    const sdfg::control_flow::Assignments& assignments,
1111
    const DebugInfo& debug_info
1112
) {
1113
    int index = parent.index(child);
12✔
1114
    if (index == -1) {
12!
1115
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1116
    }
1117

1118
    parent.children_.insert(
24!
1119
        parent.children_.begin() + index + 1,
12✔
1120
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
12!
1121
        )
1122
    );
1123

1124
    // Increment element id for body node
1125
    this->new_element_id();
12✔
1126

1127
    parent.transitions_.insert(
24!
1128
        parent.transitions_.begin() + index + 1,
12✔
1129
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
12!
1130
    );
1131

1132
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
12✔
1133
};
×
1134

1135
Continue& StructuredSDFGBuilder::
1136
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
26✔
1137
    parent.children_.push_back(std::unique_ptr<Continue>(new Continue(this->new_element_id(), debug_info)));
26!
1138

1139
    parent.transitions_
52✔
1140
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
26!
1141
        );
1142

1143
    return static_cast<Continue&>(*parent.children_.back().get());
26✔
1144
};
×
1145

1146
Break& StructuredSDFGBuilder::
1147
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
27✔
1148
    parent.children_.push_back(std::unique_ptr<Break>(new Break(this->new_element_id(), debug_info)));
27!
1149

1150
    parent.transitions_
54✔
1151
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
27!
1152
        );
1153

1154
    return static_cast<Break&>(*parent.children_.back().get());
27✔
1155
};
×
1156

1157
Return& StructuredSDFGBuilder::add_return(
31✔
1158
    Sequence& parent,
1159
    const std::string& data,
1160
    const sdfg::control_flow::Assignments& assignments,
1161
    const DebugInfo& debug_info
1162
) {
1163
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
31!
1164

1165
    parent.transitions_
62✔
1166
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
31!
1167
        );
1168

1169
    return static_cast<Return&>(*parent.children_.back().get());
31✔
1170
};
×
1171

1172
Return& StructuredSDFGBuilder::add_constant_return(
×
1173
    Sequence& parent,
1174
    const std::string& data,
1175
    const types::IType& type,
1176
    const sdfg::control_flow::Assignments& assignments,
1177
    const DebugInfo& debug_info
1178
) {
1179
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1180

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

1185
    return static_cast<Return&>(*parent.children_.back().get());
×
1186
};
×
1187

1188
For& StructuredSDFGBuilder::convert_while(
×
1189
    Sequence& parent,
1190
    While& loop,
1191
    const symbolic::Symbol indvar,
1192
    const symbolic::Condition condition,
1193
    const symbolic::Expression init,
1194
    const symbolic::Expression update
1195
) {
1196
    int index = parent.index(loop);
×
1197
    if (index == -1) {
×
1198
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1199
    }
1200

1201
    auto iter = parent.children_.begin() + index;
×
1202
    auto& new_iter = *parent.children_.insert(
×
1203
        iter + 1,
×
1204
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1205
    );
1206

1207
    // Increment element id for body node
1208
    this->new_element_id();
×
1209

1210
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1211
    this->move_children(loop.root(), for_loop.root());
×
1212

1213
    // Remove while loop
1214
    parent.children_.erase(parent.children_.begin() + index);
×
1215

1216
    return for_loop;
×
1217
};
×
1218

1219
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
9✔
1220
    int index = parent.index(loop);
9✔
1221
    if (index == -1) {
9!
1222
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1223
    }
1224

1225
    auto iter = parent.children_.begin() + index;
9✔
1226
    auto& new_iter = *parent.children_.insert(
18!
1227
        iter + 1,
9✔
1228
        std::unique_ptr<Map>(new Map(
18!
1229
            this->new_element_id(),
9!
1230
            loop.debug_info(),
9!
1231
            loop.indvar(),
9!
1232
            loop.init(),
9!
1233
            loop.update(),
9!
1234
            loop.condition(),
9!
1235
            ScheduleType_Sequential::create()
9!
1236
        ))
1237
    );
1238

1239
    // Increment element id for body node
1240
    this->new_element_id();
9✔
1241

1242
    auto& map = dynamic_cast<Map&>(*new_iter);
9!
1243
    this->move_children(loop.root(), map.root());
9✔
1244

1245
    // Remove for loop
1246
    parent.children_.erase(parent.children_.begin() + index);
9✔
1247

1248
    return map;
9✔
1249
};
×
1250

1251
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1252
    if (index >= if_else.conditions_.size()) {
×
1253
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1254
    }
1255
    if_else.conditions_.at(index) = condition;
×
1256
};
×
1257

1258
void StructuredSDFGBuilder::update_loop(
19✔
1259
    StructuredLoop& loop,
1260
    const symbolic::Symbol indvar,
1261
    const symbolic::Condition condition,
1262
    const symbolic::Expression init,
1263
    const symbolic::Expression update
1264
) {
1265
    loop.indvar_ = indvar;
19✔
1266
    loop.condition_ = condition;
19✔
1267
    loop.init_ = init;
19✔
1268
    loop.update_ = update;
19✔
1269
};
19✔
1270

1271
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1272
    map.schedule_type_ = schedule_type;
4✔
1273
}
4✔
1274

1275
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1276
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2!
1277
    while (!queue.empty()) {
2!
1278
        auto current = queue.front();
2✔
1279
        queue.pop_front();
2✔
1280

1281
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2!
1282
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2!
1283
                if (&sequence_stmt->at(i).first == &node) {
2!
1284
                    return *sequence_stmt;
2✔
1285
                }
1286
                queue.push_back(&sequence_stmt->at(i).first);
×
1287
            }
×
1288
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1289
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1290
                queue.push_back(&if_else_stmt->at(i).first);
×
1291
            }
×
1292
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1293
            queue.push_back(&while_stmt->root());
×
1294
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1295
            queue.push_back(&loop_stmt->root());
×
1296
        }
×
1297
    }
1298

1299
    return this->structured_sdfg_->root();
×
1300
};
2✔
1301

1302
/***** Section: Dataflow Graph *****/
1303

1304
data_flow::AccessNode& StructuredSDFGBuilder::
1305
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
845✔
1306
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
845✔
1307
    auto res = block.dataflow_->nodes_.insert(
1,690!
1308
        {vertex,
845✔
1309
         std::unique_ptr<data_flow::AccessNode>(
845✔
1310
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
845!
1311
         )}
1312
    );
1313

1314
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
845!
1315
};
×
1316

1317
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
78✔
1318
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1319
) {
1320
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
78✔
1321
    auto res = block.dataflow_->nodes_.insert(
156!
1322
        {vertex,
78✔
1323
         std::unique_ptr<data_flow::ConstantNode>(
78✔
1324
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
78!
1325
         )}
1326
    );
1327

1328
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
78!
1329
};
×
1330

1331

1332
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
320✔
1333
    structured_control_flow::Block& block,
1334
    const data_flow::TaskletCode code,
1335
    const std::string& output,
1336
    const std::vector<std::string>& inputs,
1337
    const DebugInfo& debug_info
1338
) {
1339
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
320✔
1340
    auto res = block.dataflow_->nodes_.insert(
640!
1341
        {vertex,
320✔
1342
         std::unique_ptr<data_flow::Tasklet>(
320✔
1343
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
320!
1344
         )}
1345
    );
1346

1347
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
320!
1348
};
×
1349

1350
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
899✔
1351
    structured_control_flow::Block& block,
1352
    data_flow::DataFlowNode& src,
1353
    const std::string& src_conn,
1354
    data_flow::DataFlowNode& dst,
1355
    const std::string& dst_conn,
1356
    const data_flow::Subset& subset,
1357
    const types::IType& base_type,
1358
    const DebugInfo& debug_info
1359
) {
1360
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
899✔
1361
    auto res = block.dataflow_->edges_.insert(
1,798!
1362
        {edge.first,
1,798✔
1363
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,798!
1364
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
899!
1365
         ))}
1366
    );
1367

1368
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
899✔
1369
#ifndef NDEBUG
1370
    memlet.validate(*this->structured_sdfg_);
899✔
1371
#endif
1372

1373
    return memlet;
899✔
1374
};
×
1375

1376
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
120✔
1377
    structured_control_flow::Block& block,
1378
    data_flow::AccessNode& src,
1379
    data_flow::Tasklet& dst,
1380
    const std::string& dst_conn,
1381
    const data_flow::Subset& subset,
1382
    const types::IType& base_type,
1383
    const DebugInfo& debug_info
1384
) {
1385
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
120!
1386
};
×
1387

1388
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
117✔
1389
    structured_control_flow::Block& block,
1390
    data_flow::Tasklet& src,
1391
    const std::string& src_conn,
1392
    data_flow::AccessNode& dst,
1393
    const data_flow::Subset& subset,
1394
    const types::IType& base_type,
1395
    const DebugInfo& debug_info
1396
) {
1397
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
117!
1398
};
×
1399

1400
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
270✔
1401
    structured_control_flow::Block& block,
1402
    data_flow::AccessNode& src,
1403
    data_flow::Tasklet& dst,
1404
    const std::string& dst_conn,
1405
    const data_flow::Subset& subset,
1406
    const DebugInfo& debug_info
1407
) {
1408
    const types::IType* src_type = nullptr;
270✔
1409
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
270!
1410
        src_type = &cnode->type();
67✔
1411
    } else {
67✔
1412
        src_type = &this->structured_sdfg_->type(src.data());
203✔
1413
    }
1414
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
270✔
1415
    if (base_type.type_id() != types::TypeID::Scalar) {
270!
1416
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1417
    }
1418
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
270!
1419
};
×
1420

1421
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
181✔
1422
    structured_control_flow::Block& block,
1423
    data_flow::Tasklet& src,
1424
    const std::string& src_conn,
1425
    data_flow::AccessNode& dst,
1426
    const data_flow::Subset& subset,
1427
    const DebugInfo& debug_info
1428
) {
1429
    auto& dst_type = this->structured_sdfg_->type(dst.data());
181✔
1430
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
181✔
1431
    if (base_type.type_id() != types::TypeID::Scalar) {
181!
1432
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1433
    }
1434
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
181!
1435
};
×
1436

1437
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
29✔
1438
    structured_control_flow::Block& block,
1439
    data_flow::AccessNode& src,
1440
    data_flow::LibraryNode& dst,
1441
    const std::string& dst_conn,
1442
    const data_flow::Subset& subset,
1443
    const types::IType& base_type,
1444
    const DebugInfo& debug_info
1445
) {
1446
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
29!
1447
};
×
1448

1449
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
38✔
1450
    structured_control_flow::Block& block,
1451
    data_flow::LibraryNode& src,
1452
    const std::string& src_conn,
1453
    data_flow::AccessNode& dst,
1454
    const data_flow::Subset& subset,
1455
    const types::IType& base_type,
1456
    const DebugInfo& debug_info
1457
) {
1458
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
38!
1459
};
×
1460

1461
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
43✔
1462
    structured_control_flow::Block& block,
1463
    data_flow::AccessNode& src,
1464
    data_flow::AccessNode& dst,
1465
    const data_flow::Subset& subset,
1466
    const types::IType& base_type,
1467
    const DebugInfo& debug_info
1468
) {
1469
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
43!
1470
};
×
1471

1472
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
20✔
1473
    structured_control_flow::Block& block,
1474
    data_flow::AccessNode& src,
1475
    data_flow::AccessNode& dst,
1476
    bool derefs_src,
1477
    const types::IType& base_type,
1478
    const DebugInfo& debug_info
1479
) {
1480
    if (derefs_src) {
20✔
1481
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
13!
1482
    } else {
1483
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
7!
1484
    }
1485
};
20✔
1486

1487
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
28✔
1488
    auto& graph = block.dataflow();
28✔
1489
    auto e = edge.edge();
28✔
1490
    boost::remove_edge(e, graph.graph_);
28✔
1491
    graph.edges_.erase(e);
28✔
1492
};
28✔
1493

1494
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
25✔
1495
    auto& graph = block.dataflow();
25✔
1496
    auto v = node.vertex();
25✔
1497
    boost::remove_vertex(v, graph.graph_);
25✔
1498
    graph.nodes_.erase(v);
25✔
1499
};
25✔
1500

1501
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::CodeNode& node) {
12✔
1502
    auto& graph = block.dataflow();
12✔
1503

1504
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
12!
1505

1506
    // Delete incoming
1507
    std::list<const data_flow::Memlet*> iedges;
12✔
1508
    for (auto& iedge : graph.in_edges(node)) {
31!
1509
        iedges.push_back(&iedge);
19!
1510
    }
1511
    for (auto iedge : iedges) {
31✔
1512
        auto& src = iedge->src();
19!
1513
        to_delete.insert(&src);
19!
1514

1515
        auto edge = iedge->edge();
19!
1516
        graph.edges_.erase(edge);
19!
1517
        boost::remove_edge(edge, graph.graph_);
19!
1518
    }
1519

1520
    // Delete outgoing
1521
    std::list<const data_flow::Memlet*> oedges;
12✔
1522
    for (auto& oedge : graph.out_edges(node)) {
24!
1523
        oedges.push_back(&oedge);
12!
1524
    }
1525
    for (auto oedge : oedges) {
24✔
1526
        auto& dst = oedge->dst();
12!
1527
        to_delete.insert(&dst);
12!
1528

1529
        auto edge = oedge->edge();
12!
1530
        graph.edges_.erase(edge);
12!
1531
        boost::remove_edge(edge, graph.graph_);
12!
1532
    }
1533

1534
    // Delete nodes
1535
    for (auto obsolete_node : to_delete) {
55✔
1536
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
43!
1537
            auto vertex = obsolete_node->vertex();
43!
1538
            graph.nodes_.erase(vertex);
43!
1539
            boost::remove_vertex(vertex, graph.graph_);
43!
1540
        }
43✔
1541
    }
1542
};
12✔
1543

1544
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
9✔
1545
    auto& graph = block.dataflow();
9✔
1546

1547
    std::list<const data_flow::Memlet*> tmp;
9✔
1548
    std::list<const data_flow::DataFlowNode*> queue = {&node};
9!
1549
    while (!queue.empty()) {
33✔
1550
        auto current = queue.front();
24✔
1551
        queue.pop_front();
24✔
1552
        if (current != &node) {
24✔
1553
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
15!
1554
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
6!
1555
                    continue;
×
1556
                }
1557
            }
6✔
1558
        }
15✔
1559

1560
        tmp.clear();
24✔
1561
        for (auto& iedge : graph.in_edges(*current)) {
39!
1562
            tmp.push_back(&iedge);
15!
1563
        }
1564
        for (auto iedge : tmp) {
39✔
1565
            auto& src = iedge->src();
15!
1566
            queue.push_back(&src);
15!
1567

1568
            auto edge = iedge->edge();
15!
1569
            graph.edges_.erase(edge);
15!
1570
            boost::remove_edge(edge, graph.graph_);
15!
1571
        }
1572

1573
        if (current != &node || graph.out_degree(*current) == 0) {
24!
1574
            auto vertex = current->vertex();
23!
1575
            graph.nodes_.erase(vertex);
23!
1576
            boost::remove_vertex(vertex, graph.graph_);
23!
1577
        }
23✔
1578
    }
1579
};
9✔
1580

1581
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
13✔
1582
    auto& to_dataflow = to.dataflow();
13✔
1583

1584
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
13✔
1585
    for (auto& entry : from.nodes_) {
14✔
1586
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1!
1587
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1!
1588
        node_mapping.insert({entry.first, vertex});
1!
1589
    }
1590

1591
    for (auto& entry : from.edges_) {
13!
1592
        auto src = node_mapping[entry.second->src().vertex()];
×
1593
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1594

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

1597
        to_dataflow.edges_.insert(
×
1598
            {edge.first,
×
1599
             entry.second->clone(
×
1600
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1601
             )}
1602
        );
1603
    }
1604
};
13✔
1605

1606
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
20✔
1607
    auto& user_graph = source_node.get_parent();
20✔
1608
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
20!
1609
    if (!block) {
20!
1610
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1611
    }
1612

1613
    // Merge access nodes if they access the same container on a tasklet
1614
    for (auto& oedge : user_graph.out_edges(source_node)) {
34✔
1615
        if (auto* tasklet = dynamic_cast<data_flow::Tasklet*>(&oedge.dst())) {
14!
1616
            std::unordered_set<data_flow::Memlet*> iedges;
7✔
1617
            for (auto& iedge : user_graph.in_edges(*tasklet)) {
16!
1618
                iedges.insert(&iedge);
9!
1619
            }
1620
            for (auto* iedge : iedges) {
16✔
1621
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
9!
1622
                    continue;
×
1623
                }
1624
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
9!
1625
                if (access_node == &source_node || access_node->data() != source_node.data()) {
9!
1626
                    continue;
8✔
1627
                }
1628
                this->add_memlet(
1!
1629
                    *block,
1✔
1630
                    source_node,
1✔
1631
                    iedge->src_conn(),
1!
1632
                    *tasklet,
1✔
1633
                    iedge->dst_conn(),
1!
1634
                    iedge->subset(),
1!
1635
                    iedge->base_type(),
1!
1636
                    iedge->debug_info()
1!
1637
                );
1638
                this->remove_memlet(*block, *iedge);
1!
1639
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
1!
1640
            }
1641
        }
7✔
1642
    }
1643
}
20✔
1644

1645
} // namespace builder
1646
} // 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