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

daisytuner / sdfglib / 17651658650

11 Sep 2025 04:58PM UTC coverage: 61.012% (+1.3%) from 59.755%
17651658650

Pull #219

github

web-flow
Merge 742a12367 into f744ac9f5
Pull Request #219: stdlib Library Nodes and ConstantNodes

499 of 1681 new or added lines in 81 files covered. (29.68%)

95 existing lines in 36 files now uncovered.

9718 of 15928 relevant lines covered (61.01%)

108.0 hits per line

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

70.08
/src/builder/sdfg_builder.cpp
1
#include "sdfg/builder/sdfg_builder.h"
2
#include <cstddef>
3
#include <unordered_set>
4

5
#include "sdfg/types/utils.h"
6

7
namespace sdfg {
8
namespace builder {
9

10
DebugInfoRegion SDFGBuilder::fill_debug_info(const DebugInfos& debug_info_elements) {
133✔
11
    std::unordered_set<size_t> indices;
133✔
12
    for (const auto& element : debug_info_elements) {
133✔
13
        auto index = sdfg_->debug_info_.add_element(element);
×
14
        indices.insert(index);
×
15
    }
16
    return DebugInfoRegion{std::move(indices), sdfg_->debug_info_.elements()};
133✔
17
}
133✔
18

19
Function& SDFGBuilder::function() const { return static_cast<Function&>(*this->sdfg_); };
226✔
20

21
SDFGBuilder::SDFGBuilder(std::unique_ptr<SDFG>& sdfg)
×
22
    : FunctionBuilder(), sdfg_(std::move(sdfg)) {
×
23

24
      };
×
25

26
SDFGBuilder::SDFGBuilder(const std::string& name, FunctionType type)
50✔
27
    : FunctionBuilder(), sdfg_(new SDFG(name, type)) {
50✔
28

29
      };
50✔
30

NEW
31
SDFGBuilder::SDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
×
NEW
32
    : FunctionBuilder(), sdfg_(new SDFG(name, type, return_type)) {
×
33

NEW
34
      };
×
35

36
SDFG& SDFGBuilder::subject() const { return *this->sdfg_; };
33✔
37

38
std::unique_ptr<SDFG> SDFGBuilder::move() {
13✔
39
#ifndef NDEBUG
40
    this->sdfg_->validate();
13✔
41
#endif
42

43
    return std::move(this->sdfg_);
13✔
44
};
45

NEW
46
void SDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
NEW
47
    FunctionBuilder::rename_container(old_name, new_name);
×
48

NEW
49
    for (auto& entry : this->sdfg_->states_) {
×
NEW
50
        entry.second->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
51
    }
NEW
52
    for (auto& entry : this->sdfg_->edges_) {
×
NEW
53
        entry.second->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
54
    }
NEW
55
}
×
56

57
/***** Section: Control-Flow Graph *****/
58

59
control_flow::State& SDFGBuilder::add_state(bool is_start_state, const DebugInfos& debug_info_elements) {
60✔
60
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
60✔
61
    auto res = this->sdfg_->states_.insert(
120✔
62
        {vertex,
60✔
63
         std::unique_ptr<control_flow::State>(
60✔
64
             new control_flow::State(this->new_element_id(), fill_debug_info(debug_info_elements), vertex)
60✔
65
         )}
66
    );
67

68
    assert(res.second);
60✔
69
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
60✔
70

71
    if (is_start_state) {
60✔
72
        this->sdfg_->start_state_ = (*res.first).second.get();
12✔
73
    }
12✔
74

75
    return *(*res.first).second;
60✔
76
};
×
77

78
control_flow::State& SDFGBuilder::
79
    add_state_before(const control_flow::State& state, bool is_start_state, const DebugInfos& debug_info_elements) {
1✔
80
    auto& new_state = this->add_state(false, debug_info_elements);
1✔
81

82
    std::vector<const control_flow::InterstateEdge*> to_redirect;
1✔
83
    for (auto& e : this->sdfg_->in_edges(state)) to_redirect.push_back(&e);
2✔
84

85
    // Redirect control-flow
86
    for (auto edge : to_redirect) {
2✔
87
        this->add_edge(edge->src(), new_state, edge->condition());
1✔
88

89
        auto desc = edge->edge();
1✔
90
        this->sdfg_->edges_.erase(desc);
1✔
91
        boost::remove_edge(desc, this->sdfg_->graph_);
1✔
92
    }
93
    this->add_edge(new_state, state);
1✔
94

95
    if (is_start_state) {
1✔
96
        this->sdfg_->start_state_ = &new_state;
×
97
    }
×
98

99
    return new_state;
1✔
100
};
1✔
101

102
control_flow::State& SDFGBuilder::
103
    add_state_after(const control_flow::State& state, bool connect_states, const DebugInfos& debug_info_elements) {
4✔
104
    auto& new_state = this->add_state(false, debug_info_elements);
4✔
105

106
    std::vector<const control_flow::InterstateEdge*> to_redirect;
4✔
107
    for (auto& e : this->sdfg_->out_edges(state)) to_redirect.push_back(&e);
5✔
108

109
    // Redirect control-flow
110
    for (auto& edge : to_redirect) {
5✔
111
        this->add_edge(new_state, edge->dst(), edge->condition());
1✔
112

113
        auto desc = edge->edge();
1✔
114
        this->sdfg_->edges_.erase(desc);
1✔
115
        boost::remove_edge(desc, this->sdfg_->graph_);
1✔
116
    }
117
    if (connect_states) {
4✔
118
        this->add_edge(state, new_state);
3✔
119
    }
3✔
120

121
    return new_state;
4✔
122
};
4✔
123

124
control_flow::ReturnState& SDFGBuilder::
125
    add_return_state(const std::string& data, bool unreachable, const DebugInfos& debug_info_elements) {
4✔
126
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
4✔
127
    auto res = this->sdfg_->states_.insert(
8✔
128
        {vertex,
4✔
129
         std::unique_ptr<control_flow::State>(new control_flow::ReturnState(
8✔
130
             this->new_element_id(), fill_debug_info(debug_info_elements), vertex, data, unreachable
4✔
131
         ))}
132
    );
133

134
    assert(res.second);
4✔
135
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
4✔
136

137
    return static_cast<control_flow::ReturnState&>(*(*res.first).second);
4✔
NEW
138
};
×
139

140
control_flow::ReturnState& SDFGBuilder::add_return_state_after(
3✔
141
    const control_flow::State& state, const std::string& data, bool unreachable, const DebugInfos& debug_info_elements
142
) {
143
    auto& new_state = this->add_return_state(data, unreachable, debug_info_elements);
3✔
144

145
    std::vector<const control_flow::InterstateEdge*> to_redirect;
3✔
146
    for (auto& e : this->sdfg_->out_edges(state)) to_redirect.push_back(&e);
3✔
147

148
    // Redirect control-flow
149
    for (auto& edge : to_redirect) {
3✔
NEW
150
        this->add_edge(new_state, edge->dst(), edge->condition());
×
151

NEW
152
        auto desc = edge->edge();
×
NEW
153
        this->sdfg_->edges_.erase(desc);
×
NEW
154
        boost::remove_edge(desc, this->sdfg_->graph_);
×
155
    }
156
    this->add_edge(state, new_state);
3✔
157

158
    return new_state;
3✔
159
};
3✔
160

161
control_flow::InterstateEdge& SDFGBuilder::
162
    add_edge(const control_flow::State& src, const control_flow::State& dst, const DebugInfos& debug_info_elements) {
41✔
163
    return this->add_edge(src, dst, control_flow::Assignments{}, SymEngine::boolTrue, debug_info_elements);
41✔
164
};
×
165

166
control_flow::InterstateEdge& SDFGBuilder::add_edge(
8✔
167
    const control_flow::State& src,
168
    const control_flow::State& dst,
169
    const symbolic::Condition condition,
170
    const DebugInfos& debug_info_elements
171
) {
172
    return this->add_edge(src, dst, control_flow::Assignments{}, condition, debug_info_elements);
8✔
173
};
×
174

175
control_flow::InterstateEdge& SDFGBuilder::add_edge(
2✔
176
    const control_flow::State& src,
177
    const control_flow::State& dst,
178
    const control_flow::Assignments& assignments,
179
    const DebugInfos& debug_info_elements
180
) {
181
    return this->add_edge(src, dst, assignments, SymEngine::boolTrue, debug_info_elements);
2✔
182
};
×
183

184
control_flow::InterstateEdge& SDFGBuilder::add_edge(
53✔
185
    const control_flow::State& src,
186
    const control_flow::State& dst,
187
    const control_flow::Assignments& assignments,
188
    const symbolic::Condition condition,
189
    const DebugInfos& debug_info_elements
190
) {
191
    if (dynamic_cast<const control_flow::ReturnState*>(&src) != nullptr) {
53✔
NEW
192
        throw InvalidSDFGException("Cannot add edge from ReturnState");
×
193
    }
194

195
    for (auto& entry : assignments) {
57✔
196
        auto& lhs = entry.first;
4✔
197
        auto& type = this->function().type(lhs->get_name());
4✔
198
        if (type.type_id() != types::TypeID::Scalar) {
4✔
199
            throw InvalidSDFGException("Assignment - LHS: must be integer type");
×
200
        }
201

202
        auto& rhs = entry.second;
4✔
203
        for (auto& atom : symbolic::atoms(rhs)) {
5✔
204
            if (symbolic::is_nullptr(atom)) {
1✔
205
                throw InvalidSDFGException("Assignment - RHS: must be integer type, but is nullptr");
×
206
            }
207
            auto& atom_type = this->function().type(atom->get_name());
1✔
208
            if (atom_type.type_id() != types::TypeID::Scalar) {
1✔
209
                throw InvalidSDFGException("Assignment - RHS: must be integer type");
×
210
            }
211
        }
212
    }
213

214
    for (auto& atom : symbolic::atoms(condition)) {
61✔
215
        if (symbolic::is_nullptr(atom)) {
8✔
216
            continue;
×
217
        }
218
        auto& atom_type = this->function().type(atom->get_name());
8✔
219
        if (atom_type.type_id() != types::TypeID::Scalar && atom_type.type_id() != types::TypeID::Pointer) {
8✔
220
            throw InvalidSDFGException("Condition: must be integer type or pointer type");
×
221
        }
222
    }
223

224
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, this->sdfg_->graph_);
53✔
225
    assert(edge.second);
53✔
226

227
    auto res = this->sdfg_->edges_.insert(
106✔
228
        {edge.first,
106✔
229
         std::unique_ptr<control_flow::InterstateEdge>(new control_flow::InterstateEdge(
106✔
230
             this->new_element_id(), fill_debug_info(debug_info_elements), edge.first, src, dst, condition, assignments
53✔
231
         ))}
232
    );
233

234
    assert(res.second);
53✔
235

236
    return *(*res.first).second;
53✔
237
};
×
238

239
void SDFGBuilder::remove_edge(const control_flow::InterstateEdge& edge) {
×
240
    auto desc = edge.edge();
×
241
    this->sdfg_->edges_.erase(desc);
×
242

243
    boost::remove_edge(desc, this->sdfg_->graph_);
×
244
};
×
245

246
std::tuple<control_flow::State&, control_flow::State&, control_flow::State&> SDFGBuilder::add_loop(
1✔
247
    const control_flow::State& state,
248
    sdfg::symbolic::Symbol iterator,
249
    sdfg::symbolic::Expression init,
250
    sdfg::symbolic::Condition cond,
251
    sdfg::symbolic::Expression update,
252
    const DebugInfos& debug_info_elements
253
) {
254
    // Init: iterator = init
255
    auto& init_state = this->add_state_after(state, true, debug_info_elements);
1✔
256
    const graph::Edge init_edge_desc = (*this->sdfg_->in_edges(init_state).begin()).edge_;
1✔
257
    auto& init_edge = this->sdfg_->edges_[init_edge_desc];
1✔
258
    init_edge->assignments_.insert({iterator, init});
1✔
259

260
    // Final state
261
    auto& final_state = this->add_state_after(init_state, false, debug_info_elements);
1✔
262

263
    // Init -> early_exit -> final
264
    auto& early_exit_state = this->add_state(false, debug_info_elements);
1✔
265
    this->add_edge(init_state, early_exit_state, symbolic::Not(cond));
1✔
266
    this->add_edge(early_exit_state, final_state);
1✔
267

268
    // Init -> header -> body
269
    auto& header_state = this->add_state(false, debug_info_elements);
1✔
270
    this->add_edge(init_state, header_state, cond);
1✔
271

272
    auto& body_state = this->add_state(false, debug_info_elements);
1✔
273
    this->add_edge(header_state, body_state);
1✔
274

275
    auto& update_state = this->add_state(false, debug_info_elements);
1✔
276
    this->add_edge(body_state, update_state, {{iterator, update}});
1✔
277

278
    // Back edge and exit edge
279
    this->add_edge(update_state, header_state, cond);
1✔
280
    this->add_edge(update_state, final_state, symbolic::Not(cond));
1✔
281

282
    return {init_state, body_state, final_state};
1✔
283
};
×
284

285
/***** Section: Dataflow Graph *****/
286

287
data_flow::AccessNode& SDFGBuilder::
288
    add_access(control_flow::State& state, const std::string& data, const DebugInfos& debug_info_elements) {
6✔
289
    auto& dataflow = state.dataflow();
6✔
290
    auto vertex = boost::add_vertex(dataflow.graph_);
6✔
291
    auto res = dataflow.nodes_.insert(
12✔
292
        {vertex,
6✔
293
         std::unique_ptr<data_flow::AccessNode>(new data_flow::AccessNode(
12✔
294
             this->new_element_id(), fill_debug_info(debug_info_elements), vertex, dataflow, data
6✔
295
         ))}
296
    );
297

298
    return static_cast<data_flow::AccessNode&>(*(res.first->second));
6✔
NEW
299
};
×
300

301
data_flow::ConstantNode& SDFGBuilder::add_constant(
1✔
302
    control_flow::State& state, const std::string& data, const types::IType& type, const DebugInfos& debug_info_elements
303
) {
304
    auto& dataflow = state.dataflow();
1✔
305
    auto vertex = boost::add_vertex(dataflow.graph_);
1✔
306
    auto res = dataflow.nodes_.insert(
2✔
307
        {vertex,
1✔
308
         std::unique_ptr<data_flow::ConstantNode>(new data_flow::ConstantNode(
2✔
309
             this->new_element_id(), fill_debug_info(debug_info_elements), vertex, dataflow, data, type
1✔
310
         ))}
311
    );
312

313
    return static_cast<data_flow::ConstantNode&>(*(res.first->second));
1✔
UNCOV
314
};
×
315

316
data_flow::Tasklet& SDFGBuilder::add_tasklet(
3✔
317
    control_flow::State& state,
318
    const data_flow::TaskletCode code,
319
    const std::string& output,
320
    const std::vector<std::string>& inputs,
321
    const DebugInfos& debug_info_elements
322
) {
323
    auto& dataflow = state.dataflow();
3✔
324
    auto vertex = boost::add_vertex(dataflow.graph_);
3✔
325
    auto res = dataflow.nodes_.insert(
6✔
326
        {vertex,
3✔
327
         std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
6✔
328
             this->new_element_id(), fill_debug_info(debug_info_elements), vertex, dataflow, code, output, inputs
3✔
329
         ))}
330
    );
331

332
    return static_cast<data_flow::Tasklet&>(*(res.first->second));
3✔
333
};
×
334

335
data_flow::Memlet& SDFGBuilder::add_memlet(
6✔
336
    control_flow::State& state,
337
    data_flow::DataFlowNode& src,
338
    const std::string& src_conn,
339
    data_flow::DataFlowNode& dst,
340
    const std::string& dst_conn,
341
    const data_flow::Subset& subset,
342
    const types::IType& base_type,
343
    const DebugInfos& debug_info_elements
344
) {
345
    auto& dataflow = state.dataflow();
6✔
346
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, dataflow.graph_);
6✔
347
    auto res = dataflow.edges_.insert(
12✔
348
        {edge.first,
12✔
349
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
12✔
350
             this->new_element_id(),
6✔
351
             fill_debug_info(debug_info_elements),
6✔
352
             edge.first,
6✔
353
             dataflow,
6✔
354
             src,
6✔
355
             src_conn,
6✔
356
             dst,
6✔
357
             dst_conn,
6✔
358
             subset,
6✔
359
             base_type
6✔
360
         ))}
361
    );
362

363
    auto& memlet = static_cast<data_flow::Memlet&>(*(res.first->second));
6✔
364
#ifndef NDEBUG
365
    memlet.validate(*this->sdfg_);
6✔
366
#endif
367

368
    return memlet;
6✔
369
};
×
370

371
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
372
    control_flow::State& state,
373
    data_flow::AccessNode& src,
374
    data_flow::Tasklet& dst,
375
    const std::string& dst_conn,
376
    const data_flow::Subset& subset,
377
    const types::IType& base_type,
378
    const DebugInfos& debug_info_elements
379
) {
380
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, base_type, debug_info_elements);
×
381
};
×
382

383
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
384
    control_flow::State& state,
385
    data_flow::Tasklet& src,
386
    const std::string& src_conn,
387
    data_flow::AccessNode& dst,
388
    const data_flow::Subset& subset,
389
    const types::IType& base_type,
390
    const DebugInfos& debug_info_elements
391
) {
392
    return this->add_memlet(state, src, src_conn, dst, "void", subset, base_type, debug_info_elements);
×
393
};
×
394

395
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
3✔
396
    control_flow::State& state,
397
    data_flow::AccessNode& src,
398
    data_flow::Tasklet& dst,
399
    const std::string& dst_conn,
400
    const data_flow::Subset& subset,
401
    const DebugInfos& debug_info_elements
402
) {
403
    const types::IType* src_type = nullptr;
3✔
404
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
3✔
NEW
405
        src_type = &cnode->type();
×
NEW
406
    } else {
×
407
        src_type = &this->sdfg_->type(src.data());
3✔
408
    }
409
    auto& base_type = types::infer_type(*this->sdfg_, *src_type, subset);
3✔
410
    if (base_type.type_id() != types::TypeID::Scalar) {
3✔
411
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
412
    }
413
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, *src_type, debug_info_elements);
3✔
414
};
×
415

416
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
3✔
417
    control_flow::State& state,
418
    data_flow::Tasklet& src,
419
    const std::string& src_conn,
420
    data_flow::AccessNode& dst,
421
    const data_flow::Subset& subset,
422
    const DebugInfos& debug_info_elements
423
) {
424
    auto& dst_type = this->function().type(dst.data());
3✔
425
    auto& base_type = types::infer_type(this->function(), dst_type, subset);
3✔
426
    if (base_type.type_id() != types::TypeID::Scalar) {
3✔
427
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
428
    }
429
    return this->add_memlet(state, src, src_conn, dst, "void", subset, dst_type, debug_info_elements);
3✔
430
};
×
431

432
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
433
    control_flow::State& state,
434
    data_flow::AccessNode& src,
435
    data_flow::LibraryNode& dst,
436
    const std::string& dst_conn,
437
    const data_flow::Subset& subset,
438
    const types::IType& base_type,
439
    const DebugInfos& debug_info_elements
440
) {
NEW
441
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, base_type, debug_info_elements);
×
442
};
×
443

444
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
445
    control_flow::State& state,
446
    data_flow::LibraryNode& src,
447
    const std::string& src_conn,
448
    data_flow::AccessNode& dst,
449
    const data_flow::Subset& subset,
450
    const types::IType& base_type,
451
    const DebugInfos& debug_info_elements
452
) {
NEW
453
    return this->add_memlet(state, src, src_conn, dst, "void", subset, base_type, debug_info_elements);
×
454
};
×
455

456
data_flow::Memlet& SDFGBuilder::add_reference_memlet(
×
457
    control_flow::State& state,
458
    data_flow::AccessNode& src,
459
    data_flow::AccessNode& dst,
460
    const data_flow::Subset& subset,
461
    const types::IType& base_type,
462
    const DebugInfos& debug_info_elements
463
) {
464
    return this->add_memlet(state, src, "void", dst, "ref", subset, base_type, debug_info_elements);
×
465
};
×
466

467
data_flow::Memlet& SDFGBuilder::add_dereference_memlet(
×
468
    control_flow::State& state,
469
    data_flow::AccessNode& src,
470
    data_flow::AccessNode& dst,
471
    bool derefs_src,
472
    const types::IType& base_type,
473
    const DebugInfos& debug_info_elements
474
) {
475
    if (derefs_src) {
×
476
        return this->add_memlet(state, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info_elements);
×
477
    } else {
478
        return this->add_memlet(state, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info_elements);
×
479
    }
480
};
×
481

482
size_t SDFGBuilder::add_debug_info_element(const DebugInfo& element) {
×
483
    return sdfg_->debug_info().add_element(element);
×
484
}
×
485

486
const DebugTable& SDFGBuilder::debug_info() const { return sdfg_->debug_info(); }
×
487

488
} // namespace builder
489
} // 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