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

daisytuner / sdfglib / 17656823807

11 Sep 2025 08:42PM UTC coverage: 60.447% (+1.1%) from 59.335%
17656823807

Pull #219

github

web-flow
Merge d5416236f into 6c1992b40
Pull Request #219: stdlib Library Nodes and ConstantNodes

460 of 1635 new or added lines in 81 files covered. (28.13%)

93 existing lines in 35 files now uncovered.

9385 of 15526 relevant lines covered (60.45%)

107.21 hits per line

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

69.96
/src/builder/sdfg_builder.cpp
1
#include "sdfg/builder/sdfg_builder.h"
2

3
#include "sdfg/types/utils.h"
4

5
namespace sdfg {
6
namespace builder {
7

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

10
SDFGBuilder::SDFGBuilder(std::unique_ptr<SDFG>& sdfg)
×
11
    : FunctionBuilder(), sdfg_(std::move(sdfg)) {
×
12

13
      };
×
14

15
SDFGBuilder::SDFGBuilder(const std::string& name, FunctionType type)
50✔
16
    : FunctionBuilder(), sdfg_(new SDFG(name, type)) {
50✔
17

18
      };
50✔
19

NEW
20
SDFGBuilder::SDFGBuilder(const std::string& name, FunctionType type, const types::IType& return_type)
×
NEW
21
    : FunctionBuilder(), sdfg_(new SDFG(name, type, return_type)) {
×
22

NEW
23
      };
×
24

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

27
std::unique_ptr<SDFG> SDFGBuilder::move() {
13✔
28
#ifndef NDEBUG
29
    this->sdfg_->validate();
13✔
30
#endif
31

32
    return std::move(this->sdfg_);
13✔
33
};
34

NEW
35
void SDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
NEW
36
    FunctionBuilder::rename_container(old_name, new_name);
×
37

NEW
38
    for (auto& entry : this->sdfg_->states_) {
×
NEW
39
        entry.second->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
40
    }
NEW
41
    for (auto& entry : this->sdfg_->edges_) {
×
NEW
42
        entry.second->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
43
    }
NEW
44
}
×
45

46
/***** Section: Control-Flow Graph *****/
47

48
control_flow::State& SDFGBuilder::add_state(bool is_start_state, const DebugInfo& debug_info) {
60✔
49
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
60✔
50
    auto res = this->sdfg_->states_.insert(
120✔
51
        {vertex,
60✔
52
         std::unique_ptr<control_flow::State>(new control_flow::State(this->new_element_id(), debug_info, vertex))}
60✔
53
    );
54

55
    assert(res.second);
60✔
56
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
60✔
57

58
    if (is_start_state) {
60✔
59
        this->sdfg_->start_state_ = (*res.first).second.get();
12✔
60
    }
12✔
61

62
    return *(*res.first).second;
60✔
63
};
×
64

65
control_flow::State& SDFGBuilder::
66
    add_state_before(const control_flow::State& state, bool is_start_state, const DebugInfo& debug_info) {
1✔
67
    auto& new_state = this->add_state(false, debug_info);
1✔
68

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

72
    // Redirect control-flow
73
    for (auto edge : to_redirect) {
2✔
74
        this->add_edge(edge->src(), new_state, edge->condition());
1✔
75

76
        auto desc = edge->edge();
1✔
77
        this->sdfg_->edges_.erase(desc);
1✔
78
        boost::remove_edge(desc, this->sdfg_->graph_);
1✔
79
    }
80
    this->add_edge(new_state, state);
1✔
81

82
    if (is_start_state) {
1✔
83
        this->sdfg_->start_state_ = &new_state;
×
84
    }
×
85

86
    return new_state;
1✔
87
};
1✔
88

89
control_flow::State& SDFGBuilder::
90
    add_state_after(const control_flow::State& state, bool connect_states, const DebugInfo& debug_info) {
4✔
91
    auto& new_state = this->add_state(false, debug_info);
4✔
92

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

96
    // Redirect control-flow
97
    for (auto& edge : to_redirect) {
5✔
98
        this->add_edge(new_state, edge->dst(), edge->condition());
1✔
99

100
        auto desc = edge->edge();
1✔
101
        this->sdfg_->edges_.erase(desc);
1✔
102
        boost::remove_edge(desc, this->sdfg_->graph_);
1✔
103
    }
104
    if (connect_states) {
4✔
105
        this->add_edge(state, new_state);
3✔
106
    }
3✔
107

108
    return new_state;
4✔
109
};
4✔
110

111
control_flow::ReturnState& SDFGBuilder::
112
    add_return_state(const std::string& data, bool unreachable, const DebugInfo& debug_info) {
4✔
113
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
4✔
114
    auto res = this->sdfg_->states_.insert(
8✔
115
        {vertex,
4✔
116
         std::unique_ptr<control_flow::State>(
4✔
117
             new control_flow::ReturnState(this->new_element_id(), debug_info, vertex, data, unreachable)
4✔
118
         )}
119
    );
120

121
    assert(res.second);
4✔
122
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
4✔
123

124
    return static_cast<control_flow::ReturnState&>(*(*res.first).second);
4✔
NEW
125
};
×
126

127
control_flow::ReturnState& SDFGBuilder::add_return_state_after(
3✔
128
    const control_flow::State& state, const std::string& data, bool unreachable, const DebugInfo& debug_info
129
) {
130
    auto& new_state = this->add_return_state(data, unreachable, debug_info);
3✔
131

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

135
    // Redirect control-flow
136
    for (auto& edge : to_redirect) {
3✔
NEW
137
        this->add_edge(new_state, edge->dst(), edge->condition());
×
138

NEW
139
        auto desc = edge->edge();
×
NEW
140
        this->sdfg_->edges_.erase(desc);
×
NEW
141
        boost::remove_edge(desc, this->sdfg_->graph_);
×
142
    }
143
    this->add_edge(state, new_state);
3✔
144

145
    return new_state;
3✔
146
};
3✔
147

148
control_flow::InterstateEdge& SDFGBuilder::
149
    add_edge(const control_flow::State& src, const control_flow::State& dst, const DebugInfo& debug_info) {
41✔
150
    return this->add_edge(src, dst, control_flow::Assignments{}, SymEngine::boolTrue, debug_info);
41✔
151
};
×
152

153
control_flow::InterstateEdge& SDFGBuilder::add_edge(
8✔
154
    const control_flow::State& src,
155
    const control_flow::State& dst,
156
    const symbolic::Condition condition,
157
    const DebugInfo& debug_info
158
) {
159
    return this->add_edge(src, dst, control_flow::Assignments{}, condition, debug_info);
8✔
160
};
×
161

162
control_flow::InterstateEdge& SDFGBuilder::add_edge(
2✔
163
    const control_flow::State& src,
164
    const control_flow::State& dst,
165
    const control_flow::Assignments& assignments,
166
    const DebugInfo& debug_info
167
) {
168
    return this->add_edge(src, dst, assignments, SymEngine::boolTrue, debug_info);
2✔
169
};
×
170

171
control_flow::InterstateEdge& SDFGBuilder::add_edge(
53✔
172
    const control_flow::State& src,
173
    const control_flow::State& dst,
174
    const control_flow::Assignments& assignments,
175
    const symbolic::Condition condition,
176
    const DebugInfo& debug_info
177
) {
178
    if (dynamic_cast<const control_flow::ReturnState*>(&src) != nullptr) {
53✔
NEW
179
        throw InvalidSDFGException("Cannot add edge from ReturnState");
×
180
    }
181

182
    for (auto& entry : assignments) {
57✔
183
        auto& lhs = entry.first;
4✔
184
        auto& type = this->function().type(lhs->get_name());
4✔
185
        if (type.type_id() != types::TypeID::Scalar) {
4✔
186
            throw InvalidSDFGException("Assignment - LHS: must be integer type");
×
187
        }
188

189
        auto& rhs = entry.second;
4✔
190
        for (auto& atom : symbolic::atoms(rhs)) {
5✔
191
            if (symbolic::is_nullptr(atom)) {
1✔
192
                throw InvalidSDFGException("Assignment - RHS: must be integer type, but is nullptr");
×
193
            }
194
            auto& atom_type = this->function().type(atom->get_name());
1✔
195
            if (atom_type.type_id() != types::TypeID::Scalar) {
1✔
196
                throw InvalidSDFGException("Assignment - RHS: must be integer type");
×
197
            }
198
        }
199
    }
200

201
    for (auto& atom : symbolic::atoms(condition)) {
61✔
202
        if (symbolic::is_nullptr(atom)) {
8✔
203
            continue;
×
204
        }
205
        auto& atom_type = this->function().type(atom->get_name());
8✔
206
        if (atom_type.type_id() != types::TypeID::Scalar && atom_type.type_id() != types::TypeID::Pointer) {
8✔
207
            throw InvalidSDFGException("Condition: must be integer type or pointer type");
×
208
        }
209
    }
210

211
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, this->sdfg_->graph_);
53✔
212
    assert(edge.second);
53✔
213

214
    auto res = this->sdfg_->edges_.insert(
106✔
215
        {edge.first,
106✔
216
         std::unique_ptr<control_flow::InterstateEdge>(new control_flow::InterstateEdge(
53✔
217
             this->new_element_id(), debug_info, edge.first, src, dst, condition, assignments
53✔
218
         ))}
219
    );
220

221
    assert(res.second);
53✔
222

223
    return *(*res.first).second;
53✔
224
};
×
225

226
void SDFGBuilder::remove_edge(const control_flow::InterstateEdge& edge) {
×
227
    auto desc = edge.edge();
×
228
    this->sdfg_->edges_.erase(desc);
×
229

230
    boost::remove_edge(desc, this->sdfg_->graph_);
×
231
};
×
232

233
std::tuple<control_flow::State&, control_flow::State&, control_flow::State&> SDFGBuilder::add_loop(
1✔
234
    const control_flow::State& state,
235
    sdfg::symbolic::Symbol iterator,
236
    sdfg::symbolic::Expression init,
237
    sdfg::symbolic::Condition cond,
238
    sdfg::symbolic::Expression update,
239
    const DebugInfo& debug_info
240
) {
241
    // Init: iterator = init
242
    auto& init_state = this->add_state_after(state, true, debug_info);
1✔
243
    const graph::Edge init_edge_desc = (*this->sdfg_->in_edges(init_state).begin()).edge_;
1✔
244
    auto& init_edge = this->sdfg_->edges_[init_edge_desc];
1✔
245
    init_edge->assignments_.insert({iterator, init});
1✔
246

247
    // Final state
248
    auto& final_state = this->add_state_after(init_state, false, debug_info);
1✔
249

250
    // Init -> early_exit -> final
251
    auto& early_exit_state = this->add_state(false, debug_info);
1✔
252
    this->add_edge(init_state, early_exit_state, symbolic::Not(cond));
1✔
253
    this->add_edge(early_exit_state, final_state);
1✔
254

255
    // Init -> header -> body
256
    auto& header_state = this->add_state(false, debug_info);
1✔
257
    this->add_edge(init_state, header_state, cond);
1✔
258

259
    auto& body_state = this->add_state(false, debug_info);
1✔
260
    this->add_edge(header_state, body_state);
1✔
261

262
    auto& update_state = this->add_state(false, debug_info);
1✔
263
    this->add_edge(body_state, update_state, {{iterator, update}});
1✔
264

265
    // Back edge and exit edge
266
    this->add_edge(update_state, header_state, cond);
1✔
267
    this->add_edge(update_state, final_state, symbolic::Not(cond));
1✔
268

269
    return {init_state, body_state, final_state};
1✔
270
};
×
271

272
/***** Section: Dataflow Graph *****/
273

274
data_flow::AccessNode& SDFGBuilder::
275
    add_access(control_flow::State& state, const std::string& data, const DebugInfo& debug_info) {
6✔
276
    auto& dataflow = state.dataflow();
6✔
277
    auto vertex = boost::add_vertex(dataflow.graph_);
6✔
278
    auto res = dataflow.nodes_.insert(
12✔
279
        {vertex,
6✔
280
         std::unique_ptr<
6✔
281
             data_flow::AccessNode>(new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, dataflow, data)
6✔
282
         )}
283
    );
284

285
    return static_cast<data_flow::AccessNode&>(*(res.first->second));
6✔
NEW
286
};
×
287

288
data_flow::ConstantNode& SDFGBuilder::add_constant(
1✔
289
    control_flow::State& state, const std::string& data, const types::IType& type, const DebugInfo& debug_info
290
) {
291
    auto& dataflow = state.dataflow();
1✔
292
    auto vertex = boost::add_vertex(dataflow.graph_);
1✔
293
    auto res = dataflow.nodes_.insert(
2✔
294
        {vertex,
1✔
295
         std::unique_ptr<data_flow::ConstantNode>(
1✔
296
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, dataflow, data, type)
1✔
297
         )}
298
    );
299

300
    return static_cast<data_flow::ConstantNode&>(*(res.first->second));
1✔
UNCOV
301
};
×
302

303
data_flow::Tasklet& SDFGBuilder::add_tasklet(
3✔
304
    control_flow::State& state,
305
    const data_flow::TaskletCode code,
306
    const std::string& output,
307
    const std::vector<std::string>& inputs,
308
    const DebugInfo& debug_info
309
) {
310
    auto& dataflow = state.dataflow();
3✔
311
    auto vertex = boost::add_vertex(dataflow.graph_);
3✔
312
    auto res = dataflow.nodes_.insert(
6✔
313
        {vertex,
3✔
314
         std::unique_ptr<data_flow::Tasklet>(
3✔
315
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, dataflow, code, output, inputs)
3✔
316
         )}
317
    );
318

319
    return static_cast<data_flow::Tasklet&>(*(res.first->second));
3✔
320
};
×
321

322
data_flow::Memlet& SDFGBuilder::add_memlet(
6✔
323
    control_flow::State& state,
324
    data_flow::DataFlowNode& src,
325
    const std::string& src_conn,
326
    data_flow::DataFlowNode& dst,
327
    const std::string& dst_conn,
328
    const data_flow::Subset& subset,
329
    const types::IType& base_type,
330
    const DebugInfo& debug_info
331
) {
332
    auto& dataflow = state.dataflow();
6✔
333
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, dataflow.graph_);
6✔
334
    auto res = dataflow.edges_.insert(
12✔
335
        {edge.first,
12✔
336
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
6✔
337
             this->new_element_id(), debug_info, edge.first, dataflow, src, src_conn, dst, dst_conn, subset, base_type
6✔
338
         ))}
339
    );
340

341
    auto& memlet = static_cast<data_flow::Memlet&>(*(res.first->second));
6✔
342
#ifndef NDEBUG
343
    memlet.validate(*this->sdfg_);
6✔
344
#endif
345

346
    return memlet;
6✔
347
};
×
348

349
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
350
    control_flow::State& state,
351
    data_flow::AccessNode& src,
352
    data_flow::Tasklet& dst,
353
    const std::string& dst_conn,
354
    const data_flow::Subset& subset,
355
    const types::IType& base_type,
356
    const DebugInfo& debug_info
357
) {
358
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, base_type, debug_info);
×
359
};
×
360

361
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
362
    control_flow::State& state,
363
    data_flow::Tasklet& src,
364
    const std::string& src_conn,
365
    data_flow::AccessNode& dst,
366
    const data_flow::Subset& subset,
367
    const types::IType& base_type,
368
    const DebugInfo& debug_info
369
) {
370
    return this->add_memlet(state, src, src_conn, dst, "void", subset, base_type, debug_info);
×
371
};
×
372

373
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
3✔
374
    control_flow::State& state,
375
    data_flow::AccessNode& src,
376
    data_flow::Tasklet& dst,
377
    const std::string& dst_conn,
378
    const data_flow::Subset& subset,
379
    const DebugInfo& debug_info
380
) {
381
    const types::IType* src_type = nullptr;
3✔
382
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
3✔
NEW
383
        src_type = &cnode->type();
×
NEW
384
    } else {
×
385
        src_type = &this->sdfg_->type(src.data());
3✔
386
    }
387
    auto& base_type = types::infer_type(*this->sdfg_, *src_type, subset);
3✔
388
    if (base_type.type_id() != types::TypeID::Scalar) {
3✔
389
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
390
    }
391
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, *src_type, debug_info);
3✔
392
};
×
393

394
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
3✔
395
    control_flow::State& state,
396
    data_flow::Tasklet& src,
397
    const std::string& src_conn,
398
    data_flow::AccessNode& dst,
399
    const data_flow::Subset& subset,
400
    const DebugInfo& debug_info
401
) {
402
    auto& dst_type = this->function().type(dst.data());
3✔
403
    auto& base_type = types::infer_type(this->function(), dst_type, subset);
3✔
404
    if (base_type.type_id() != types::TypeID::Scalar) {
3✔
405
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
406
    }
407
    return this->add_memlet(state, src, src_conn, dst, "void", subset, dst_type, debug_info);
3✔
408
};
×
409

410
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
411
    control_flow::State& state,
412
    data_flow::AccessNode& src,
413
    data_flow::LibraryNode& dst,
414
    const std::string& dst_conn,
415
    const data_flow::Subset& subset,
416
    const types::IType& base_type,
417
    const DebugInfo& debug_info
418
) {
NEW
419
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, base_type, debug_info);
×
420
};
×
421

422
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
423
    control_flow::State& state,
424
    data_flow::LibraryNode& src,
425
    const std::string& src_conn,
426
    data_flow::AccessNode& dst,
427
    const data_flow::Subset& subset,
428
    const types::IType& base_type,
429
    const DebugInfo& debug_info
430
) {
NEW
431
    return this->add_memlet(state, src, src_conn, dst, "void", subset, base_type, debug_info);
×
432
};
×
433

434
data_flow::Memlet& SDFGBuilder::add_reference_memlet(
×
435
    control_flow::State& state,
436
    data_flow::AccessNode& src,
437
    data_flow::AccessNode& dst,
438
    const data_flow::Subset& subset,
439
    const types::IType& base_type,
440
    const DebugInfo& debug_info
441
) {
442
    return this->add_memlet(state, src, "void", dst, "ref", subset, base_type, debug_info);
×
443
};
×
444

445
data_flow::Memlet& SDFGBuilder::add_dereference_memlet(
×
446
    control_flow::State& state,
447
    data_flow::AccessNode& src,
448
    data_flow::AccessNode& dst,
449
    bool derefs_src,
450
    const types::IType& base_type,
451
    const DebugInfo& debug_info
452
) {
453
    if (derefs_src) {
×
454
        return this->add_memlet(state, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
×
455
    } else {
456
        return this->add_memlet(state, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
×
457
    }
458
};
×
459

460
} // namespace builder
461
} // 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