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

daisytuner / sdfglib / 17637380013

11 Sep 2025 07:29AM UTC coverage: 59.755% (+0.6%) from 59.145%
17637380013

push

github

web-flow
New debug info (#210)

* initial draft

* update data structure and construction logic

* finalize DebugInfo draft

* fix tests

* Update serializer and fix tests

* fix append bug

* update data structure

* sdfg builder update

* const ref vectors

* update implementation and partial tests

* compiling state

* update serializer interface

* update dot test

* reset interface to debug_info in json to maintain compatibility with tools

* first review batch

* second batch of changes

* merge fixes

777 of 1111 new or added lines in 46 files covered. (69.94%)

11 existing lines in 11 files now uncovered.

9755 of 16325 relevant lines covered (59.75%)

115.06 hits per line

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

66.67
/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) {
127✔
11
    std::unordered_set<size_t> indices;
127✔
12
    for (const auto& element : debug_info_elements) {
127✔
NEW
13
        auto index = sdfg_->debug_info_.add_element(element);
×
NEW
14
        indices.insert(index);
×
15
    }
16
    return DebugInfoRegion{std::move(indices), sdfg_->debug_info_.elements()};
127✔
17
}
127✔
18

19
Function& SDFGBuilder::function() const { return static_cast<Function&>(*this->sdfg_); };
233✔
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)
51✔
27
    : FunctionBuilder(), sdfg_(new SDFG(name, type)) {
51✔
28

29
      };
51✔
30

31
SDFG& SDFGBuilder::subject() const { return *this->sdfg_; };
14✔
32

33
std::unique_ptr<SDFG> SDFGBuilder::move() {
33✔
34
#ifndef NDEBUG
35
    this->sdfg_->validate();
33✔
36
#endif
37

38
    return std::move(this->sdfg_);
33✔
39
};
40

41
/***** Section: Control-Flow Graph *****/
42

43
control_flow::State& SDFGBuilder::add_state(bool is_start_state, const DebugInfos& debug_info_elements) {
61✔
44
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
61✔
45
    auto res = this->sdfg_->states_.insert(
122✔
46
        {vertex,
61✔
47
         std::unique_ptr<control_flow::State>(
61✔
48
             new control_flow::State(this->new_element_id(), fill_debug_info(debug_info_elements), vertex)
61✔
49
         )}
50
    );
51

52
    assert(res.second);
61✔
53
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
61✔
54

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

59
    return *(*res.first).second;
61✔
60
};
×
61

62
control_flow::State& SDFGBuilder::
63
    add_state_before(const control_flow::State& state, bool is_start_state, const DebugInfos& debug_info_elements) {
1✔
64
    auto& new_state = this->add_state(false, debug_info_elements);
1✔
65

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

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

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

79
    if (is_start_state) {
1✔
80
        this->sdfg_->start_state_ = &new_state;
×
81
    }
×
82

83
    return new_state;
1✔
84
};
1✔
85

86
control_flow::State& SDFGBuilder::
87
    add_state_after(const control_flow::State& state, bool connect_states, const DebugInfos& debug_info_elements) {
5✔
88
    auto& new_state = this->add_state(false, debug_info_elements);
5✔
89

90
    std::vector<const control_flow::InterstateEdge*> to_redirect;
5✔
91
    for (auto& e : this->sdfg_->out_edges(state)) to_redirect.push_back(&e);
6✔
92

93
    // Redirect control-flow
94
    for (auto& edge : to_redirect) {
6✔
95
        this->add_edge(new_state, edge->dst(), edge->condition());
1✔
96

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

105
    return new_state;
5✔
106
};
5✔
107

108
control_flow::InterstateEdge& SDFGBuilder::
109
    add_edge(const control_flow::State& src, const control_flow::State& dst, const DebugInfos& debug_info_elements) {
39✔
110
    return this->add_edge(src, dst, control_flow::Assignments{}, SymEngine::boolTrue, debug_info_elements);
39✔
UNCOV
111
};
×
112

113
control_flow::InterstateEdge& SDFGBuilder::add_edge(
8✔
114
    const control_flow::State& src,
115
    const control_flow::State& dst,
116
    const symbolic::Condition condition,
117
    const DebugInfos& debug_info_elements
118
) {
119
    return this->add_edge(src, dst, control_flow::Assignments{}, condition, debug_info_elements);
8✔
120
};
×
121

122
control_flow::InterstateEdge& SDFGBuilder::add_edge(
2✔
123
    const control_flow::State& src,
124
    const control_flow::State& dst,
125
    const control_flow::Assignments& assignments,
126
    const DebugInfos& debug_info_elements
127
) {
128
    return this->add_edge(src, dst, assignments, SymEngine::boolTrue, debug_info_elements);
2✔
129
};
×
130

131
control_flow::InterstateEdge& SDFGBuilder::add_edge(
51✔
132
    const control_flow::State& src,
133
    const control_flow::State& dst,
134
    const control_flow::Assignments& assignments,
135
    const symbolic::Condition condition,
136
    const DebugInfos& debug_info_elements
137
) {
138
    for (auto& entry : assignments) {
55✔
139
        auto& lhs = entry.first;
4✔
140
        auto& type = this->function().type(lhs->get_name());
4✔
141
        if (type.type_id() != types::TypeID::Scalar) {
4✔
142
            throw InvalidSDFGException("Assignment - LHS: must be integer type");
×
143
        }
144

145
        auto& rhs = entry.second;
4✔
146
        for (auto& atom : symbolic::atoms(rhs)) {
5✔
147
            if (symbolic::is_nullptr(atom)) {
1✔
148
                throw InvalidSDFGException("Assignment - RHS: must be integer type, but is nullptr");
×
149
            }
150
            auto& atom_type = this->function().type(atom->get_name());
1✔
151
            if (atom_type.type_id() != types::TypeID::Scalar) {
1✔
152
                throw InvalidSDFGException("Assignment - RHS: must be integer type");
×
153
            }
154
        }
155
    }
156

157
    for (auto& atom : symbolic::atoms(condition)) {
59✔
158
        if (symbolic::is_nullptr(atom)) {
8✔
159
            continue;
×
160
        }
161
        auto& atom_type = this->function().type(atom->get_name());
8✔
162
        if (atom_type.type_id() != types::TypeID::Scalar && atom_type.type_id() != types::TypeID::Pointer) {
8✔
163
            throw InvalidSDFGException("Condition: must be integer type or pointer type");
×
164
        }
165
    }
166

167
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, this->sdfg_->graph_);
51✔
168
    assert(edge.second);
51✔
169

170
    auto res = this->sdfg_->edges_.insert(
102✔
171
        {edge.first,
102✔
172
         std::unique_ptr<control_flow::InterstateEdge>(new control_flow::InterstateEdge(
102✔
173
             this->new_element_id(), fill_debug_info(debug_info_elements), edge.first, src, dst, condition, assignments
51✔
174
         ))}
175
    );
176

177
    assert(res.second);
51✔
178

179
    return *(*res.first).second;
51✔
180
};
×
181

182
void SDFGBuilder::remove_edge(const control_flow::InterstateEdge& edge) {
×
183
    auto desc = edge.edge();
×
184
    this->sdfg_->edges_.erase(desc);
×
185

186
    boost::remove_edge(desc, this->sdfg_->graph_);
×
187
};
×
188

189
std::tuple<control_flow::State&, control_flow::State&, control_flow::State&> SDFGBuilder::add_loop(
1✔
190
    const control_flow::State& state,
191
    sdfg::symbolic::Symbol iterator,
192
    sdfg::symbolic::Expression init,
193
    sdfg::symbolic::Condition cond,
194
    sdfg::symbolic::Expression update,
195
    const DebugInfos& debug_info_elements
196
) {
197
    // Init: iterator = init
198
    auto& init_state = this->add_state_after(state, true, debug_info_elements);
1✔
199
    const graph::Edge init_edge_desc = (*this->sdfg_->in_edges(init_state).begin()).edge_;
1✔
200
    auto& init_edge = this->sdfg_->edges_[init_edge_desc];
1✔
201
    init_edge->assignments_.insert({iterator, init});
1✔
202

203
    // Final state
204
    auto& final_state = this->add_state_after(init_state, false, debug_info_elements);
1✔
205

206
    // Init -> early_exit -> final
207
    auto& early_exit_state = this->add_state(false, debug_info_elements);
1✔
208
    this->add_edge(init_state, early_exit_state, symbolic::Not(cond));
1✔
209
    this->add_edge(early_exit_state, final_state);
1✔
210

211
    // Init -> header -> body
212
    auto& header_state = this->add_state(false, debug_info_elements);
1✔
213
    this->add_edge(init_state, header_state, cond);
1✔
214

215
    auto& body_state = this->add_state(false, debug_info_elements);
1✔
216
    this->add_edge(header_state, body_state);
1✔
217

218
    auto& update_state = this->add_state(false, debug_info_elements);
1✔
219
    this->add_edge(body_state, update_state, {{iterator, update}});
1✔
220

221
    // Back edge and exit edge
222
    this->add_edge(update_state, header_state, cond);
1✔
223
    this->add_edge(update_state, final_state, symbolic::Not(cond));
1✔
224

225
    return {init_state, body_state, final_state};
1✔
226
};
×
227

228
/***** Section: Dataflow Graph *****/
229

230
data_flow::AccessNode& SDFGBuilder::
231
    add_access(control_flow::State& state, const std::string& data, const DebugInfos& debug_info_elements) {
6✔
232
    auto& dataflow = state.dataflow();
6✔
233
    auto vertex = boost::add_vertex(dataflow.graph_);
6✔
234
    auto res = dataflow.nodes_.insert(
12✔
235
        {vertex,
6✔
236
         std::unique_ptr<data_flow::AccessNode>(new data_flow::AccessNode(
12✔
237
             this->new_element_id(), fill_debug_info(debug_info_elements), vertex, dataflow, data
6✔
238
         ))}
239
    );
240

241
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
6✔
242
};
×
243

244
data_flow::Tasklet& SDFGBuilder::add_tasklet(
3✔
245
    control_flow::State& state,
246
    const data_flow::TaskletCode code,
247
    const std::string& output,
248
    const std::vector<std::string>& inputs,
249
    const DebugInfos& debug_info_elements
250
) {
251
    auto& dataflow = state.dataflow();
3✔
252
    auto vertex = boost::add_vertex(dataflow.graph_);
3✔
253
    auto res = dataflow.nodes_.insert(
6✔
254
        {vertex,
3✔
255
         std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
6✔
256
             this->new_element_id(),
3✔
257
             fill_debug_info(debug_info_elements),
3✔
258
             vertex,
3✔
259
             dataflow,
3✔
260
             code,
3✔
261
             output,
3✔
262
             inputs,
3✔
263
             symbolic::__true__()
3✔
264
         ))}
265
    );
266

267
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
3✔
268
};
×
269

270
data_flow::Memlet& SDFGBuilder::add_memlet(
6✔
271
    control_flow::State& state,
272
    data_flow::DataFlowNode& src,
273
    const std::string& src_conn,
274
    data_flow::DataFlowNode& dst,
275
    const std::string& dst_conn,
276
    const data_flow::Subset& subset,
277
    const types::IType& base_type,
278
    const DebugInfos& debug_info_elements
279
) {
280
    auto& dataflow = state.dataflow();
6✔
281
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, dataflow.graph_);
6✔
282
    auto res = dataflow.edges_.insert(
12✔
283
        {edge.first,
12✔
284
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
12✔
285
             this->new_element_id(),
6✔
286
             fill_debug_info(debug_info_elements),
6✔
287
             edge.first,
6✔
288
             dataflow,
6✔
289
             src,
6✔
290
             src_conn,
6✔
291
             dst,
6✔
292
             dst_conn,
6✔
293
             subset,
6✔
294
             base_type
6✔
295
         ))}
296
    );
297

298
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
6✔
299
#ifndef NDEBUG
300
    memlet.validate(*this->sdfg_);
6✔
301
#endif
302

303
    return memlet;
6✔
304
};
×
305

306
data_flow::Memlet& SDFGBuilder::add_memlet(
×
307
    control_flow::State& state,
308
    data_flow::DataFlowNode& src,
309
    const std::string& src_conn,
310
    data_flow::DataFlowNode& dst,
311
    const std::string& dst_conn,
312
    const data_flow::Subset& begin_subset,
313
    const data_flow::Subset& end_subset,
314
    const types::IType& base_type,
315
    const DebugInfos& debug_info_elements
316
) {
317
    auto& dataflow = state.dataflow();
×
318
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, dataflow.graph_);
×
319
    auto res = dataflow.edges_.insert(
×
320
        {edge.first,
×
321
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
×
322
             this->new_element_id(),
×
NEW
323
             fill_debug_info(debug_info_elements),
×
324
             edge.first,
×
325
             dataflow,
×
326
             src,
×
327
             src_conn,
×
328
             dst,
×
329
             dst_conn,
×
330
             begin_subset,
×
331
             end_subset,
×
332
             base_type
×
333
         ))}
334
    );
335
    auto& memlet = dynamic_cast<data_flow::Memlet&>(*(res.first->second));
×
336
#ifndef NDEBUG
337
    memlet.validate(*this->sdfg_);
×
338
#endif
339

340
    return memlet;
×
341
};
×
342

343
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
344
    control_flow::State& state,
345
    data_flow::AccessNode& src,
346
    data_flow::Tasklet& dst,
347
    const std::string& dst_conn,
348
    const data_flow::Subset& subset,
349
    const types::IType& base_type,
350
    const DebugInfos& debug_info_elements
351
) {
NEW
352
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, base_type, debug_info_elements);
×
353
};
×
354

355
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
356
    control_flow::State& state,
357
    data_flow::Tasklet& src,
358
    const std::string& src_conn,
359
    data_flow::AccessNode& dst,
360
    const data_flow::Subset& subset,
361
    const types::IType& base_type,
362
    const DebugInfos& debug_info_elements
363
) {
NEW
364
    return this->add_memlet(state, src, src_conn, dst, "void", subset, base_type, debug_info_elements);
×
365
};
×
366

367
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
3✔
368
    control_flow::State& state,
369
    data_flow::AccessNode& src,
370
    data_flow::Tasklet& dst,
371
    const std::string& dst_conn,
372
    const data_flow::Subset& subset,
373
    const DebugInfos& debug_info_elements
374
) {
375
    auto& src_type = this->function().type(src.data());
3✔
376
    auto& base_type = types::infer_type(this->function(), src_type, subset);
3✔
377
    if (base_type.type_id() != types::TypeID::Scalar) {
3✔
378
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
379
    }
380
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, src_type, debug_info_elements);
3✔
381
};
×
382

383
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
3✔
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 DebugInfos& debug_info_elements
390
) {
391
    auto& dst_type = this->function().type(dst.data());
3✔
392
    auto& base_type = types::infer_type(this->function(), dst_type, subset);
3✔
393
    if (base_type.type_id() != types::TypeID::Scalar) {
3✔
394
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
395
    }
396
    return this->add_memlet(state, src, src_conn, dst, "void", subset, dst_type, debug_info_elements);
3✔
397
};
×
398

399
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
400
    control_flow::State& state,
401
    data_flow::AccessNode& src,
402
    data_flow::LibraryNode& dst,
403
    const std::string& dst_conn,
404
    const data_flow::Subset& begin_subset,
405
    const data_flow::Subset& end_subset,
406
    const types::IType& base_type,
407
    const DebugInfos& debug_info_elements
408
) {
NEW
409
    return this->add_memlet(state, src, "void", dst, dst_conn, begin_subset, end_subset, base_type, debug_info_elements);
×
410
};
×
411

412
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
×
413
    control_flow::State& state,
414
    data_flow::LibraryNode& src,
415
    const std::string& src_conn,
416
    data_flow::AccessNode& dst,
417
    const data_flow::Subset& begin_subset,
418
    const data_flow::Subset& end_subset,
419
    const types::IType& base_type,
420
    const DebugInfos& debug_info_elements
421
) {
NEW
422
    return this->add_memlet(state, src, src_conn, dst, "void", begin_subset, end_subset, base_type, debug_info_elements);
×
423
};
×
424

425
data_flow::Memlet& SDFGBuilder::add_reference_memlet(
×
426
    control_flow::State& state,
427
    data_flow::AccessNode& src,
428
    data_flow::AccessNode& dst,
429
    const data_flow::Subset& subset,
430
    const types::IType& base_type,
431
    const DebugInfos& debug_info_elements
432
) {
NEW
433
    return this->add_memlet(state, src, "void", dst, "ref", subset, base_type, debug_info_elements);
×
434
};
×
435

436
data_flow::Memlet& SDFGBuilder::add_dereference_memlet(
×
437
    control_flow::State& state,
438
    data_flow::AccessNode& src,
439
    data_flow::AccessNode& dst,
440
    bool derefs_src,
441
    const types::IType& base_type,
442
    const DebugInfos& debug_info_elements
443
) {
444
    if (derefs_src) {
×
NEW
445
        return this->add_memlet(state, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info_elements);
×
446
    } else {
NEW
447
        return this->add_memlet(state, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info_elements);
×
448
    }
449
};
×
450

NEW
451
size_t SDFGBuilder::add_debug_info_element(const DebugInfo& element) {
×
NEW
452
    return sdfg_->debug_info().add_element(element);
×
NEW
453
}
×
454

NEW
455
const DebugTable& SDFGBuilder::debug_info() const { return sdfg_->debug_info(); }
×
456

457
} // namespace builder
458
} // 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