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

daisytuner / sdfglib / 19434185884

17 Nov 2025 03:04PM UTC coverage: 62.169% (-0.003%) from 62.172%
19434185884

push

github

web-flow
Merge pull request #350 from daisytuner/traverse-cutoff

adds traverse cutoff

2 of 4 new or added lines in 1 file covered. (50.0%)

3 existing lines in 1 file now uncovered.

11073 of 17811 relevant lines covered (62.17%)

112.6 hits per line

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

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

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

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

43
    return nodes;
1✔
44
};
1✔
45

46
bool post_dominates(
6✔
47
    const State* pdom,
48
    const State* node,
49
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree
50
) {
51
    if (pdom == node) {
6✔
52
        return true;
1✔
53
    }
54

55
    auto current = pdom_tree.at(node);
5✔
56
    while (current != nullptr) {
9✔
57
        if (current == pdom) {
9✔
58
            return true;
5✔
59
        }
60
        current = pdom_tree.at(current);
4✔
61
    }
62

63
    return false;
×
64
}
6✔
65

66
const control_flow::State* StructuredSDFGBuilder::find_end_of_if_else(
3✔
67
    SDFG& sdfg,
68
    const State* current,
69
    std::vector<const InterstateEdge*>& out_edges,
70
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree
71
) {
72
    // Best-effort approach: Check if post-dominator of current dominates all out edges
73
    auto pdom = pdom_tree.at(current);
3✔
74
    if (pdom == nullptr) {
3✔
75
        return nullptr;
×
76
    }
77

78
    for (auto& edge : out_edges) {
9✔
79
        if (!post_dominates(pdom, &edge->dst(), pdom_tree)) {
6✔
80
            return nullptr;
×
81
        }
82
    }
83

84
    return pdom;
3✔
85
}
3✔
86

87
void StructuredSDFGBuilder::traverse(SDFG& sdfg) {
4✔
88
    // Start of SDFGS
89
    Sequence& root = *structured_sdfg_->root_;
4✔
90
    const State* start_state = &sdfg.start_state();
4✔
91

92
    auto pdom_tree = sdfg.post_dominator_tree();
4✔
93

94
    std::unordered_set<const InterstateEdge*> breaks;
4✔
95
    std::unordered_set<const InterstateEdge*> continues;
4✔
96
    for (auto& edge : sdfg.back_edges()) {
5✔
97
        continues.insert(edge);
1✔
98
    }
99

100
    std::unordered_set<const control_flow::State*> visited;
4✔
101
    this->traverse_with_loop_detection(sdfg, root, start_state, nullptr, continues, breaks, pdom_tree, visited);
4✔
102
};
4✔
103

104
void StructuredSDFGBuilder::traverse_with_loop_detection(
9✔
105
    SDFG& sdfg,
106
    Sequence& scope,
107
    const State* current,
108
    const State* end,
109
    const std::unordered_set<const InterstateEdge*>& continues,
110
    const std::unordered_set<const InterstateEdge*>& breaks,
111
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
112
    std::unordered_set<const control_flow::State*>& visited
113
) {
114
    if (current == end) {
9✔
115
        return;
1✔
116
    }
117
    // Cutoff
118
    if (this->function().element_counter_ > sdfg.states().size() * TRAVERSE_CUTOFF) {
8✔
NEW
119
        throw UnstructuredControlFlowException();
×
120
    }
121

122
    auto in_edges = sdfg.in_edges(*current);
8✔
123

124
    // Loop detection
125
    std::unordered_set<const InterstateEdge*> loop_edges;
8✔
126
    for (auto& iedge : in_edges) {
13✔
127
        if (continues.find(&iedge) != continues.end()) {
5✔
128
            loop_edges.insert(&iedge);
1✔
129
        }
1✔
130
    }
131
    if (!loop_edges.empty()) {
8✔
132
        // 1. Determine nodes of loop body
133
        std::unordered_set<const control_flow::State*> body;
1✔
134
        for (auto back_edge : loop_edges) {
2✔
135
            auto loop_nodes = this->determine_loop_nodes(sdfg, back_edge->src(), back_edge->dst());
1✔
136
            body.insert(loop_nodes.begin(), loop_nodes.end());
1✔
137
        }
1✔
138

139
        // 2. Determine exit states and exit edges
140
        std::unordered_set<const control_flow::State*> exit_states;
1✔
141
        std::unordered_set<const control_flow::InterstateEdge*> exit_edges;
1✔
142
        for (auto node : body) {
4✔
143
            for (auto& edge : sdfg.out_edges(*node)) {
7✔
144
                if (body.find(&edge.dst()) == body.end()) {
4✔
145
                    exit_edges.insert(&edge);
1✔
146
                    exit_states.insert(&edge.dst());
1✔
147
                }
1✔
148
            }
149
        }
150
        if (exit_states.size() != 1) {
1✔
151
            throw UnstructuredControlFlowException();
×
152
        }
153
        const control_flow::State* exit_state = *exit_states.begin();
1✔
154

155
        for (auto& edge : breaks) {
1✔
156
            exit_edges.insert(edge);
×
157
        }
158

159
        // Collect debug information (could be removed when this is computed dynamically)
160
        DebugInfo dbg_info = current->debug_info();
1✔
161
        for (auto& edge : in_edges) {
3✔
162
            dbg_info = DebugInfo::merge(dbg_info, edge.debug_info());
2✔
163
        }
164
        for (auto node : body) {
4✔
165
            dbg_info = DebugInfo::merge(dbg_info, node->debug_info());
3✔
166
        }
167
        for (auto edge : exit_edges) {
2✔
168
            dbg_info = DebugInfo::merge(dbg_info, edge->debug_info());
1✔
169
        }
170

171
        // 3. Add while loop
172
        While& loop = this->add_while(scope, {}, dbg_info);
1✔
173

174
        std::unordered_set<const control_flow::State*> loop_visited(visited);
1✔
175
        this->traverse_without_loop_detection(
1✔
176
            sdfg, loop.root(), current, exit_state, continues, exit_edges, pdom_tree, loop_visited
1✔
177
        );
178

179
        this->traverse_with_loop_detection(sdfg, scope, exit_state, end, continues, breaks, pdom_tree, visited);
1✔
180
    } else {
1✔
181
        this->traverse_without_loop_detection(sdfg, scope, current, end, continues, breaks, pdom_tree, visited);
7✔
182
    }
183
};
9✔
184

185
void StructuredSDFGBuilder::traverse_without_loop_detection(
8✔
186
    SDFG& sdfg,
187
    Sequence& scope,
188
    const State* current,
189
    const State* end,
190
    const std::unordered_set<const InterstateEdge*>& continues,
191
    const std::unordered_set<const InterstateEdge*>& breaks,
192
    const std::unordered_map<const control_flow::State*, const control_flow::State*>& pdom_tree,
193
    std::unordered_set<const control_flow::State*>& visited
194
) {
195
    // Cutoff
196
    if (this->function().element_counter_ > sdfg.states().size() * TRAVERSE_CUTOFF) {
8✔
NEW
197
        throw UnstructuredControlFlowException();
×
198
    }
199

200
    std::list<const State*> queue = {current};
8✔
201
    while (!queue.empty()) {
28✔
202
        auto curr = queue.front();
20✔
203
        queue.pop_front();
20✔
204
        if (curr == end) {
20✔
205
            continue;
3✔
206
        }
207

208
        if (visited.find(curr) != visited.end()) {
17✔
209
            throw UnstructuredControlFlowException();
×
210
        }
211
        visited.insert(curr);
17✔
212

213
        auto out_edges = sdfg.out_edges(*curr);
17✔
214
        auto out_degree = sdfg.out_degree(*curr);
17✔
215

216
        // Case 1: Sink node
217
        if (out_degree == 0) {
17✔
218
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
4✔
219

220
            auto return_state = dynamic_cast<const control_flow::ReturnState*>(curr);
4✔
221
            assert(return_state != nullptr);
4✔
222
            if (return_state->is_data()) {
4✔
223
                this->add_return(scope, return_state->data(), {}, return_state->debug_info());
4✔
224
            } else if (return_state->is_constant()) {
4✔
225
                this->add_constant_return(
×
226
                    scope, return_state->data(), return_state->type(), {}, return_state->debug_info()
×
227
                );
228
            } else {
×
229
                assert(false && "Unknown return state type");
×
230
            }
231

232
            continue;
4✔
233
        }
234

235
        // Case 2: Transition
236
        if (out_degree == 1) {
13✔
237
            auto& oedge = *out_edges.begin();
10✔
238
            if (!oedge.is_unconditional()) {
10✔
239
                throw UnstructuredControlFlowException();
×
240
            }
241
            this->add_block(scope, curr->dataflow(), oedge.assignments(), curr->debug_info());
10✔
242

243
            if (continues.find(&oedge) != continues.end()) {
10✔
244
                this->add_continue(scope, {}, oedge.debug_info());
×
245
            } else if (breaks.find(&oedge) != breaks.end()) {
10✔
246
                this->add_break(scope, {}, oedge.debug_info());
×
247
            } else {
×
248
                bool starts_loop = false;
10✔
249
                for (auto& iedge : sdfg.in_edges(oedge.dst())) {
23✔
250
                    if (continues.find(&iedge) != continues.end()) {
13✔
251
                        starts_loop = true;
×
252
                        break;
×
253
                    }
254
                }
255
                if (!starts_loop) {
10✔
256
                    queue.push_back(&oedge.dst());
10✔
257
                } else {
10✔
258
                    this->traverse_with_loop_detection(
×
259
                        sdfg, scope, &oedge.dst(), end, continues, breaks, pdom_tree, visited
×
260
                    );
261
                }
262
            }
263
            continue;
10✔
264
        }
265

266
        // Case 3: Branches
267
        if (out_degree > 1) {
3✔
268
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
3✔
269

270
            std::vector<const InterstateEdge*> out_edges_vec;
3✔
271
            for (auto& edge : out_edges) {
9✔
272
                out_edges_vec.push_back(&edge);
6✔
273
            }
274

275
            // Best-effort approach: Find end of if-else
276
            // If not found, the branches may repeat paths yielding a large SDFG
277
            const control_flow::State* local_end = this->find_end_of_if_else(sdfg, curr, out_edges_vec, pdom_tree);
3✔
278
            if (local_end == nullptr) {
3✔
279
                local_end = end;
×
280
            }
×
281

282
            auto& if_else = this->add_if_else(scope, {}, curr->debug_info());
3✔
283
            for (size_t i = 0; i < out_degree; i++) {
9✔
284
                auto& out_edge = out_edges_vec[i];
6✔
285

286
                auto& branch = this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
287
                if (!out_edge->assignments().empty()) {
6✔
288
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
289
                }
2✔
290
                if (continues.find(out_edge) != continues.end()) {
6✔
291
                    this->add_continue(branch, {}, out_edge->debug_info());
1✔
292
                } else if (breaks.find(out_edge) != breaks.end()) {
6✔
293
                    this->add_break(branch, {}, out_edge->debug_info());
1✔
294
                } else {
1✔
295
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
4✔
296
                    this->traverse_with_loop_detection(
4✔
297
                        sdfg, branch, &out_edge->dst(), local_end, continues, breaks, pdom_tree, branch_visited
4✔
298
                    );
299
                }
4✔
300
            }
6✔
301

302
            if (local_end != end) {
3✔
303
                bool starts_loop = false;
2✔
304
                for (auto& iedge : sdfg.in_edges(*local_end)) {
6✔
305
                    if (continues.find(&iedge) != continues.end()) {
4✔
306
                        starts_loop = true;
×
307
                        break;
×
308
                    }
309
                }
310
                if (!starts_loop) {
2✔
311
                    queue.push_back(local_end);
2✔
312
                } else {
2✔
313
                    this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues, breaks, pdom_tree, visited);
×
314
                }
315
            }
2✔
316
            continue;
317
        }
3✔
318
    }
319
}
8✔
320

321
Function& StructuredSDFGBuilder::function() const { return static_cast<Function&>(*this->structured_sdfg_); };
6,946✔
322

323
StructuredSDFGBuilder::StructuredSDFGBuilder(StructuredSDFG& sdfg)
×
324
    : FunctionBuilder(), structured_sdfg_(&sdfg, owned(false)) {};
×
325

326
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
92✔
327
    : FunctionBuilder(), structured_sdfg_(sdfg.release(), owned(true)) {};
92✔
328

329
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
448✔
330
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type), owned(true)) {};
448✔
331

332
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
7✔
333
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type, return_type), owned(true)) {};
7✔
334

335
StructuredSDFGBuilder::StructuredSDFGBuilder(SDFG& sdfg)
4✔
336
    : FunctionBuilder(),
4✔
337
      structured_sdfg_(new StructuredSDFG(sdfg.name(), sdfg.type(), sdfg.return_type()), owned(true)) {
4✔
338
    for (auto& entry : sdfg.structures_) {
4✔
339
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
340
    }
341

342
    for (auto& entry : sdfg.containers_) {
11✔
343
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
344
    }
345

346
    for (auto& arg : sdfg.arguments_) {
6✔
347
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
348
    }
349

350
    for (auto& ext : sdfg.externals_) {
5✔
351
        this->structured_sdfg_->externals_.push_back(ext);
1✔
352
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
1✔
353
    }
354

355
    for (auto& entry : sdfg.assumptions_) {
9✔
356
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
357
    }
358

359
    for (auto& entry : sdfg.metadata_) {
6✔
360
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
361
    }
362

363
    this->traverse(sdfg);
4✔
364
};
4✔
365

366
StructuredSDFG& StructuredSDFGBuilder::subject() const { return *this->structured_sdfg_; };
1,230✔
367

368
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
278✔
369
#ifndef NDEBUG
370
    this->structured_sdfg_->validate();
278✔
371
#endif
372

373
    if (!structured_sdfg_.get_deleter().should_delete_) {
278✔
374
        throw InvalidSDFGException("StructuredSDFGBuilder: Cannot move a non-owned SDFG");
×
375
    }
376

377
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
278✔
378
};
×
379

380
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
381
    FunctionBuilder::rename_container(old_name, new_name);
×
382

383
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
384
};
×
385

386
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
13✔
387
    auto& sdfg = this->subject();
13✔
388
    std::list<Element*> queue = {&sdfg.root()};
13✔
389
    while (!queue.empty()) {
55✔
390
        auto current = queue.front();
55✔
391
        queue.pop_front();
55✔
392

393
        if (current->element_id() == element_id) {
55✔
394
            return current;
13✔
395
        }
396

397
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
42✔
398
            auto& dataflow = block_stmt->dataflow();
×
399
            for (auto& node : dataflow.nodes()) {
×
400
                queue.push_back(&node);
×
401
            }
402
            for (auto& edge : dataflow.edges()) {
×
403
                queue.push_back(&edge);
×
404
            }
405
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
42✔
406
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
44✔
407
                queue.push_back(&sequence_stmt->at(i).first);
22✔
408
                queue.push_back(&sequence_stmt->at(i).second);
22✔
409
            }
22✔
410
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
42✔
411
            // Do nothing
412
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
20✔
413
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
414
                queue.push_back(&if_else_stmt->at(i).first);
×
415
            }
×
416
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
20✔
417
            queue.push_back(&for_stmt->root());
×
418
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
20✔
419
            queue.push_back(&while_stmt->root());
×
420
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
20✔
421
            // Do nothing
422
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
20✔
423
            // Do nothing
424
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
20✔
425
            queue.push_back(&map_stmt->root());
10✔
426
        }
10✔
427
    }
428

429
    return nullptr;
×
430
};
13✔
431

432
Sequence& StructuredSDFGBuilder::
433
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
30✔
434
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
30✔
435

436
    parent.transitions_
60✔
437
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
30✔
438
        );
439

440
    return static_cast<Sequence&>(*parent.children_.back().get());
30✔
441
};
×
442

443
Sequence& StructuredSDFGBuilder::add_sequence_before(
5✔
444
    Sequence& parent,
445
    ControlFlowNode& child,
446
    const sdfg::control_flow::Assignments& assignments,
447
    const DebugInfo& debug_info
448
) {
449
    int index = parent.index(child);
5✔
450
    if (index == -1) {
5✔
451
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
452
    }
453

454
    parent.children_.insert(
10✔
455
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
5✔
456
    );
457

458
    parent.transitions_.insert(
10✔
459
        parent.transitions_.begin() + index,
5✔
460
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
5✔
461
    );
462

463
    return static_cast<Sequence&>(*parent.children_.at(index).get());
5✔
464
};
×
465

466
Sequence& StructuredSDFGBuilder::add_sequence_after(
×
467
    Sequence& parent,
468
    ControlFlowNode& child,
469
    const sdfg::control_flow::Assignments& assignments,
470
    const DebugInfo& debug_info
471
) {
472
    int index = parent.index(child);
×
473
    if (index == -1) {
×
474
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
475
    }
476

477
    parent.children_.insert(
×
478
        parent.children_.begin() + index + 1,
×
479
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
480
    );
481

482
    parent.transitions_.insert(
×
483
        parent.transitions_.begin() + index + 1,
×
484
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
485
    );
486

487
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
488
};
×
489

490
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
491
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
492
    int index = parent.index(child);
×
493
    if (index == -1) {
×
494
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
495
    }
496

497
    parent.children_.insert(
×
498
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
499
    );
500

501
    parent.transitions_.insert(
×
502
        parent.transitions_.begin() + index,
×
503
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
504
    );
505

506
    auto new_entry = parent.at(index);
×
507
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
508

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

512
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
31✔
513
    parent.children_.erase(parent.children_.begin() + index);
31✔
514
    parent.transitions_.erase(parent.transitions_.begin() + index);
31✔
515
};
31✔
516

517
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
518
    parent.children_.clear();
×
519
    parent.transitions_.clear();
×
520
};
×
521

522
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
10✔
523
    this->move_child(source, source_index, target, target.size());
10✔
524
};
10✔
525

526
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
39✔
527
    auto node_ptr = std::move(source.children_.at(source_index));
39✔
528
    auto trans_ptr = std::move(source.transitions_.at(source_index));
39✔
529
    source.children_.erase(source.children_.begin() + source_index);
39✔
530
    source.transitions_.erase(source.transitions_.begin() + source_index);
39✔
531

532
    trans_ptr->parent_ = &target;
39✔
533
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
39✔
534
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
39✔
535
};
39✔
536

537
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
24✔
538
    this->move_children(source, target, target.size());
24✔
539
};
24✔
540

541
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
24✔
542
    target.children_.insert(
48✔
543
        target.children_.begin() + target_index,
24✔
544
        std::make_move_iterator(source.children_.begin()),
24✔
545
        std::make_move_iterator(source.children_.end())
24✔
546
    );
547
    target.transitions_.insert(
48✔
548
        target.transitions_.begin() + target_index,
24✔
549
        std::make_move_iterator(source.transitions_.begin()),
24✔
550
        std::make_move_iterator(source.transitions_.end())
24✔
551
    );
552
    for (auto& trans : target.transitions_) {
55✔
553
        trans->parent_ = &target;
31✔
554
    }
555
    source.children_.clear();
24✔
556
    source.transitions_.clear();
24✔
557
};
24✔
558

559
Block& StructuredSDFGBuilder::
560
    add_block(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
536✔
561
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
536✔
562

563
    parent.transitions_
1,072✔
564
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
536✔
565
        );
566

567
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
536✔
568
    (*new_block.dataflow_).parent_ = &new_block;
536✔
569

570
    return new_block;
536✔
571
};
×
572

573
Block& StructuredSDFGBuilder::add_block(
20✔
574
    Sequence& parent,
575
    const data_flow::DataFlowGraph& data_flow_graph,
576
    const sdfg::control_flow::Assignments& assignments,
577
    const DebugInfo& debug_info
578
) {
579
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
20✔
580

581
    parent.transitions_
40✔
582
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
20✔
583
        );
584

585
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
20✔
586
    (*new_block.dataflow_).parent_ = &new_block;
20✔
587

588
    this->add_dataflow(data_flow_graph, new_block);
20✔
589

590
    return new_block;
20✔
591
};
×
592

593
Block& StructuredSDFGBuilder::add_block_before(
14✔
594
    Sequence& parent,
595
    ControlFlowNode& child,
596
    const sdfg::control_flow::Assignments& assignments,
597
    const DebugInfo& debug_info
598
) {
599
    int index = parent.index(child);
14✔
600
    if (index == -1) {
14✔
601
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
602
    }
603

604
    parent.children_
28✔
605
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
14✔
606

607
    parent.transitions_.insert(
28✔
608
        parent.transitions_.begin() + index,
14✔
609
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
610
    );
611

612
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
14✔
613
    (*new_block.dataflow_).parent_ = &new_block;
14✔
614

615
    return new_block;
14✔
616
};
×
617

618
Block& StructuredSDFGBuilder::add_block_before(
×
619
    Sequence& parent,
620
    ControlFlowNode& child,
621
    data_flow::DataFlowGraph& data_flow_graph,
622
    const sdfg::control_flow::Assignments& assignments,
623
    const DebugInfo& debug_info
624
) {
625
    int index = parent.index(child);
×
626
    if (index == -1) {
×
627
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
628
    }
629

630
    parent.children_
×
631
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
632

633
    parent.transitions_.insert(
×
634
        parent.transitions_.begin() + index,
×
635
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
636
    );
637

638
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
639
    (*new_block.dataflow_).parent_ = &new_block;
×
640
    this->add_dataflow(data_flow_graph, new_block);
×
641

642
    return new_block;
×
643
};
×
644

645
Block& StructuredSDFGBuilder::add_block_after(
3✔
646
    Sequence& parent,
647
    ControlFlowNode& child,
648
    const sdfg::control_flow::Assignments& assignments,
649
    const DebugInfo& debug_info
650
) {
651
    int index = parent.index(child);
3✔
652
    if (index == -1) {
3✔
653
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
654
    }
655

656
    parent.children_.insert(
6✔
657
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3✔
658
    );
659

660
    parent.transitions_.insert(
6✔
661
        parent.transitions_.begin() + index + 1,
3✔
662
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3✔
663
    );
664

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

668
    return new_block;
3✔
669
};
×
670

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

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

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

692
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
693
    (*new_block.dataflow_).parent_ = &new_block;
×
694
    this->add_dataflow(data_flow_graph, new_block);
×
695

696
    return new_block;
×
697
};
×
698

699
std::pair<Block&, Transition&> StructuredSDFGBuilder::
700
    add_block_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
701
    int index = parent.index(child);
×
702
    if (index == -1) {
×
703
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
704
    }
705

706
    parent.children_
×
707
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
708

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

714
    auto new_entry = parent.at(index);
×
715
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
716
    (*new_block.dataflow_).parent_ = &new_block;
×
717

718
    return {new_block, new_entry.second};
×
719
};
×
720

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

729
    parent.children_
×
730
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
731

732
    parent.transitions_.insert(
×
733
        parent.transitions_.begin() + index,
×
734
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
735
    );
736

737
    auto new_entry = parent.at(index);
×
738
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
739
    (*new_block.dataflow_).parent_ = &new_block;
×
740

741
    this->add_dataflow(data_flow_graph, new_block);
×
742

743
    return {new_block, new_entry.second};
×
744
};
×
745

746
std::pair<Block&, Transition&> StructuredSDFGBuilder::
747
    add_block_after(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
748
    int index = parent.index(child);
×
749
    if (index == -1) {
×
750
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
751
    }
752

753
    parent.children_.insert(
×
754
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
755
    );
756

757
    parent.transitions_.insert(
×
758
        parent.transitions_.begin() + index + 1,
×
759
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
760
    );
761

762
    auto new_entry = parent.at(index + 1);
×
763
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
764
    (*new_block.dataflow_).parent_ = &new_block;
×
765

766
    return {new_block, new_entry.second};
×
767
};
×
768

769
std::pair<Block&, Transition&> StructuredSDFGBuilder::add_block_after(
×
770
    Sequence& parent, ControlFlowNode& child, data_flow::DataFlowGraph& data_flow_graph, const DebugInfo& debug_info
771
) {
772
    int index = parent.index(child);
×
773
    if (index == -1) {
×
774
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
775
    }
776

777
    parent.children_.insert(
×
778
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
779
    );
780

781
    parent.transitions_.insert(
×
782
        parent.transitions_.begin() + index + 1,
×
783
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
784
    );
785

786
    auto new_entry = parent.at(index + 1);
×
787
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
788
    (*new_block.dataflow_).parent_ = &new_block;
×
789

790
    this->add_dataflow(data_flow_graph, new_block);
×
791

792
    return {new_block, new_entry.second};
×
793
};
×
794

795
IfElse& StructuredSDFGBuilder::
796
    add_if_else(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
48✔
797
    parent.children_.push_back(std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
48✔
798

799
    parent.transitions_
96✔
800
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
48✔
801
        );
802

803
    return static_cast<IfElse&>(*parent.children_.back().get());
48✔
804
};
×
805

806
IfElse& StructuredSDFGBuilder::add_if_else_before(
1✔
807
    Sequence& parent,
808
    ControlFlowNode& child,
809
    const sdfg::control_flow::Assignments& assignments,
810
    const DebugInfo& debug_info
811
) {
812
    int index = parent.index(child);
1✔
813
    if (index == -1) {
1✔
814
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
815
    }
816

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

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

825
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
826
};
×
827

828
IfElse& StructuredSDFGBuilder::add_if_else_after(
×
829
    Sequence& parent,
830
    ControlFlowNode& child,
831
    const sdfg::control_flow::Assignments& assignments,
832
    const DebugInfo& debug_info
833
) {
834
    int index = parent.index(child);
×
835
    if (index == -1) {
×
836
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
837
    }
838

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

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

848
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
849
};
×
850

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

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

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

866
    auto new_entry = parent.at(index);
×
867
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
868

869
    return {new_block, new_entry.second};
×
870
};
×
871

872
Sequence& StructuredSDFGBuilder::add_case(IfElse& scope, const sdfg::symbolic::Condition cond, const DebugInfo& debug_info) {
82✔
873
    scope.cases_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
82✔
874

875
    scope.conditions_.push_back(cond);
82✔
876
    return *scope.cases_.back();
82✔
877
};
×
878

879
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
880
    scope.cases_.erase(scope.cases_.begin() + index);
×
881
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
882
};
×
883

884
While& StructuredSDFGBuilder::
885
    add_while(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
36✔
886
    parent.children_.push_back(std::unique_ptr<While>(new While(this->new_element_id(), debug_info)));
36✔
887

888
    // Increment element id for body node
889
    this->new_element_id();
36✔
890

891
    parent.transitions_
72✔
892
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
36✔
893
        );
894

895
    return static_cast<While&>(*parent.children_.back().get());
36✔
896
};
×
897

898
For& StructuredSDFGBuilder::add_for(
178✔
899
    Sequence& parent,
900
    const symbolic::Symbol indvar,
901
    const symbolic::Condition condition,
902
    const symbolic::Expression init,
903
    const symbolic::Expression update,
904
    const sdfg::control_flow::Assignments& assignments,
905
    const DebugInfo& debug_info
906
) {
907
    parent.children_
356✔
908
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
178✔
909

910
    // Increment element id for body node
911
    this->new_element_id();
178✔
912

913
    parent.transitions_
356✔
914
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
178✔
915
        );
916

917
    return static_cast<For&>(*parent.children_.back().get());
178✔
918
};
×
919

920
For& StructuredSDFGBuilder::add_for_before(
6✔
921
    Sequence& parent,
922
    ControlFlowNode& child,
923
    const symbolic::Symbol indvar,
924
    const symbolic::Condition condition,
925
    const symbolic::Expression init,
926
    const symbolic::Expression update,
927
    const sdfg::control_flow::Assignments& assignments,
928
    const DebugInfo& debug_info
929
) {
930
    int index = parent.index(child);
6✔
931
    if (index == -1) {
6✔
932
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
933
    }
934

935
    parent.children_.insert(
12✔
936
        parent.children_.begin() + index,
6✔
937
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
938
    );
939

940
    // Increment element id for body node
941
    this->new_element_id();
6✔
942

943
    parent.transitions_.insert(
12✔
944
        parent.transitions_.begin() + index,
6✔
945
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
946
    );
947

948
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
949
};
×
950

951
For& StructuredSDFGBuilder::add_for_after(
2✔
952
    Sequence& parent,
953
    ControlFlowNode& child,
954
    const symbolic::Symbol indvar,
955
    const symbolic::Condition condition,
956
    const symbolic::Expression init,
957
    const symbolic::Expression update,
958
    const sdfg::control_flow::Assignments& assignments,
959
    const DebugInfo& debug_info
960
) {
961
    int index = parent.index(child);
2✔
962
    if (index == -1) {
2✔
963
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
964
    }
965

966
    parent.children_.insert(
4✔
967
        parent.children_.begin() + index + 1,
2✔
968
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
2✔
969
    );
970

971
    // Increment element id for body node
972
    this->new_element_id();
2✔
973

974
    parent.transitions_.insert(
4✔
975
        parent.transitions_.begin() + index + 1,
2✔
976
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2✔
977
    );
978

979
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
980
};
×
981

982
Map& StructuredSDFGBuilder::add_map(
47✔
983
    Sequence& parent,
984
    const symbolic::Symbol indvar,
985
    const symbolic::Condition condition,
986
    const symbolic::Expression init,
987
    const symbolic::Expression update,
988
    const ScheduleType& schedule_type,
989
    const sdfg::control_flow::Assignments& assignments,
990
    const DebugInfo& debug_info
991
) {
992
    parent.children_
94✔
993
        .push_back(std::unique_ptr<
47✔
994
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
47✔
995

996
    // Increment element id for body node
997
    this->new_element_id();
47✔
998

999
    parent.transitions_
94✔
1000
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
47✔
1001
        );
1002

1003
    return static_cast<Map&>(*parent.children_.back().get());
47✔
1004
};
×
1005

1006
Map& StructuredSDFGBuilder::add_map_before(
6✔
1007
    Sequence& parent,
1008
    ControlFlowNode& child,
1009
    const symbolic::Symbol indvar,
1010
    const symbolic::Condition condition,
1011
    const symbolic::Expression init,
1012
    const symbolic::Expression update,
1013
    const ScheduleType& schedule_type,
1014
    const sdfg::control_flow::Assignments& assignments,
1015
    const DebugInfo& debug_info
1016
) {
1017
    int index = parent.index(child);
6✔
1018
    if (index == -1) {
6✔
1019
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1020
    }
1021

1022
    parent.children_.insert(
12✔
1023
        parent.children_.begin() + index,
6✔
1024
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
6✔
1025
        )
1026
    );
1027

1028
    // Increment element id for body node
1029
    this->new_element_id();
6✔
1030

1031
    parent.transitions_.insert(
12✔
1032
        parent.transitions_.begin() + index,
6✔
1033
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
1034
    );
1035

1036
    return static_cast<Map&>(*parent.children_.at(index).get());
6✔
1037
};
×
1038

1039
Map& StructuredSDFGBuilder::add_map_after(
12✔
1040
    Sequence& parent,
1041
    ControlFlowNode& child,
1042
    const symbolic::Symbol indvar,
1043
    const symbolic::Condition condition,
1044
    const symbolic::Expression init,
1045
    const symbolic::Expression update,
1046
    const ScheduleType& schedule_type,
1047
    const sdfg::control_flow::Assignments& assignments,
1048
    const DebugInfo& debug_info
1049
) {
1050
    int index = parent.index(child);
12✔
1051
    if (index == -1) {
12✔
1052
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1053
    }
1054

1055
    parent.children_.insert(
24✔
1056
        parent.children_.begin() + index + 1,
12✔
1057
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
12✔
1058
        )
1059
    );
1060

1061
    // Increment element id for body node
1062
    this->new_element_id();
12✔
1063

1064
    parent.transitions_.insert(
24✔
1065
        parent.transitions_.begin() + index + 1,
12✔
1066
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
12✔
1067
    );
1068

1069
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
12✔
1070
};
×
1071

1072
Continue& StructuredSDFGBuilder::
1073
    add_continue(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
14✔
1074
    parent.children_.push_back(std::unique_ptr<Continue>(new Continue(this->new_element_id(), debug_info)));
14✔
1075

1076
    parent.transitions_
28✔
1077
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
1078
        );
1079

1080
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
1081
};
×
1082

1083
Break& StructuredSDFGBuilder::
1084
    add_break(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
16✔
1085
    parent.children_.push_back(std::unique_ptr<Break>(new Break(this->new_element_id(), debug_info)));
16✔
1086

1087
    parent.transitions_
32✔
1088
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
16✔
1089
        );
1090

1091
    return static_cast<Break&>(*parent.children_.back().get());
16✔
1092
};
×
1093

1094
Return& StructuredSDFGBuilder::add_return(
18✔
1095
    Sequence& parent,
1096
    const std::string& data,
1097
    const sdfg::control_flow::Assignments& assignments,
1098
    const DebugInfo& debug_info
1099
) {
1100
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data)));
18✔
1101

1102
    parent.transitions_
36✔
1103
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
18✔
1104
        );
1105

1106
    return static_cast<Return&>(*parent.children_.back().get());
18✔
1107
};
×
1108

1109
Return& StructuredSDFGBuilder::add_constant_return(
×
1110
    Sequence& parent,
1111
    const std::string& data,
1112
    const types::IType& type,
1113
    const sdfg::control_flow::Assignments& assignments,
1114
    const DebugInfo& debug_info
1115
) {
1116
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1117

1118
    parent.transitions_
×
1119
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1120
        );
1121

1122
    return static_cast<Return&>(*parent.children_.back().get());
×
1123
};
×
1124

1125
For& StructuredSDFGBuilder::convert_while(
×
1126
    Sequence& parent,
1127
    While& loop,
1128
    const symbolic::Symbol indvar,
1129
    const symbolic::Condition condition,
1130
    const symbolic::Expression init,
1131
    const symbolic::Expression update
1132
) {
1133
    int index = parent.index(loop);
×
1134
    if (index == -1) {
×
1135
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1136
    }
1137

1138
    auto iter = parent.children_.begin() + index;
×
1139
    auto& new_iter = *parent.children_.insert(
×
1140
        iter + 1,
×
1141
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1142
    );
1143

1144
    // Increment element id for body node
1145
    this->new_element_id();
×
1146

1147
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1148
    this->move_children(loop.root(), for_loop.root());
×
1149

1150
    // Remove while loop
1151
    parent.children_.erase(parent.children_.begin() + index);
×
1152

1153
    return for_loop;
×
1154
};
×
1155

1156
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
9✔
1157
    int index = parent.index(loop);
9✔
1158
    if (index == -1) {
9✔
1159
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1160
    }
1161

1162
    auto iter = parent.children_.begin() + index;
9✔
1163
    auto& new_iter = *parent.children_.insert(
18✔
1164
        iter + 1,
9✔
1165
        std::unique_ptr<Map>(new Map(
18✔
1166
            this->new_element_id(),
9✔
1167
            loop.debug_info(),
9✔
1168
            loop.indvar(),
9✔
1169
            loop.init(),
9✔
1170
            loop.update(),
9✔
1171
            loop.condition(),
9✔
1172
            ScheduleType_Sequential::create()
9✔
1173
        ))
1174
    );
1175

1176
    // Increment element id for body node
1177
    this->new_element_id();
9✔
1178

1179
    auto& map = dynamic_cast<Map&>(*new_iter);
9✔
1180
    this->move_children(loop.root(), map.root());
9✔
1181

1182
    // Remove for loop
1183
    parent.children_.erase(parent.children_.begin() + index);
9✔
1184

1185
    return map;
9✔
1186
};
×
1187

1188
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1189
    if (index >= if_else.conditions_.size()) {
×
1190
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1191
    }
1192
    if_else.conditions_.at(index) = condition;
×
1193
};
×
1194

1195
void StructuredSDFGBuilder::update_loop(
17✔
1196
    StructuredLoop& loop,
1197
    const symbolic::Symbol indvar,
1198
    const symbolic::Condition condition,
1199
    const symbolic::Expression init,
1200
    const symbolic::Expression update
1201
) {
1202
    loop.indvar_ = indvar;
17✔
1203
    loop.condition_ = condition;
17✔
1204
    loop.init_ = init;
17✔
1205
    loop.update_ = update;
17✔
1206
};
17✔
1207

1208
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1209
    map.schedule_type_ = schedule_type;
4✔
1210
}
4✔
1211

1212
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1213
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1214
    while (!queue.empty()) {
2✔
1215
        auto current = queue.front();
2✔
1216
        queue.pop_front();
2✔
1217

1218
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1219
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1220
                if (&sequence_stmt->at(i).first == &node) {
2✔
1221
                    return *sequence_stmt;
2✔
1222
                }
1223
                queue.push_back(&sequence_stmt->at(i).first);
×
1224
            }
×
1225
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1226
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1227
                queue.push_back(&if_else_stmt->at(i).first);
×
1228
            }
×
1229
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1230
            queue.push_back(&while_stmt->root());
×
1231
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1232
            queue.push_back(&loop_stmt->root());
×
1233
        }
×
1234
    }
1235

1236
    return this->structured_sdfg_->root();
×
1237
};
2✔
1238

1239
/***** Section: Dataflow Graph *****/
1240

1241
data_flow::AccessNode& StructuredSDFGBuilder::
1242
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
820✔
1243
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
820✔
1244
    auto res = block.dataflow_->nodes_.insert(
1,640✔
1245
        {vertex,
820✔
1246
         std::unique_ptr<data_flow::AccessNode>(
820✔
1247
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
820✔
1248
         )}
1249
    );
1250

1251
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
820✔
1252
};
×
1253

1254
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
77✔
1255
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1256
) {
1257
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
77✔
1258
    auto res = block.dataflow_->nodes_.insert(
154✔
1259
        {vertex,
77✔
1260
         std::unique_ptr<data_flow::ConstantNode>(
77✔
1261
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
77✔
1262
         )}
1263
    );
1264

1265
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
77✔
1266
};
×
1267

1268

1269
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
314✔
1270
    structured_control_flow::Block& block,
1271
    const data_flow::TaskletCode code,
1272
    const std::string& output,
1273
    const std::vector<std::string>& inputs,
1274
    const DebugInfo& debug_info
1275
) {
1276
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
314✔
1277
    auto res = block.dataflow_->nodes_.insert(
628✔
1278
        {vertex,
314✔
1279
         std::unique_ptr<data_flow::Tasklet>(
314✔
1280
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
314✔
1281
         )}
1282
    );
1283

1284
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
314✔
1285
};
×
1286

1287
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
880✔
1288
    structured_control_flow::Block& block,
1289
    data_flow::DataFlowNode& src,
1290
    const std::string& src_conn,
1291
    data_flow::DataFlowNode& dst,
1292
    const std::string& dst_conn,
1293
    const data_flow::Subset& subset,
1294
    const types::IType& base_type,
1295
    const DebugInfo& debug_info
1296
) {
1297
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
880✔
1298
    auto res = block.dataflow_->edges_.insert(
1,760✔
1299
        {edge.first,
1,760✔
1300
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,760✔
1301
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
880✔
1302
         ))}
1303
    );
1304

1305
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
880✔
1306
#ifndef NDEBUG
1307
    memlet.validate(*this->structured_sdfg_);
880✔
1308
#endif
1309

1310
    return memlet;
880✔
1311
};
×
1312

1313
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
121✔
1314
    structured_control_flow::Block& block,
1315
    data_flow::AccessNode& src,
1316
    data_flow::Tasklet& dst,
1317
    const std::string& dst_conn,
1318
    const data_flow::Subset& subset,
1319
    const types::IType& base_type,
1320
    const DebugInfo& debug_info
1321
) {
1322
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
121✔
1323
};
×
1324

1325
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
113✔
1326
    structured_control_flow::Block& block,
1327
    data_flow::Tasklet& src,
1328
    const std::string& src_conn,
1329
    data_flow::AccessNode& dst,
1330
    const data_flow::Subset& subset,
1331
    const types::IType& base_type,
1332
    const DebugInfo& debug_info
1333
) {
1334
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
113✔
1335
};
×
1336

1337
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
267✔
1338
    structured_control_flow::Block& block,
1339
    data_flow::AccessNode& src,
1340
    data_flow::Tasklet& dst,
1341
    const std::string& dst_conn,
1342
    const data_flow::Subset& subset,
1343
    const DebugInfo& debug_info
1344
) {
1345
    const types::IType* src_type = nullptr;
267✔
1346
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
267✔
1347
        src_type = &cnode->type();
66✔
1348
    } else {
66✔
1349
        src_type = &this->structured_sdfg_->type(src.data());
201✔
1350
    }
1351
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
267✔
1352
    if (base_type.type_id() != types::TypeID::Scalar) {
267✔
1353
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1354
    }
1355
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
267✔
1356
};
×
1357

1358
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
179✔
1359
    structured_control_flow::Block& block,
1360
    data_flow::Tasklet& src,
1361
    const std::string& src_conn,
1362
    data_flow::AccessNode& dst,
1363
    const data_flow::Subset& subset,
1364
    const DebugInfo& debug_info
1365
) {
1366
    auto& dst_type = this->structured_sdfg_->type(dst.data());
179✔
1367
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
179✔
1368
    if (base_type.type_id() != types::TypeID::Scalar) {
179✔
1369
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1370
    }
1371
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
179✔
1372
};
×
1373

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

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

1398
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
37✔
1399
    structured_control_flow::Block& block,
1400
    data_flow::AccessNode& src,
1401
    data_flow::AccessNode& dst,
1402
    const data_flow::Subset& subset,
1403
    const types::IType& base_type,
1404
    const DebugInfo& debug_info
1405
) {
1406
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
37✔
1407
};
×
1408

1409
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
18✔
1410
    structured_control_flow::Block& block,
1411
    data_flow::AccessNode& src,
1412
    data_flow::AccessNode& dst,
1413
    bool derefs_src,
1414
    const types::IType& base_type,
1415
    const DebugInfo& debug_info
1416
) {
1417
    if (derefs_src) {
18✔
1418
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
11✔
1419
    } else {
1420
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
7✔
1421
    }
1422
};
18✔
1423

1424
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
27✔
1425
    auto& graph = block.dataflow();
27✔
1426
    auto e = edge.edge();
27✔
1427
    boost::remove_edge(e, graph.graph_);
27✔
1428
    graph.edges_.erase(e);
27✔
1429
};
27✔
1430

1431
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
23✔
1432
    auto& graph = block.dataflow();
23✔
1433
    auto v = node.vertex();
23✔
1434
    boost::remove_vertex(v, graph.graph_);
23✔
1435
    graph.nodes_.erase(v);
23✔
1436
};
23✔
1437

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

1441
    std::unordered_set<const data_flow::DataFlowNode*> to_delete = {&node};
12✔
1442

1443
    // Delete incoming
1444
    std::list<const data_flow::Memlet*> iedges;
12✔
1445
    for (auto& iedge : graph.in_edges(node)) {
31✔
1446
        iedges.push_back(&iedge);
19✔
1447
    }
1448
    for (auto iedge : iedges) {
31✔
1449
        auto& src = iedge->src();
19✔
1450
        to_delete.insert(&src);
19✔
1451

1452
        auto edge = iedge->edge();
19✔
1453
        graph.edges_.erase(edge);
19✔
1454
        boost::remove_edge(edge, graph.graph_);
19✔
1455
    }
1456

1457
    // Delete outgoing
1458
    std::list<const data_flow::Memlet*> oedges;
12✔
1459
    for (auto& oedge : graph.out_edges(node)) {
24✔
1460
        oedges.push_back(&oedge);
12✔
1461
    }
1462
    for (auto oedge : oedges) {
24✔
1463
        auto& dst = oedge->dst();
12✔
1464
        to_delete.insert(&dst);
12✔
1465

1466
        auto edge = oedge->edge();
12✔
1467
        graph.edges_.erase(edge);
12✔
1468
        boost::remove_edge(edge, graph.graph_);
12✔
1469
    }
1470

1471
    // Delete nodes
1472
    for (auto obsolete_node : to_delete) {
55✔
1473
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
43✔
1474
            auto vertex = obsolete_node->vertex();
43✔
1475
            graph.nodes_.erase(vertex);
43✔
1476
            boost::remove_vertex(vertex, graph.graph_);
43✔
1477
        }
43✔
1478
    }
1479
};
12✔
1480

1481
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
7✔
1482
    auto& graph = block.dataflow();
7✔
1483
    if (graph.out_degree(node) != 0) {
7✔
1484
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1485
    }
1486

1487
    std::list<const data_flow::Memlet*> tmp;
7✔
1488
    std::list<const data_flow::DataFlowNode*> queue = {&node};
7✔
1489
    while (!queue.empty()) {
25✔
1490
        auto current = queue.front();
18✔
1491
        queue.pop_front();
18✔
1492
        if (current != &node) {
18✔
1493
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
11✔
1494
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
4✔
1495
                    continue;
×
1496
                }
1497
            }
4✔
1498
        }
11✔
1499

1500
        tmp.clear();
18✔
1501
        for (auto& iedge : graph.in_edges(*current)) {
29✔
1502
            tmp.push_back(&iedge);
11✔
1503
        }
1504
        for (auto iedge : tmp) {
29✔
1505
            auto& src = iedge->src();
11✔
1506
            queue.push_back(&src);
11✔
1507

1508
            auto edge = iedge->edge();
11✔
1509
            graph.edges_.erase(edge);
11✔
1510
            boost::remove_edge(edge, graph.graph_);
11✔
1511
        }
1512

1513
        auto vertex = current->vertex();
18✔
1514
        graph.nodes_.erase(vertex);
18✔
1515
        boost::remove_vertex(vertex, graph.graph_);
18✔
1516
    }
1517
};
7✔
1518

1519
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
20✔
1520
    auto& to_dataflow = to.dataflow();
20✔
1521

1522
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
20✔
1523
    for (auto& entry : from.nodes_) {
21✔
1524
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1525
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1526
        node_mapping.insert({entry.first, vertex});
1✔
1527
    }
1528

1529
    for (auto& entry : from.edges_) {
20✔
1530
        auto src = node_mapping[entry.second->src().vertex()];
×
1531
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1532

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

1535
        to_dataflow.edges_.insert(
×
1536
            {edge.first,
×
1537
             entry.second->clone(
×
1538
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1539
             )}
1540
        );
1541
    }
1542
};
20✔
1543

1544
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
18✔
1545
    auto& user_graph = source_node.get_parent();
18✔
1546
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
18✔
1547
    if (!block) {
18✔
1548
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1549
    }
1550

1551
    // Merge access nodes if they access the same container on a tasklet
1552
    for (auto& oedge : user_graph.out_edges(source_node)) {
30✔
1553
        if (auto* tasklet = dynamic_cast<data_flow::Tasklet*>(&oedge.dst())) {
12✔
1554
            std::unordered_set<data_flow::Memlet*> iedges;
7✔
1555
            for (auto& iedge : user_graph.in_edges(*tasklet)) {
16✔
1556
                iedges.insert(&iedge);
9✔
1557
            }
1558
            for (auto* iedge : iedges) {
16✔
1559
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
9✔
1560
                    continue;
×
1561
                }
1562
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
9✔
1563
                if (access_node == &source_node || access_node->data() != source_node.data()) {
9✔
1564
                    continue;
8✔
1565
                }
1566
                this->add_memlet(
1✔
1567
                    *block,
1✔
1568
                    source_node,
1✔
1569
                    iedge->src_conn(),
1✔
1570
                    *tasklet,
1✔
1571
                    iedge->dst_conn(),
1✔
1572
                    iedge->subset(),
1✔
1573
                    iedge->base_type(),
1✔
1574
                    iedge->debug_info()
1✔
1575
                );
1576
                this->remove_memlet(*block, *iedge);
1✔
1577
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
1✔
1578
            }
1579
        }
7✔
1580
    }
1581
}
18✔
1582

1583
} // namespace builder
1584
} // 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