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

daisytuner / sdfglib / 19435487175

17 Nov 2025 03:45PM UTC coverage: 62.157% (-0.01%) from 62.169%
19435487175

push

github

web-flow
Merge pull request #351 from daisytuner/loop-dections

adds safe guard for loop detection

10 of 16 new or added lines in 3 files covered. (62.5%)

1 existing line in 1 file now uncovered.

11077 of 17821 relevant lines covered (62.16%)

112.5 hits per line

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

67.5
/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
    this->current_traverse_loop_ = nullptr;
4✔
101
    std::unordered_set<const control_flow::State*> visited;
4✔
102
    this->traverse_with_loop_detection(sdfg, root, start_state, nullptr, continues, breaks, pdom_tree, visited);
4✔
103
};
4✔
104

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

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

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

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

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

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

172
        // 3. Add while loop
173
        While& loop = this->add_while(scope, {}, dbg_info);
1✔
174
        auto last_loop_ = this->current_traverse_loop_;
1✔
175
        this->current_traverse_loop_ = &loop;
1✔
176

177
        std::unordered_set<const control_flow::State*> loop_visited(visited);
1✔
178
        this->traverse_without_loop_detection(
1✔
179
            sdfg, loop.root(), current, exit_state, continues, exit_edges, pdom_tree, loop_visited
1✔
180
        );
181
        this->current_traverse_loop_ = last_loop_;
1✔
182

183
        this->traverse_with_loop_detection(sdfg, scope, exit_state, end, continues, breaks, pdom_tree, visited);
1✔
184
    } else {
1✔
185
        this->traverse_without_loop_detection(sdfg, scope, current, end, continues, breaks, pdom_tree, visited);
7✔
186
    }
187
};
9✔
188

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

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

212
        if (visited.find(curr) != visited.end()) {
17✔
213
            throw UnstructuredControlFlowException();
×
214
        }
215
        visited.insert(curr);
17✔
216

217
        auto out_edges = sdfg.out_edges(*curr);
17✔
218
        auto out_degree = sdfg.out_degree(*curr);
17✔
219

220
        // Case 1: Sink node
221
        if (out_degree == 0) {
17✔
222
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
4✔
223

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

236
            continue;
4✔
237
        }
238

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

247
            if (continues.find(&oedge) != continues.end()) {
10✔
NEW
248
                if (this->current_traverse_loop_ == nullptr) {
×
NEW
249
                    throw UnstructuredControlFlowException();
×
250
                }
UNCOV
251
                this->add_continue(scope, {}, oedge.debug_info());
×
252
            } else if (breaks.find(&oedge) != breaks.end()) {
10✔
NEW
253
                if (this->current_traverse_loop_ == nullptr) {
×
NEW
254
                    throw UnstructuredControlFlowException();
×
255
                }
256
                this->add_break(scope, {}, oedge.debug_info());
×
257
            } else {
×
258
                bool starts_loop = false;
10✔
259
                for (auto& iedge : sdfg.in_edges(oedge.dst())) {
23✔
260
                    if (continues.find(&iedge) != continues.end()) {
13✔
261
                        starts_loop = true;
×
262
                        break;
×
263
                    }
264
                }
265
                if (!starts_loop) {
10✔
266
                    queue.push_back(&oedge.dst());
10✔
267
                } else {
10✔
268
                    this->traverse_with_loop_detection(
×
269
                        sdfg, scope, &oedge.dst(), end, continues, breaks, pdom_tree, visited
×
270
                    );
271
                }
272
            }
273
            continue;
10✔
274
        }
275

276
        // Case 3: Branches
277
        if (out_degree > 1) {
3✔
278
            this->add_block(scope, curr->dataflow(), {}, curr->debug_info());
3✔
279

280
            std::vector<const InterstateEdge*> out_edges_vec;
3✔
281
            for (auto& edge : out_edges) {
9✔
282
                out_edges_vec.push_back(&edge);
6✔
283
            }
284

285
            // Best-effort approach: Find end of if-else
286
            // If not found, the branches may repeat paths yielding a large SDFG
287
            const control_flow::State* local_end = this->find_end_of_if_else(sdfg, curr, out_edges_vec, pdom_tree);
3✔
288
            if (local_end == nullptr) {
3✔
289
                local_end = end;
×
290
            }
×
291

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

296
                auto& branch = this->add_case(if_else, out_edge->condition(), out_edge->debug_info());
6✔
297
                if (!out_edge->assignments().empty()) {
6✔
298
                    this->add_block(branch, out_edge->assignments(), out_edge->debug_info());
2✔
299
                }
2✔
300
                if (continues.find(out_edge) != continues.end()) {
6✔
301
                    if (this->current_traverse_loop_ == nullptr) {
1✔
NEW
302
                        throw UnstructuredControlFlowException();
×
303
                    }
304
                    this->add_continue(branch, {}, out_edge->debug_info());
1✔
305
                } else if (breaks.find(out_edge) != breaks.end()) {
6✔
306
                    if (this->current_traverse_loop_ == nullptr) {
1✔
NEW
307
                        throw UnstructuredControlFlowException();
×
308
                    }
309
                    this->add_break(branch, {}, out_edge->debug_info());
1✔
310
                } else {
1✔
311
                    std::unordered_set<const control_flow::State*> branch_visited(visited);
4✔
312
                    this->traverse_with_loop_detection(
4✔
313
                        sdfg, branch, &out_edge->dst(), local_end, continues, breaks, pdom_tree, branch_visited
4✔
314
                    );
315
                }
4✔
316
            }
6✔
317

318
            if (local_end != end) {
3✔
319
                bool starts_loop = false;
2✔
320
                for (auto& iedge : sdfg.in_edges(*local_end)) {
6✔
321
                    if (continues.find(&iedge) != continues.end()) {
4✔
322
                        starts_loop = true;
×
323
                        break;
×
324
                    }
325
                }
326
                if (!starts_loop) {
2✔
327
                    queue.push_back(local_end);
2✔
328
                } else {
2✔
329
                    this->traverse_with_loop_detection(sdfg, scope, local_end, end, continues, breaks, pdom_tree, visited);
×
330
                }
331
            }
2✔
332
            continue;
333
        }
3✔
334
    }
335
}
8✔
336

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

339
StructuredSDFGBuilder::StructuredSDFGBuilder(StructuredSDFG& sdfg)
×
340
    : FunctionBuilder(), structured_sdfg_(&sdfg, owned(false)) {};
×
341

342
StructuredSDFGBuilder::StructuredSDFGBuilder(std::unique_ptr<StructuredSDFG>& sdfg)
92✔
343
    : FunctionBuilder(), structured_sdfg_(sdfg.release(), owned(true)) {};
92✔
344

345
StructuredSDFGBuilder::StructuredSDFGBuilder(const std::string& name, FunctionType type)
448✔
346
    : FunctionBuilder(), structured_sdfg_(new StructuredSDFG(name, type), owned(true)) {};
448✔
347

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

351
StructuredSDFGBuilder::StructuredSDFGBuilder(SDFG& sdfg)
4✔
352
    : FunctionBuilder(),
4✔
353
      structured_sdfg_(new StructuredSDFG(sdfg.name(), sdfg.type(), sdfg.return_type()), owned(true)) {
4✔
354
    for (auto& entry : sdfg.structures_) {
4✔
355
        this->structured_sdfg_->structures_.insert({entry.first, entry.second->clone()});
×
356
    }
357

358
    for (auto& entry : sdfg.containers_) {
11✔
359
        this->structured_sdfg_->containers_.insert({entry.first, entry.second->clone()});
7✔
360
    }
361

362
    for (auto& arg : sdfg.arguments_) {
6✔
363
        this->structured_sdfg_->arguments_.push_back(arg);
2✔
364
    }
365

366
    for (auto& ext : sdfg.externals_) {
5✔
367
        this->structured_sdfg_->externals_.push_back(ext);
1✔
368
        this->structured_sdfg_->externals_linkage_types_[ext] = sdfg.linkage_type(ext);
1✔
369
    }
370

371
    for (auto& entry : sdfg.assumptions_) {
9✔
372
        this->structured_sdfg_->assumptions_.insert({entry.first, entry.second});
5✔
373
    }
374

375
    for (auto& entry : sdfg.metadata_) {
6✔
376
        this->structured_sdfg_->metadata_[entry.first] = entry.second;
2✔
377
    }
378

379
    this->traverse(sdfg);
4✔
380
};
4✔
381

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

384
std::unique_ptr<StructuredSDFG> StructuredSDFGBuilder::move() {
278✔
385
#ifndef NDEBUG
386
    this->structured_sdfg_->validate();
278✔
387
#endif
388

389
    if (!structured_sdfg_.get_deleter().should_delete_) {
278✔
390
        throw InvalidSDFGException("StructuredSDFGBuilder: Cannot move a non-owned SDFG");
×
391
    }
392

393
    return std::move(std::unique_ptr<StructuredSDFG>(structured_sdfg_.release()));
278✔
394
};
×
395

396
void StructuredSDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
397
    FunctionBuilder::rename_container(old_name, new_name);
×
398

399
    this->structured_sdfg_->root_->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
400
};
×
401

402
Element* StructuredSDFGBuilder::find_element_by_id(const size_t& element_id) const {
13✔
403
    auto& sdfg = this->subject();
13✔
404
    std::list<Element*> queue = {&sdfg.root()};
13✔
405
    while (!queue.empty()) {
55✔
406
        auto current = queue.front();
55✔
407
        queue.pop_front();
55✔
408

409
        if (current->element_id() == element_id) {
55✔
410
            return current;
13✔
411
        }
412

413
        if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(current)) {
42✔
414
            auto& dataflow = block_stmt->dataflow();
×
415
            for (auto& node : dataflow.nodes()) {
×
416
                queue.push_back(&node);
×
417
            }
418
            for (auto& edge : dataflow.edges()) {
×
419
                queue.push_back(&edge);
×
420
            }
421
        } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
42✔
422
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
44✔
423
                queue.push_back(&sequence_stmt->at(i).first);
22✔
424
                queue.push_back(&sequence_stmt->at(i).second);
22✔
425
            }
22✔
426
        } else if (dynamic_cast<structured_control_flow::Return*>(current)) {
42✔
427
            // Do nothing
428
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
20✔
429
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
430
                queue.push_back(&if_else_stmt->at(i).first);
×
431
            }
×
432
        } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(current)) {
20✔
433
            queue.push_back(&for_stmt->root());
×
434
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
20✔
435
            queue.push_back(&while_stmt->root());
×
436
        } else if (dynamic_cast<structured_control_flow::Continue*>(current)) {
20✔
437
            // Do nothing
438
        } else if (dynamic_cast<structured_control_flow::Break*>(current)) {
20✔
439
            // Do nothing
440
        } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(current)) {
20✔
441
            queue.push_back(&map_stmt->root());
10✔
442
        }
10✔
443
    }
444

445
    return nullptr;
×
446
};
13✔
447

448
Sequence& StructuredSDFGBuilder::
449
    add_sequence(Sequence& parent, const sdfg::control_flow::Assignments& assignments, const DebugInfo& debug_info) {
30✔
450
    parent.children_.push_back(std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info)));
30✔
451

452
    parent.transitions_
60✔
453
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
30✔
454
        );
455

456
    return static_cast<Sequence&>(*parent.children_.back().get());
30✔
457
};
×
458

459
Sequence& StructuredSDFGBuilder::add_sequence_before(
5✔
460
    Sequence& parent,
461
    ControlFlowNode& child,
462
    const sdfg::control_flow::Assignments& assignments,
463
    const DebugInfo& debug_info
464
) {
465
    int index = parent.index(child);
5✔
466
    if (index == -1) {
5✔
467
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
468
    }
469

470
    parent.children_.insert(
10✔
471
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
5✔
472
    );
473

474
    parent.transitions_.insert(
10✔
475
        parent.transitions_.begin() + index,
5✔
476
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
5✔
477
    );
478

479
    return static_cast<Sequence&>(*parent.children_.at(index).get());
5✔
480
};
×
481

482
Sequence& StructuredSDFGBuilder::add_sequence_after(
×
483
    Sequence& parent,
484
    ControlFlowNode& child,
485
    const sdfg::control_flow::Assignments& assignments,
486
    const DebugInfo& debug_info
487
) {
488
    int index = parent.index(child);
×
489
    if (index == -1) {
×
490
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
491
    }
492

493
    parent.children_.insert(
×
494
        parent.children_.begin() + index + 1,
×
495
        std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
496
    );
497

498
    parent.transitions_.insert(
×
499
        parent.transitions_.begin() + index + 1,
×
500
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
501
    );
502

503
    return static_cast<Sequence&>(*parent.children_.at(index + 1).get());
×
504
};
×
505

506
std::pair<Sequence&, Transition&> StructuredSDFGBuilder::
507
    add_sequence_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
508
    int index = parent.index(child);
×
509
    if (index == -1) {
×
510
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
511
    }
512

513
    parent.children_.insert(
×
514
        parent.children_.begin() + index, std::unique_ptr<Sequence>(new Sequence(this->new_element_id(), debug_info))
×
515
    );
516

517
    parent.transitions_.insert(
×
518
        parent.transitions_.begin() + index,
×
519
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
520
    );
521

522
    auto new_entry = parent.at(index);
×
523
    auto& new_block = dynamic_cast<structured_control_flow::Sequence&>(new_entry.first);
×
524

525
    return {new_block, new_entry.second};
×
526
};
×
527

528
void StructuredSDFGBuilder::remove_child(Sequence& parent, size_t index) {
31✔
529
    parent.children_.erase(parent.children_.begin() + index);
31✔
530
    parent.transitions_.erase(parent.transitions_.begin() + index);
31✔
531
};
31✔
532

533
void StructuredSDFGBuilder::remove_children(Sequence& parent) {
×
534
    parent.children_.clear();
×
535
    parent.transitions_.clear();
×
536
};
×
537

538
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target) {
10✔
539
    this->move_child(source, source_index, target, target.size());
10✔
540
};
10✔
541

542
void StructuredSDFGBuilder::move_child(Sequence& source, size_t source_index, Sequence& target, size_t target_index) {
39✔
543
    auto node_ptr = std::move(source.children_.at(source_index));
39✔
544
    auto trans_ptr = std::move(source.transitions_.at(source_index));
39✔
545
    source.children_.erase(source.children_.begin() + source_index);
39✔
546
    source.transitions_.erase(source.transitions_.begin() + source_index);
39✔
547

548
    trans_ptr->parent_ = &target;
39✔
549
    target.children_.insert(target.children_.begin() + target_index, std::move(node_ptr));
39✔
550
    target.transitions_.insert(target.transitions_.begin() + target_index, std::move(trans_ptr));
39✔
551
};
39✔
552

553
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target) {
24✔
554
    this->move_children(source, target, target.size());
24✔
555
};
24✔
556

557
void StructuredSDFGBuilder::move_children(Sequence& source, Sequence& target, size_t target_index) {
24✔
558
    target.children_.insert(
48✔
559
        target.children_.begin() + target_index,
24✔
560
        std::make_move_iterator(source.children_.begin()),
24✔
561
        std::make_move_iterator(source.children_.end())
24✔
562
    );
563
    target.transitions_.insert(
48✔
564
        target.transitions_.begin() + target_index,
24✔
565
        std::make_move_iterator(source.transitions_.begin()),
24✔
566
        std::make_move_iterator(source.transitions_.end())
24✔
567
    );
568
    for (auto& trans : target.transitions_) {
55✔
569
        trans->parent_ = &target;
31✔
570
    }
571
    source.children_.clear();
24✔
572
    source.transitions_.clear();
24✔
573
};
24✔
574

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

579
    parent.transitions_
1,072✔
580
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
536✔
581
        );
582

583
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
536✔
584
    (*new_block.dataflow_).parent_ = &new_block;
536✔
585

586
    return new_block;
536✔
587
};
×
588

589
Block& StructuredSDFGBuilder::add_block(
20✔
590
    Sequence& parent,
591
    const data_flow::DataFlowGraph& data_flow_graph,
592
    const sdfg::control_flow::Assignments& assignments,
593
    const DebugInfo& debug_info
594
) {
595
    parent.children_.push_back(std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
20✔
596

597
    parent.transitions_
40✔
598
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
20✔
599
        );
600

601
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.back());
20✔
602
    (*new_block.dataflow_).parent_ = &new_block;
20✔
603

604
    this->add_dataflow(data_flow_graph, new_block);
20✔
605

606
    return new_block;
20✔
607
};
×
608

609
Block& StructuredSDFGBuilder::add_block_before(
14✔
610
    Sequence& parent,
611
    ControlFlowNode& child,
612
    const sdfg::control_flow::Assignments& assignments,
613
    const DebugInfo& debug_info
614
) {
615
    int index = parent.index(child);
14✔
616
    if (index == -1) {
14✔
617
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
618
    }
619

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

623
    parent.transitions_.insert(
28✔
624
        parent.transitions_.begin() + index,
14✔
625
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
626
    );
627

628
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
14✔
629
    (*new_block.dataflow_).parent_ = &new_block;
14✔
630

631
    return new_block;
14✔
632
};
×
633

634
Block& StructuredSDFGBuilder::add_block_before(
×
635
    Sequence& parent,
636
    ControlFlowNode& child,
637
    data_flow::DataFlowGraph& data_flow_graph,
638
    const sdfg::control_flow::Assignments& assignments,
639
    const DebugInfo& debug_info
640
) {
641
    int index = parent.index(child);
×
642
    if (index == -1) {
×
643
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
644
    }
645

646
    parent.children_
×
647
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
648

649
    parent.transitions_.insert(
×
650
        parent.transitions_.begin() + index,
×
651
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
652
    );
653

654
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index));
×
655
    (*new_block.dataflow_).parent_ = &new_block;
×
656
    this->add_dataflow(data_flow_graph, new_block);
×
657

658
    return new_block;
×
659
};
×
660

661
Block& StructuredSDFGBuilder::add_block_after(
3✔
662
    Sequence& parent,
663
    ControlFlowNode& child,
664
    const sdfg::control_flow::Assignments& assignments,
665
    const DebugInfo& debug_info
666
) {
667
    int index = parent.index(child);
3✔
668
    if (index == -1) {
3✔
669
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
670
    }
671

672
    parent.children_.insert(
6✔
673
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
3✔
674
    );
675

676
    parent.transitions_.insert(
6✔
677
        parent.transitions_.begin() + index + 1,
3✔
678
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
3✔
679
    );
680

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

684
    return new_block;
3✔
685
};
×
686

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

699
    parent.children_.insert(
×
700
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
701
    );
702

703
    parent.transitions_.insert(
×
704
        parent.transitions_.begin() + index + 1,
×
705
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
706
    );
707

708
    auto& new_block = static_cast<structured_control_flow::Block&>(*parent.children_.at(index + 1));
×
709
    (*new_block.dataflow_).parent_ = &new_block;
×
710
    this->add_dataflow(data_flow_graph, new_block);
×
711

712
    return new_block;
×
713
};
×
714

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

722
    parent.children_
×
723
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
724

725
    parent.transitions_.insert(
×
726
        parent.transitions_.begin() + index,
×
727
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
728
    );
729

730
    auto new_entry = parent.at(index);
×
731
    auto& new_block = static_cast<structured_control_flow::Block&>(new_entry.first);
×
732
    (*new_block.dataflow_).parent_ = &new_block;
×
733

734
    return {new_block, new_entry.second};
×
735
};
×
736

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

745
    parent.children_
×
746
        .insert(parent.children_.begin() + index, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info)));
×
747

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

753
    auto new_entry = parent.at(index);
×
754
    auto& new_block = dynamic_cast<structured_control_flow::Block&>(new_entry.first);
×
755
    (*new_block.dataflow_).parent_ = &new_block;
×
756

757
    this->add_dataflow(data_flow_graph, new_block);
×
758

759
    return {new_block, new_entry.second};
×
760
};
×
761

762
std::pair<Block&, Transition&> StructuredSDFGBuilder::
763
    add_block_after(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_.insert(
×
770
        parent.children_.begin() + index + 1, std::unique_ptr<Block>(new Block(this->new_element_id(), debug_info))
×
771
    );
772

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

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

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

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

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

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

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

806
    this->add_dataflow(data_flow_graph, new_block);
×
807

808
    return {new_block, new_entry.second};
×
809
};
×
810

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

815
    parent.transitions_
96✔
816
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
48✔
817
        );
818

819
    return static_cast<IfElse&>(*parent.children_.back().get());
48✔
820
};
×
821

822
IfElse& StructuredSDFGBuilder::add_if_else_before(
1✔
823
    Sequence& parent,
824
    ControlFlowNode& child,
825
    const sdfg::control_flow::Assignments& assignments,
826
    const DebugInfo& debug_info
827
) {
828
    int index = parent.index(child);
1✔
829
    if (index == -1) {
1✔
830
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
831
    }
832

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

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

841
    return static_cast<IfElse&>(*parent.children_.at(index));
1✔
842
};
×
843

844
IfElse& StructuredSDFGBuilder::add_if_else_after(
×
845
    Sequence& parent,
846
    ControlFlowNode& child,
847
    const sdfg::control_flow::Assignments& assignments,
848
    const DebugInfo& debug_info
849
) {
850
    int index = parent.index(child);
×
851
    if (index == -1) {
×
852
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
853
    }
854

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

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

864
    return static_cast<IfElse&>(*parent.children_.at(index + 1));
×
865
};
×
866

867
std::pair<IfElse&, Transition&> StructuredSDFGBuilder::
868
    add_if_else_before(Sequence& parent, ControlFlowNode& child, const DebugInfo& debug_info) {
×
869
    int index = parent.index(child);
×
870
    if (index == -1) {
×
871
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
872
    }
873

874
    parent.children_
×
875
        .insert(parent.children_.begin() + index, std::unique_ptr<IfElse>(new IfElse(this->new_element_id(), debug_info)));
×
876

877
    parent.transitions_.insert(
×
878
        parent.transitions_.begin() + index,
×
879
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent))
×
880
    );
881

882
    auto new_entry = parent.at(index);
×
883
    auto& new_block = dynamic_cast<structured_control_flow::IfElse&>(new_entry.first);
×
884

885
    return {new_block, new_entry.second};
×
886
};
×
887

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

891
    scope.conditions_.push_back(cond);
82✔
892
    return *scope.cases_.back();
82✔
893
};
×
894

895
void StructuredSDFGBuilder::remove_case(IfElse& scope, size_t index, const DebugInfo& debug_info) {
×
896
    scope.cases_.erase(scope.cases_.begin() + index);
×
897
    scope.conditions_.erase(scope.conditions_.begin() + index);
×
898
};
×
899

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

904
    // Increment element id for body node
905
    this->new_element_id();
36✔
906

907
    parent.transitions_
72✔
908
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
36✔
909
        );
910

911
    return static_cast<While&>(*parent.children_.back().get());
36✔
912
};
×
913

914
For& StructuredSDFGBuilder::add_for(
178✔
915
    Sequence& parent,
916
    const symbolic::Symbol indvar,
917
    const symbolic::Condition condition,
918
    const symbolic::Expression init,
919
    const symbolic::Expression update,
920
    const sdfg::control_flow::Assignments& assignments,
921
    const DebugInfo& debug_info
922
) {
923
    parent.children_
356✔
924
        .push_back(std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition)));
178✔
925

926
    // Increment element id for body node
927
    this->new_element_id();
178✔
928

929
    parent.transitions_
356✔
930
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
178✔
931
        );
932

933
    return static_cast<For&>(*parent.children_.back().get());
178✔
934
};
×
935

936
For& StructuredSDFGBuilder::add_for_before(
6✔
937
    Sequence& parent,
938
    ControlFlowNode& child,
939
    const symbolic::Symbol indvar,
940
    const symbolic::Condition condition,
941
    const symbolic::Expression init,
942
    const symbolic::Expression update,
943
    const sdfg::control_flow::Assignments& assignments,
944
    const DebugInfo& debug_info
945
) {
946
    int index = parent.index(child);
6✔
947
    if (index == -1) {
6✔
948
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
949
    }
950

951
    parent.children_.insert(
12✔
952
        parent.children_.begin() + index,
6✔
953
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
6✔
954
    );
955

956
    // Increment element id for body node
957
    this->new_element_id();
6✔
958

959
    parent.transitions_.insert(
12✔
960
        parent.transitions_.begin() + index,
6✔
961
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
962
    );
963

964
    return static_cast<For&>(*parent.children_.at(index).get());
6✔
965
};
×
966

967
For& StructuredSDFGBuilder::add_for_after(
2✔
968
    Sequence& parent,
969
    ControlFlowNode& child,
970
    const symbolic::Symbol indvar,
971
    const symbolic::Condition condition,
972
    const symbolic::Expression init,
973
    const symbolic::Expression update,
974
    const sdfg::control_flow::Assignments& assignments,
975
    const DebugInfo& debug_info
976
) {
977
    int index = parent.index(child);
2✔
978
    if (index == -1) {
2✔
979
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
980
    }
981

982
    parent.children_.insert(
4✔
983
        parent.children_.begin() + index + 1,
2✔
984
        std::unique_ptr<For>(new For(this->new_element_id(), debug_info, indvar, init, update, condition))
2✔
985
    );
986

987
    // Increment element id for body node
988
    this->new_element_id();
2✔
989

990
    parent.transitions_.insert(
4✔
991
        parent.transitions_.begin() + index + 1,
2✔
992
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
2✔
993
    );
994

995
    return static_cast<For&>(*parent.children_.at(index + 1).get());
2✔
996
};
×
997

998
Map& StructuredSDFGBuilder::add_map(
47✔
999
    Sequence& parent,
1000
    const symbolic::Symbol indvar,
1001
    const symbolic::Condition condition,
1002
    const symbolic::Expression init,
1003
    const symbolic::Expression update,
1004
    const ScheduleType& schedule_type,
1005
    const sdfg::control_flow::Assignments& assignments,
1006
    const DebugInfo& debug_info
1007
) {
1008
    parent.children_
94✔
1009
        .push_back(std::unique_ptr<
47✔
1010
                   Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)));
47✔
1011

1012
    // Increment element id for body node
1013
    this->new_element_id();
47✔
1014

1015
    parent.transitions_
94✔
1016
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
47✔
1017
        );
1018

1019
    return static_cast<Map&>(*parent.children_.back().get());
47✔
1020
};
×
1021

1022
Map& StructuredSDFGBuilder::add_map_before(
6✔
1023
    Sequence& parent,
1024
    ControlFlowNode& child,
1025
    const symbolic::Symbol indvar,
1026
    const symbolic::Condition condition,
1027
    const symbolic::Expression init,
1028
    const symbolic::Expression update,
1029
    const ScheduleType& schedule_type,
1030
    const sdfg::control_flow::Assignments& assignments,
1031
    const DebugInfo& debug_info
1032
) {
1033
    int index = parent.index(child);
6✔
1034
    if (index == -1) {
6✔
1035
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1036
    }
1037

1038
    parent.children_.insert(
12✔
1039
        parent.children_.begin() + index,
6✔
1040
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
6✔
1041
        )
1042
    );
1043

1044
    // Increment element id for body node
1045
    this->new_element_id();
6✔
1046

1047
    parent.transitions_.insert(
12✔
1048
        parent.transitions_.begin() + index,
6✔
1049
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
6✔
1050
    );
1051

1052
    return static_cast<Map&>(*parent.children_.at(index).get());
6✔
1053
};
×
1054

1055
Map& StructuredSDFGBuilder::add_map_after(
12✔
1056
    Sequence& parent,
1057
    ControlFlowNode& child,
1058
    const symbolic::Symbol indvar,
1059
    const symbolic::Condition condition,
1060
    const symbolic::Expression init,
1061
    const symbolic::Expression update,
1062
    const ScheduleType& schedule_type,
1063
    const sdfg::control_flow::Assignments& assignments,
1064
    const DebugInfo& debug_info
1065
) {
1066
    int index = parent.index(child);
12✔
1067
    if (index == -1) {
12✔
1068
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1069
    }
1070

1071
    parent.children_.insert(
24✔
1072
        parent.children_.begin() + index + 1,
12✔
1073
        std::unique_ptr<Map>(new Map(this->new_element_id(), debug_info, indvar, init, update, condition, schedule_type)
12✔
1074
        )
1075
    );
1076

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

1080
    parent.transitions_.insert(
24✔
1081
        parent.transitions_.begin() + index + 1,
12✔
1082
        std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
12✔
1083
    );
1084

1085
    return static_cast<Map&>(*parent.children_.at(index + 1).get());
12✔
1086
};
×
1087

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

1092
    parent.transitions_
28✔
1093
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
14✔
1094
        );
1095

1096
    return static_cast<Continue&>(*parent.children_.back().get());
14✔
1097
};
×
1098

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

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

1107
    return static_cast<Break&>(*parent.children_.back().get());
16✔
1108
};
×
1109

1110
Return& StructuredSDFGBuilder::add_return(
18✔
1111
    Sequence& parent,
1112
    const std::string& data,
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)));
18✔
1117

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

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

1125
Return& StructuredSDFGBuilder::add_constant_return(
×
1126
    Sequence& parent,
1127
    const std::string& data,
1128
    const types::IType& type,
1129
    const sdfg::control_flow::Assignments& assignments,
1130
    const DebugInfo& debug_info
1131
) {
1132
    parent.children_.push_back(std::unique_ptr<Return>(new Return(this->new_element_id(), debug_info, data, type)));
×
1133

1134
    parent.transitions_
×
1135
        .push_back(std::unique_ptr<Transition>(new Transition(this->new_element_id(), debug_info, parent, assignments))
×
1136
        );
1137

1138
    return static_cast<Return&>(*parent.children_.back().get());
×
1139
};
×
1140

1141
For& StructuredSDFGBuilder::convert_while(
×
1142
    Sequence& parent,
1143
    While& loop,
1144
    const symbolic::Symbol indvar,
1145
    const symbolic::Condition condition,
1146
    const symbolic::Expression init,
1147
    const symbolic::Expression update
1148
) {
1149
    int index = parent.index(loop);
×
1150
    if (index == -1) {
×
1151
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1152
    }
1153

1154
    auto iter = parent.children_.begin() + index;
×
1155
    auto& new_iter = *parent.children_.insert(
×
1156
        iter + 1,
×
1157
        std::unique_ptr<For>(new For(this->new_element_id(), loop.debug_info(), indvar, init, update, condition))
×
1158
    );
1159

1160
    // Increment element id for body node
1161
    this->new_element_id();
×
1162

1163
    auto& for_loop = dynamic_cast<For&>(*new_iter);
×
1164
    this->move_children(loop.root(), for_loop.root());
×
1165

1166
    // Remove while loop
1167
    parent.children_.erase(parent.children_.begin() + index);
×
1168

1169
    return for_loop;
×
1170
};
×
1171

1172
Map& StructuredSDFGBuilder::convert_for(Sequence& parent, For& loop) {
9✔
1173
    int index = parent.index(loop);
9✔
1174
    if (index == -1) {
9✔
1175
        throw InvalidSDFGException("StructuredSDFGBuilder: Child not found");
×
1176
    }
1177

1178
    auto iter = parent.children_.begin() + index;
9✔
1179
    auto& new_iter = *parent.children_.insert(
18✔
1180
        iter + 1,
9✔
1181
        std::unique_ptr<Map>(new Map(
18✔
1182
            this->new_element_id(),
9✔
1183
            loop.debug_info(),
9✔
1184
            loop.indvar(),
9✔
1185
            loop.init(),
9✔
1186
            loop.update(),
9✔
1187
            loop.condition(),
9✔
1188
            ScheduleType_Sequential::create()
9✔
1189
        ))
1190
    );
1191

1192
    // Increment element id for body node
1193
    this->new_element_id();
9✔
1194

1195
    auto& map = dynamic_cast<Map&>(*new_iter);
9✔
1196
    this->move_children(loop.root(), map.root());
9✔
1197

1198
    // Remove for loop
1199
    parent.children_.erase(parent.children_.begin() + index);
9✔
1200

1201
    return map;
9✔
1202
};
×
1203

1204
void StructuredSDFGBuilder::update_if_else_condition(IfElse& if_else, size_t index, const symbolic::Condition condition) {
×
1205
    if (index >= if_else.conditions_.size()) {
×
1206
        throw InvalidSDFGException("StructuredSDFGBuilder: Index out of range");
×
1207
    }
1208
    if_else.conditions_.at(index) = condition;
×
1209
};
×
1210

1211
void StructuredSDFGBuilder::update_loop(
17✔
1212
    StructuredLoop& loop,
1213
    const symbolic::Symbol indvar,
1214
    const symbolic::Condition condition,
1215
    const symbolic::Expression init,
1216
    const symbolic::Expression update
1217
) {
1218
    loop.indvar_ = indvar;
17✔
1219
    loop.condition_ = condition;
17✔
1220
    loop.init_ = init;
17✔
1221
    loop.update_ = update;
17✔
1222
};
17✔
1223

1224
void StructuredSDFGBuilder::update_schedule_type(Map& map, const ScheduleType& schedule_type) {
4✔
1225
    map.schedule_type_ = schedule_type;
4✔
1226
}
4✔
1227

1228
Sequence& StructuredSDFGBuilder::parent(const ControlFlowNode& node) {
2✔
1229
    std::list<structured_control_flow::ControlFlowNode*> queue = {&this->structured_sdfg_->root()};
2✔
1230
    while (!queue.empty()) {
2✔
1231
        auto current = queue.front();
2✔
1232
        queue.pop_front();
2✔
1233

1234
        if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(current)) {
2✔
1235
            for (size_t i = 0; i < sequence_stmt->size(); i++) {
2✔
1236
                if (&sequence_stmt->at(i).first == &node) {
2✔
1237
                    return *sequence_stmt;
2✔
1238
                }
1239
                queue.push_back(&sequence_stmt->at(i).first);
×
1240
            }
×
1241
        } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(current)) {
×
1242
            for (size_t i = 0; i < if_else_stmt->size(); i++) {
×
1243
                queue.push_back(&if_else_stmt->at(i).first);
×
1244
            }
×
1245
        } else if (auto while_stmt = dynamic_cast<structured_control_flow::While*>(current)) {
×
1246
            queue.push_back(&while_stmt->root());
×
1247
        } else if (auto loop_stmt = dynamic_cast<structured_control_flow::StructuredLoop*>(current)) {
×
1248
            queue.push_back(&loop_stmt->root());
×
1249
        }
×
1250
    }
1251

1252
    return this->structured_sdfg_->root();
×
1253
};
2✔
1254

1255
/***** Section: Dataflow Graph *****/
1256

1257
data_flow::AccessNode& StructuredSDFGBuilder::
1258
    add_access(structured_control_flow::Block& block, const std::string& data, const DebugInfo& debug_info) {
820✔
1259
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
820✔
1260
    auto res = block.dataflow_->nodes_.insert(
1,640✔
1261
        {vertex,
820✔
1262
         std::unique_ptr<data_flow::AccessNode>(
820✔
1263
             new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data)
820✔
1264
         )}
1265
    );
1266

1267
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
820✔
1268
};
×
1269

1270
data_flow::ConstantNode& StructuredSDFGBuilder::add_constant(
77✔
1271
    structured_control_flow::Block& block, const std::string& data, const types::IType& type, const DebugInfo& debug_info
1272
) {
1273
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
77✔
1274
    auto res = block.dataflow_->nodes_.insert(
154✔
1275
        {vertex,
77✔
1276
         std::unique_ptr<data_flow::ConstantNode>(
77✔
1277
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, block.dataflow(), data, type)
77✔
1278
         )}
1279
    );
1280

1281
    return dynamic_cast<data_flow::ConstantNode&>(*(res.first->second));
77✔
1282
};
×
1283

1284

1285
data_flow::Tasklet& StructuredSDFGBuilder::add_tasklet(
314✔
1286
    structured_control_flow::Block& block,
1287
    const data_flow::TaskletCode code,
1288
    const std::string& output,
1289
    const std::vector<std::string>& inputs,
1290
    const DebugInfo& debug_info
1291
) {
1292
    auto vertex = boost::add_vertex(block.dataflow_->graph_);
314✔
1293
    auto res = block.dataflow_->nodes_.insert(
628✔
1294
        {vertex,
314✔
1295
         std::unique_ptr<data_flow::Tasklet>(
314✔
1296
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, block.dataflow(), code, output, inputs)
314✔
1297
         )}
1298
    );
1299

1300
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
314✔
1301
};
×
1302

1303
data_flow::Memlet& StructuredSDFGBuilder::add_memlet(
880✔
1304
    structured_control_flow::Block& block,
1305
    data_flow::DataFlowNode& src,
1306
    const std::string& src_conn,
1307
    data_flow::DataFlowNode& dst,
1308
    const std::string& dst_conn,
1309
    const data_flow::Subset& subset,
1310
    const types::IType& base_type,
1311
    const DebugInfo& debug_info
1312
) {
1313
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, block.dataflow_->graph_);
880✔
1314
    auto res = block.dataflow_->edges_.insert(
1,760✔
1315
        {edge.first,
1,760✔
1316
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
1,760✔
1317
             this->new_element_id(), debug_info, edge.first, block.dataflow(), src, src_conn, dst, dst_conn, subset, base_type
880✔
1318
         ))}
1319
    );
1320

1321
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
880✔
1322
#ifndef NDEBUG
1323
    memlet.validate(*this->structured_sdfg_);
880✔
1324
#endif
1325

1326
    return memlet;
880✔
1327
};
×
1328

1329
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
121✔
1330
    structured_control_flow::Block& block,
1331
    data_flow::AccessNode& src,
1332
    data_flow::Tasklet& dst,
1333
    const std::string& dst_conn,
1334
    const data_flow::Subset& subset,
1335
    const types::IType& base_type,
1336
    const DebugInfo& debug_info
1337
) {
1338
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, base_type, debug_info);
121✔
1339
};
×
1340

1341
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
113✔
1342
    structured_control_flow::Block& block,
1343
    data_flow::Tasklet& src,
1344
    const std::string& src_conn,
1345
    data_flow::AccessNode& dst,
1346
    const data_flow::Subset& subset,
1347
    const types::IType& base_type,
1348
    const DebugInfo& debug_info
1349
) {
1350
    return this->add_memlet(block, src, src_conn, dst, "void", subset, base_type, debug_info);
113✔
1351
};
×
1352

1353
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
267✔
1354
    structured_control_flow::Block& block,
1355
    data_flow::AccessNode& src,
1356
    data_flow::Tasklet& dst,
1357
    const std::string& dst_conn,
1358
    const data_flow::Subset& subset,
1359
    const DebugInfo& debug_info
1360
) {
1361
    const types::IType* src_type = nullptr;
267✔
1362
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
267✔
1363
        src_type = &cnode->type();
66✔
1364
    } else {
66✔
1365
        src_type = &this->structured_sdfg_->type(src.data());
201✔
1366
    }
1367
    auto& base_type = types::infer_type(*this->structured_sdfg_, *src_type, subset);
267✔
1368
    if (base_type.type_id() != types::TypeID::Scalar) {
267✔
1369
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1370
    }
1371
    return this->add_memlet(block, src, "void", dst, dst_conn, subset, *src_type, debug_info);
267✔
1372
};
×
1373

1374
data_flow::Memlet& StructuredSDFGBuilder::add_computational_memlet(
179✔
1375
    structured_control_flow::Block& block,
1376
    data_flow::Tasklet& src,
1377
    const std::string& src_conn,
1378
    data_flow::AccessNode& dst,
1379
    const data_flow::Subset& subset,
1380
    const DebugInfo& debug_info
1381
) {
1382
    auto& dst_type = this->structured_sdfg_->type(dst.data());
179✔
1383
    auto& base_type = types::infer_type(*this->structured_sdfg_, dst_type, subset);
179✔
1384
    if (base_type.type_id() != types::TypeID::Scalar) {
179✔
1385
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
1386
    }
1387
    return this->add_memlet(block, src, src_conn, dst, "void", subset, dst_type, debug_info);
179✔
1388
};
×
1389

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

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

1414
data_flow::Memlet& StructuredSDFGBuilder::add_reference_memlet(
37✔
1415
    structured_control_flow::Block& block,
1416
    data_flow::AccessNode& src,
1417
    data_flow::AccessNode& dst,
1418
    const data_flow::Subset& subset,
1419
    const types::IType& base_type,
1420
    const DebugInfo& debug_info
1421
) {
1422
    return this->add_memlet(block, src, "void", dst, "ref", subset, base_type, debug_info);
37✔
1423
};
×
1424

1425
data_flow::Memlet& StructuredSDFGBuilder::add_dereference_memlet(
18✔
1426
    structured_control_flow::Block& block,
1427
    data_flow::AccessNode& src,
1428
    data_flow::AccessNode& dst,
1429
    bool derefs_src,
1430
    const types::IType& base_type,
1431
    const DebugInfo& debug_info
1432
) {
1433
    if (derefs_src) {
18✔
1434
        return this->add_memlet(block, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
11✔
1435
    } else {
1436
        return this->add_memlet(block, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
7✔
1437
    }
1438
};
18✔
1439

1440
void StructuredSDFGBuilder::remove_memlet(structured_control_flow::Block& block, const data_flow::Memlet& edge) {
27✔
1441
    auto& graph = block.dataflow();
27✔
1442
    auto e = edge.edge();
27✔
1443
    boost::remove_edge(e, graph.graph_);
27✔
1444
    graph.edges_.erase(e);
27✔
1445
};
27✔
1446

1447
void StructuredSDFGBuilder::remove_node(structured_control_flow::Block& block, const data_flow::DataFlowNode& node) {
23✔
1448
    auto& graph = block.dataflow();
23✔
1449
    auto v = node.vertex();
23✔
1450
    boost::remove_vertex(v, graph.graph_);
23✔
1451
    graph.nodes_.erase(v);
23✔
1452
};
23✔
1453

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

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

1459
    // Delete incoming
1460
    std::list<const data_flow::Memlet*> iedges;
12✔
1461
    for (auto& iedge : graph.in_edges(node)) {
31✔
1462
        iedges.push_back(&iedge);
19✔
1463
    }
1464
    for (auto iedge : iedges) {
31✔
1465
        auto& src = iedge->src();
19✔
1466
        to_delete.insert(&src);
19✔
1467

1468
        auto edge = iedge->edge();
19✔
1469
        graph.edges_.erase(edge);
19✔
1470
        boost::remove_edge(edge, graph.graph_);
19✔
1471
    }
1472

1473
    // Delete outgoing
1474
    std::list<const data_flow::Memlet*> oedges;
12✔
1475
    for (auto& oedge : graph.out_edges(node)) {
24✔
1476
        oedges.push_back(&oedge);
12✔
1477
    }
1478
    for (auto oedge : oedges) {
24✔
1479
        auto& dst = oedge->dst();
12✔
1480
        to_delete.insert(&dst);
12✔
1481

1482
        auto edge = oedge->edge();
12✔
1483
        graph.edges_.erase(edge);
12✔
1484
        boost::remove_edge(edge, graph.graph_);
12✔
1485
    }
1486

1487
    // Delete nodes
1488
    for (auto obsolete_node : to_delete) {
55✔
1489
        if (graph.in_degree(*obsolete_node) == 0 && graph.out_degree(*obsolete_node) == 0) {
43✔
1490
            auto vertex = obsolete_node->vertex();
43✔
1491
            graph.nodes_.erase(vertex);
43✔
1492
            boost::remove_vertex(vertex, graph.graph_);
43✔
1493
        }
43✔
1494
    }
1495
};
12✔
1496

1497
void StructuredSDFGBuilder::clear_node(structured_control_flow::Block& block, const data_flow::AccessNode& node) {
7✔
1498
    auto& graph = block.dataflow();
7✔
1499
    if (graph.out_degree(node) != 0) {
7✔
1500
        throw InvalidSDFGException("StructuredSDFGBuilder: Access node has outgoing edges");
×
1501
    }
1502

1503
    std::list<const data_flow::Memlet*> tmp;
7✔
1504
    std::list<const data_flow::DataFlowNode*> queue = {&node};
7✔
1505
    while (!queue.empty()) {
25✔
1506
        auto current = queue.front();
18✔
1507
        queue.pop_front();
18✔
1508
        if (current != &node) {
18✔
1509
            if (dynamic_cast<const data_flow::AccessNode*>(current)) {
11✔
1510
                if (graph.in_degree(*current) > 0 || graph.out_degree(*current) > 0) {
4✔
1511
                    continue;
×
1512
                }
1513
            }
4✔
1514
        }
11✔
1515

1516
        tmp.clear();
18✔
1517
        for (auto& iedge : graph.in_edges(*current)) {
29✔
1518
            tmp.push_back(&iedge);
11✔
1519
        }
1520
        for (auto iedge : tmp) {
29✔
1521
            auto& src = iedge->src();
11✔
1522
            queue.push_back(&src);
11✔
1523

1524
            auto edge = iedge->edge();
11✔
1525
            graph.edges_.erase(edge);
11✔
1526
            boost::remove_edge(edge, graph.graph_);
11✔
1527
        }
1528

1529
        auto vertex = current->vertex();
18✔
1530
        graph.nodes_.erase(vertex);
18✔
1531
        boost::remove_vertex(vertex, graph.graph_);
18✔
1532
    }
1533
};
7✔
1534

1535
void StructuredSDFGBuilder::add_dataflow(const data_flow::DataFlowGraph& from, Block& to) {
20✔
1536
    auto& to_dataflow = to.dataflow();
20✔
1537

1538
    std::unordered_map<graph::Vertex, graph::Vertex> node_mapping;
20✔
1539
    for (auto& entry : from.nodes_) {
21✔
1540
        auto vertex = boost::add_vertex(to_dataflow.graph_);
1✔
1541
        to_dataflow.nodes_.insert({vertex, entry.second->clone(this->new_element_id(), vertex, to_dataflow)});
1✔
1542
        node_mapping.insert({entry.first, vertex});
1✔
1543
    }
1544

1545
    for (auto& entry : from.edges_) {
20✔
1546
        auto src = node_mapping[entry.second->src().vertex()];
×
1547
        auto dst = node_mapping[entry.second->dst().vertex()];
×
1548

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

1551
        to_dataflow.edges_.insert(
×
1552
            {edge.first,
×
1553
             entry.second->clone(
×
1554
                 this->new_element_id(), edge.first, to_dataflow, *to_dataflow.nodes_[src], *to_dataflow.nodes_[dst]
×
1555
             )}
1556
        );
1557
    }
1558
};
20✔
1559

1560
void StructuredSDFGBuilder::merge_siblings(data_flow::AccessNode& source_node) {
18✔
1561
    auto& user_graph = source_node.get_parent();
18✔
1562
    auto* block = dynamic_cast<structured_control_flow::Block*>(user_graph.get_parent());
18✔
1563
    if (!block) {
18✔
1564
        throw InvalidSDFGException("Parent of user graph must be a block!");
×
1565
    }
1566

1567
    // Merge access nodes if they access the same container on a tasklet
1568
    for (auto& oedge : user_graph.out_edges(source_node)) {
30✔
1569
        if (auto* tasklet = dynamic_cast<data_flow::Tasklet*>(&oedge.dst())) {
12✔
1570
            std::unordered_set<data_flow::Memlet*> iedges;
7✔
1571
            for (auto& iedge : user_graph.in_edges(*tasklet)) {
16✔
1572
                iedges.insert(&iedge);
9✔
1573
            }
1574
            for (auto* iedge : iedges) {
16✔
1575
                if (dynamic_cast<data_flow::ConstantNode*>(&iedge->src())) {
9✔
1576
                    continue;
×
1577
                }
1578
                auto* access_node = static_cast<data_flow::AccessNode*>(&iedge->src());
9✔
1579
                if (access_node == &source_node || access_node->data() != source_node.data()) {
9✔
1580
                    continue;
8✔
1581
                }
1582
                this->add_memlet(
1✔
1583
                    *block,
1✔
1584
                    source_node,
1✔
1585
                    iedge->src_conn(),
1✔
1586
                    *tasklet,
1✔
1587
                    iedge->dst_conn(),
1✔
1588
                    iedge->subset(),
1✔
1589
                    iedge->base_type(),
1✔
1590
                    iedge->debug_info()
1✔
1591
                );
1592
                this->remove_memlet(*block, *iedge);
1✔
1593
                source_node.set_debug_info(DebugInfo::merge(source_node.debug_info(), access_node->debug_info()));
1✔
1594
            }
1595
        }
7✔
1596
    }
1597
}
18✔
1598

1599
} // namespace builder
1600
} // 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