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

daisytuner / sdfglib / 20764569418

06 Jan 2026 10:50PM UTC coverage: 62.168% (+21.4%) from 40.764%
20764569418

push

github

web-flow
Merge pull request #433 from daisytuner/clang-coverage

updates clang coverage flags

14988 of 24109 relevant lines covered (62.17%)

88.57 hits per line

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

75.27
/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_); };
1,747✔
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)
16
    : FunctionBuilder(), sdfg_(new SDFG(name, type)) {
237✔
17

18
      };
237✔
19

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

23
      };
8✔
24

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

27
std::unique_ptr<SDFG> SDFGBuilder::move() { return std::move(this->sdfg_); };
20✔
28

29
void SDFGBuilder::rename_container(const std::string& old_name, const std::string& new_name) const {
×
30
    FunctionBuilder::rename_container(old_name, new_name);
×
31

32
    for (auto& entry : this->sdfg_->states_) {
×
33
        entry.second->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
34
    }
×
35
    for (auto& entry : this->sdfg_->edges_) {
×
36
        entry.second->replace(symbolic::symbol(old_name), symbolic::symbol(new_name));
×
37
    }
×
38
}
×
39

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

42
control_flow::State& SDFGBuilder::add_state(bool is_start_state, const DebugInfo& debug_info) {
252✔
43
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
252✔
44
    auto res = this->sdfg_->states_.insert(
252✔
45
        {vertex,
252✔
46
         std::unique_ptr<control_flow::State>(new control_flow::State(this->new_element_id(), debug_info, vertex))}
252✔
47
    );
252✔
48

49
    assert(res.second);
252✔
50
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
252✔
51

52
    if (is_start_state) {
252✔
53
        this->sdfg_->start_state_ = (*res.first).second.get();
43✔
54
    }
43✔
55

56
    return *(*res.first).second;
252✔
57
};
252✔
58

59
control_flow::State& SDFGBuilder::
60
    add_state_before(const control_flow::State& state, bool is_start_state, const DebugInfo& debug_info) {
1✔
61
    auto& new_state = this->add_state(false, debug_info);
1✔
62

63
    std::vector<const control_flow::InterstateEdge*> to_redirect;
1✔
64
    for (auto& e : this->sdfg_->in_edges(state)) to_redirect.push_back(&e);
1✔
65

66
    // Redirect control-flow
67
    for (auto edge : to_redirect) {
1✔
68
        this->add_edge(edge->src(), new_state, edge->condition());
1✔
69

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

76
    if (is_start_state) {
1✔
77
        this->sdfg_->start_state_ = &new_state;
×
78
    }
×
79

80
    return new_state;
1✔
81
};
1✔
82

83
control_flow::State& SDFGBuilder::
84
    add_state_after(const control_flow::State& state, bool connect_states, const DebugInfo& debug_info) {
4✔
85
    auto& new_state = this->add_state(false, debug_info);
4✔
86

87
    std::vector<const control_flow::InterstateEdge*> to_redirect;
4✔
88
    for (auto& e : this->sdfg_->out_edges(state)) to_redirect.push_back(&e);
4✔
89

90
    // Redirect control-flow
91
    for (auto& edge : to_redirect) {
4✔
92
        this->add_edge(new_state, edge->dst(), edge->condition());
1✔
93

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

102
    return new_state;
4✔
103
};
4✔
104

105
control_flow::ReturnState& SDFGBuilder::add_return_state(const std::string& data, const DebugInfo& debug_info) {
26✔
106
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
26✔
107
    auto res = this->sdfg_->states_.insert(
26✔
108
        {vertex,
26✔
109
         std::unique_ptr<
26✔
110
             control_flow::State>(new control_flow::ReturnState(this->new_element_id(), debug_info, vertex, data))}
26✔
111
    );
26✔
112

113
    assert(res.second);
26✔
114
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
26✔
115

116
    return static_cast<control_flow::ReturnState&>(*(*res.first).second);
26✔
117
};
26✔
118

119
control_flow::ReturnState& SDFGBuilder::
120
    add_return_state_after(const control_flow::State& state, const std::string& data, const DebugInfo& debug_info) {
4✔
121
    auto& new_state = this->add_return_state(data, debug_info);
4✔
122

123
    std::vector<const control_flow::InterstateEdge*> to_redirect;
4✔
124
    for (auto& e : this->sdfg_->out_edges(state)) to_redirect.push_back(&e);
4✔
125

126
    // Redirect control-flow
127
    for (auto& edge : to_redirect) {
4✔
128
        this->add_edge(new_state, edge->dst(), edge->condition());
×
129

130
        auto desc = edge->edge();
×
131
        this->sdfg_->edges_.erase(desc);
×
132
        boost::remove_edge(desc, this->sdfg_->graph_);
×
133
    }
×
134
    this->add_edge(state, new_state);
4✔
135

136
    return new_state;
4✔
137
};
4✔
138

139
control_flow::ReturnState& SDFGBuilder::
140
    add_constant_return_state(const std::string& data, const types::IType& type, const DebugInfo& debug_info) {
1✔
141
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
1✔
142
    auto res = this->sdfg_->states_.insert(
1✔
143
        {vertex,
1✔
144
         std::unique_ptr<
1✔
145
             control_flow::State>(new control_flow::ReturnState(this->new_element_id(), debug_info, vertex, data, type))
1✔
146
        }
1✔
147
    );
1✔
148

149
    assert(res.second);
1✔
150
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
1✔
151

152
    return static_cast<control_flow::ReturnState&>(*(*res.first).second);
1✔
153
};
1✔
154

155
control_flow::ReturnState& SDFGBuilder::add_constant_return_state_after(
156
    const control_flow::State& state, const std::string& data, const types::IType& type, const DebugInfo& debug_info
157
) {
×
158
    auto& new_state = this->add_constant_return_state(data, type, debug_info);
×
159

160
    std::vector<const control_flow::InterstateEdge*> to_redirect;
×
161
    for (auto& e : this->sdfg_->out_edges(state)) to_redirect.push_back(&e);
×
162

163
    // Redirect control-flow
164
    for (auto& edge : to_redirect) {
×
165
        this->add_edge(new_state, edge->dst(), edge->condition());
×
166

167
        auto desc = edge->edge();
×
168
        this->sdfg_->edges_.erase(desc);
×
169
        boost::remove_edge(desc, this->sdfg_->graph_);
×
170
    }
×
171
    this->add_edge(state, new_state);
×
172

173
    return new_state;
×
174
};
×
175

176
control_flow::InterstateEdge& SDFGBuilder::
177
    add_edge(const control_flow::State& src, const control_flow::State& dst, const DebugInfo& debug_info) {
75✔
178
    return this->add_edge(src, dst, control_flow::Assignments{}, SymEngine::boolTrue, debug_info);
75✔
179
};
75✔
180

181
control_flow::InterstateEdge& SDFGBuilder::add_edge(
182
    const control_flow::State& src,
183
    const control_flow::State& dst,
184
    const symbolic::Condition condition,
185
    const DebugInfo& debug_info
186
) {
28✔
187
    return this->add_edge(src, dst, control_flow::Assignments{}, condition, debug_info);
28✔
188
};
28✔
189

190
control_flow::InterstateEdge& SDFGBuilder::add_edge(
191
    const control_flow::State& src,
192
    const control_flow::State& dst,
193
    const control_flow::Assignments& assignments,
194
    const DebugInfo& debug_info
195
) {
19✔
196
    return this->add_edge(src, dst, assignments, SymEngine::boolTrue, debug_info);
19✔
197
};
19✔
198

199
control_flow::InterstateEdge& SDFGBuilder::add_edge(
200
    const control_flow::State& src,
201
    const control_flow::State& dst,
202
    const control_flow::Assignments& assignments,
203
    const symbolic::Condition condition,
204
    const DebugInfo& debug_info
205
) {
167✔
206
    if (dynamic_cast<const control_flow::ReturnState*>(&src) != nullptr) {
167✔
207
        throw InvalidSDFGException("Cannot add edge from ReturnState");
1✔
208
    }
1✔
209

210
    for (auto& entry : assignments) {
166✔
211
        auto& lhs = entry.first;
33✔
212
        auto& type = this->function().type(lhs->get_name());
33✔
213
        if (type.type_id() != types::TypeID::Scalar) {
33✔
214
            throw InvalidSDFGException("Assignment - LHS: must be scalar type");
×
215
        }
×
216
        if (!types::is_integer(type.primitive_type())) {
33✔
217
            throw InvalidSDFGException("Assignment - LHS: must be integer type");
×
218
        }
×
219

220
        auto& rhs = entry.second;
33✔
221
        for (auto& atom : symbolic::atoms(rhs)) {
33✔
222
            if (symbolic::is_nullptr(atom)) {
21✔
223
                continue;
×
224
            }
×
225
            auto& atom_type = this->function().type(atom->get_name());
21✔
226

227
            // Scalar integers
228
            if (atom_type.type_id() == types::TypeID::Scalar) {
21✔
229
                if (!types::is_integer(atom_type.primitive_type())) {
21✔
230
                    throw InvalidSDFGException("Assignment - RHS: must evaluate to integer type");
×
231
                }
×
232
                continue;
21✔
233
            } else if (atom_type.type_id() == types::TypeID::Pointer) {
21✔
234
                continue;
×
235
            } else {
×
236
                throw InvalidSDFGException("Assignment - RHS: must evaluate to integer or pointer type");
×
237
            }
×
238
        }
21✔
239
    }
33✔
240

241
    for (auto& atom : symbolic::atoms(condition)) {
166✔
242
        if (symbolic::is_nullptr(atom)) {
75✔
243
            continue;
1✔
244
        }
1✔
245
        auto& atom_type = this->function().type(atom->get_name());
74✔
246
        if (atom_type.type_id() != types::TypeID::Scalar && atom_type.type_id() != types::TypeID::Pointer) {
74✔
247
            throw InvalidSDFGException("Condition: must be integer type or pointer type");
×
248
        }
×
249
    }
74✔
250

251
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, this->sdfg_->graph_);
166✔
252
    assert(edge.second);
166✔
253

254
    auto res = this->sdfg_->edges_.insert(
166✔
255
        {edge.first,
166✔
256
         std::unique_ptr<control_flow::InterstateEdge>(new control_flow::InterstateEdge(
166✔
257
             this->new_element_id(), debug_info, edge.first, src, dst, condition, assignments
166✔
258
         ))}
166✔
259
    );
166✔
260

261
    assert(res.second);
166✔
262

263
    return *(*res.first).second;
166✔
264
};
166✔
265

266
void SDFGBuilder::remove_edge(const control_flow::InterstateEdge& edge) {
×
267
    auto desc = edge.edge();
×
268
    this->sdfg_->edges_.erase(desc);
×
269

270
    boost::remove_edge(desc, this->sdfg_->graph_);
×
271
};
×
272

273
std::tuple<control_flow::State&, control_flow::State&, control_flow::State&> SDFGBuilder::add_loop(
274
    const control_flow::State& state,
275
    sdfg::symbolic::Symbol iterator,
276
    sdfg::symbolic::Expression init,
277
    sdfg::symbolic::Condition cond,
278
    sdfg::symbolic::Expression update,
279
    const DebugInfo& debug_info
280
) {
1✔
281
    // Init: iterator = init
282
    auto& init_state = this->add_state_after(state, true, debug_info);
1✔
283
    const graph::Edge init_edge_desc = (*this->sdfg_->in_edges(init_state).begin()).edge_;
1✔
284
    auto& init_edge = this->sdfg_->edges_[init_edge_desc];
1✔
285
    init_edge->assignments_.insert({iterator, init});
1✔
286

287
    // Final state
288
    auto& final_state = this->add_state_after(init_state, false, debug_info);
1✔
289

290
    // Init -> early_exit -> final
291
    auto& early_exit_state = this->add_state(false, debug_info);
1✔
292
    this->add_edge(init_state, early_exit_state, symbolic::Not(cond));
1✔
293
    this->add_edge(early_exit_state, final_state);
1✔
294

295
    // Init -> header -> body
296
    auto& header_state = this->add_state(false, debug_info);
1✔
297
    this->add_edge(init_state, header_state, cond);
1✔
298

299
    auto& body_state = this->add_state(false, debug_info);
1✔
300
    this->add_edge(header_state, body_state);
1✔
301

302
    auto& update_state = this->add_state(false, debug_info);
1✔
303
    this->add_edge(body_state, update_state, {{iterator, update}});
1✔
304

305
    // Back edge and exit edge
306
    this->add_edge(update_state, header_state, cond);
1✔
307
    this->add_edge(update_state, final_state, symbolic::Not(cond));
1✔
308

309
    return {init_state, body_state, final_state};
1✔
310
};
1✔
311

312
/***** Section: Dataflow Graph *****/
313

314
data_flow::AccessNode& SDFGBuilder::
315
    add_access(control_flow::State& state, const std::string& data, const DebugInfo& debug_info) {
194✔
316
    auto& dataflow = state.dataflow();
194✔
317
    auto vertex = boost::add_vertex(dataflow.graph_);
194✔
318
    auto res = dataflow.nodes_.insert(
194✔
319
        {vertex,
194✔
320
         std::unique_ptr<
194✔
321
             data_flow::AccessNode>(new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, dataflow, data)
194✔
322
         )}
194✔
323
    );
194✔
324

325
    return static_cast<data_flow::AccessNode&>(*(res.first->second));
194✔
326
};
194✔
327

328
data_flow::ConstantNode& SDFGBuilder::add_constant(
329
    control_flow::State& state, const std::string& data, const types::IType& type, const DebugInfo& debug_info
330
) {
19✔
331
    auto& dataflow = state.dataflow();
19✔
332
    auto vertex = boost::add_vertex(dataflow.graph_);
19✔
333
    auto res = dataflow.nodes_.insert(
19✔
334
        {vertex,
19✔
335
         std::unique_ptr<data_flow::ConstantNode>(
19✔
336
             new data_flow::ConstantNode(this->new_element_id(), debug_info, vertex, dataflow, data, type)
19✔
337
         )}
19✔
338
    );
19✔
339

340
    return static_cast<data_flow::ConstantNode&>(*(res.first->second));
19✔
341
};
19✔
342

343
data_flow::Tasklet& SDFGBuilder::add_tasklet(
344
    control_flow::State& state,
345
    const data_flow::TaskletCode code,
346
    const std::string& output,
347
    const std::vector<std::string>& inputs,
348
    const DebugInfo& debug_info
349
) {
103✔
350
    auto& dataflow = state.dataflow();
103✔
351
    auto vertex = boost::add_vertex(dataflow.graph_);
103✔
352
    auto res = dataflow.nodes_.insert(
103✔
353
        {vertex,
103✔
354
         std::unique_ptr<data_flow::Tasklet>(
103✔
355
             new data_flow::Tasklet(this->new_element_id(), debug_info, vertex, dataflow, code, output, inputs)
103✔
356
         )}
103✔
357
    );
103✔
358

359
    return static_cast<data_flow::Tasklet&>(*(res.first->second));
103✔
360
};
103✔
361

362
data_flow::Memlet& SDFGBuilder::add_memlet(
363
    control_flow::State& state,
364
    data_flow::DataFlowNode& src,
365
    const std::string& src_conn,
366
    data_flow::DataFlowNode& dst,
367
    const std::string& dst_conn,
368
    const data_flow::Subset& subset,
369
    const types::IType& base_type,
370
    const DebugInfo& debug_info
371
) {
232✔
372
    auto& dataflow = state.dataflow();
232✔
373
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, dataflow.graph_);
232✔
374
    auto res = dataflow.edges_.insert(
232✔
375
        {edge.first,
232✔
376
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
232✔
377
             this->new_element_id(), debug_info, edge.first, dataflow, src, src_conn, dst, dst_conn, subset, base_type
232✔
378
         ))}
232✔
379
    );
232✔
380

381
    auto& memlet = static_cast<data_flow::Memlet&>(*(res.first->second));
232✔
382

383
    return memlet;
232✔
384
};
232✔
385

386
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
387
    control_flow::State& state,
388
    data_flow::AccessNode& src,
389
    data_flow::Tasklet& dst,
390
    const std::string& dst_conn,
391
    const data_flow::Subset& subset,
392
    const types::IType& base_type,
393
    const DebugInfo& debug_info
394
) {
×
395
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, base_type, debug_info);
×
396
};
×
397

398
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
399
    control_flow::State& state,
400
    data_flow::Tasklet& src,
401
    const std::string& src_conn,
402
    data_flow::AccessNode& dst,
403
    const data_flow::Subset& subset,
404
    const types::IType& base_type,
405
    const DebugInfo& debug_info
406
) {
×
407
    return this->add_memlet(state, src, src_conn, dst, "void", subset, base_type, debug_info);
×
408
};
×
409

410
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
411
    control_flow::State& state,
412
    data_flow::AccessNode& src,
413
    data_flow::Tasklet& dst,
414
    const std::string& dst_conn,
415
    const data_flow::Subset& subset,
416
    const DebugInfo& debug_info
417
) {
122✔
418
    const types::IType* src_type = nullptr;
122✔
419
    if (auto cnode = dynamic_cast<data_flow::ConstantNode*>(&src)) {
122✔
420
        src_type = &cnode->type();
4✔
421
    } else {
118✔
422
        src_type = &this->sdfg_->type(src.data());
118✔
423
    }
118✔
424
    auto& base_type = types::infer_type(*this->sdfg_, *src_type, subset);
122✔
425
    if (base_type.type_id() != types::TypeID::Scalar) {
122✔
426
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
427
    }
×
428
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, *src_type, debug_info);
122✔
429
};
122✔
430

431
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
432
    control_flow::State& state,
433
    data_flow::Tasklet& src,
434
    const std::string& src_conn,
435
    data_flow::AccessNode& dst,
436
    const data_flow::Subset& subset,
437
    const DebugInfo& debug_info
438
) {
104✔
439
    auto& dst_type = this->function().type(dst.data());
104✔
440
    auto& base_type = types::infer_type(this->function(), dst_type, subset);
104✔
441
    if (base_type.type_id() != types::TypeID::Scalar) {
104✔
442
        throw InvalidSDFGException("Computational memlet must have a scalar type");
×
443
    }
×
444
    return this->add_memlet(state, src, src_conn, dst, "void", subset, dst_type, debug_info);
104✔
445
};
104✔
446

447
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
448
    control_flow::State& state,
449
    data_flow::AccessNode& src,
450
    data_flow::LibraryNode& dst,
451
    const std::string& dst_conn,
452
    const data_flow::Subset& subset,
453
    const types::IType& base_type,
454
    const DebugInfo& debug_info
455
) {
2✔
456
    return this->add_memlet(state, src, "void", dst, dst_conn, subset, base_type, debug_info);
2✔
457
};
2✔
458

459
data_flow::Memlet& SDFGBuilder::add_computational_memlet(
460
    control_flow::State& state,
461
    data_flow::LibraryNode& src,
462
    const std::string& src_conn,
463
    data_flow::AccessNode& dst,
464
    const data_flow::Subset& subset,
465
    const types::IType& base_type,
466
    const DebugInfo& debug_info
467
) {
4✔
468
    return this->add_memlet(state, src, src_conn, dst, "void", subset, base_type, debug_info);
4✔
469
};
4✔
470

471
data_flow::Memlet& SDFGBuilder::add_reference_memlet(
472
    control_flow::State& state,
473
    data_flow::AccessNode& src,
474
    data_flow::AccessNode& dst,
475
    const data_flow::Subset& subset,
476
    const types::IType& base_type,
477
    const DebugInfo& debug_info
478
) {
×
479
    return this->add_memlet(state, src, "void", dst, "ref", subset, base_type, debug_info);
×
480
};
×
481

482
data_flow::Memlet& SDFGBuilder::add_dereference_memlet(
483
    control_flow::State& state,
484
    data_flow::AccessNode& src,
485
    data_flow::AccessNode& dst,
486
    bool derefs_src,
487
    const types::IType& base_type,
488
    const DebugInfo& debug_info
489
) {
×
490
    if (derefs_src) {
×
491
        return this->add_memlet(state, src, "void", dst, "deref", {symbolic::zero()}, base_type, debug_info);
×
492
    } else {
×
493
        return this->add_memlet(state, src, "deref", dst, "void", {symbolic::zero()}, base_type, debug_info);
×
494
    }
×
495
};
×
496

497
} // namespace builder
498
} // 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