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

daisytuner / sdfglib / 16069945621

04 Jul 2025 08:56AM UTC coverage: 64.375% (-0.2%) from 64.606%
16069945621

push

github

web-flow
Merge pull request #137 from daisytuner/clang-format

runs clang-format on codebase

609 of 827 new or added lines in 63 files covered. (73.64%)

46 existing lines in 30 files now uncovered.

8578 of 13325 relevant lines covered (64.38%)

177.24 hits per line

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

64.53
/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_); };
205✔
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)
49✔
16
    : FunctionBuilder(), sdfg_(new SDFG(name, type)) {
49✔
17

18
      };
49✔
19

20
SDFG& SDFGBuilder::subject() const { return *this->sdfg_; };
20✔
21

22
std::unique_ptr<SDFG> SDFGBuilder::move() { return std::move(this->sdfg_); };
31✔
23

24
/***** Section: Control-Flow Graph *****/
25

26
control_flow::State& SDFGBuilder::add_state(bool is_start_state, const DebugInfo& debug_info) {
61✔
27
    auto vertex = boost::add_vertex(this->sdfg_->graph_);
61✔
28
    auto res = this->sdfg_->states_.insert(
122✔
29
        {vertex,
61✔
30
         std::unique_ptr<control_flow::State>(new control_flow::State(this->new_element_id(), debug_info, vertex))}
61✔
31
    );
32

33
    assert(res.second);
61✔
34
    (*res.first).second->dataflow_->parent_ = (*res.first).second.get();
61✔
35

36
    if (is_start_state) {
61✔
37
        this->sdfg_->start_state_ = (*res.first).second.get();
12✔
38
    }
12✔
39

40
    return *(*res.first).second;
61✔
41
};
×
42

43
control_flow::State& SDFGBuilder::
44
    add_state_before(const control_flow::State& state, bool is_start_state, const DebugInfo& debug_info) {
1✔
45
    auto& new_state = this->add_state(false, debug_info);
1✔
46

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

50
    // Redirect control-flow
51
    for (auto edge : to_redirect) {
2✔
52
        this->add_edge(edge->src(), new_state, edge->condition());
1✔
53

54
        auto desc = edge->edge();
1✔
55
        this->sdfg_->edges_.erase(desc);
1✔
56
        boost::remove_edge(desc, this->sdfg_->graph_);
1✔
57
    }
58
    this->add_edge(new_state, state);
1✔
59

60
    if (is_start_state) {
1✔
61
        this->sdfg_->start_state_ = &new_state;
×
62
    }
×
63

64
    return new_state;
1✔
65
};
1✔
66

67
control_flow::State& SDFGBuilder::
68
    add_state_after(const control_flow::State& state, bool connect_states, const DebugInfo& debug_info) {
5✔
69
    auto& new_state = this->add_state(false, debug_info);
5✔
70

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

74
    // Redirect control-flow
75
    for (auto& edge : to_redirect) {
6✔
76
        this->add_edge(new_state, edge->dst(), edge->condition());
1✔
77

78
        auto desc = edge->edge();
1✔
79
        this->sdfg_->edges_.erase(desc);
1✔
80
        boost::remove_edge(desc, this->sdfg_->graph_);
1✔
81
    }
82
    if (connect_states) {
5✔
83
        this->add_edge(state, new_state);
4✔
84
    }
4✔
85

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

89
control_flow::InterstateEdge& SDFGBuilder::
90
    add_edge(const control_flow::State& src, const control_flow::State& dst, const DebugInfo& debug_info) {
39✔
91
    return this->add_edge(src, dst, control_flow::Assignments{}, SymEngine::boolTrue, debug_info);
39✔
92
};
×
93

94
control_flow::InterstateEdge& SDFGBuilder::add_edge(
8✔
95
    const control_flow::State& src,
96
    const control_flow::State& dst,
97
    const symbolic::Condition condition,
98
    const DebugInfo& debug_info
99
) {
100
    return this->add_edge(src, dst, control_flow::Assignments{}, condition, debug_info);
8✔
101
};
×
102

103
control_flow::InterstateEdge& SDFGBuilder::add_edge(
2✔
104
    const control_flow::State& src,
105
    const control_flow::State& dst,
106
    const control_flow::Assignments& assignments,
107
    const DebugInfo& debug_info
108
) {
109
    return this->add_edge(src, dst, assignments, SymEngine::boolTrue, debug_info);
2✔
110
};
×
111

112
control_flow::InterstateEdge& SDFGBuilder::add_edge(
51✔
113
    const control_flow::State& src,
114
    const control_flow::State& dst,
115
    const control_flow::Assignments& assignments,
116
    const symbolic::Condition condition,
117
    const DebugInfo& debug_info
118
) {
119
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, this->sdfg_->graph_);
51✔
120
    assert(edge.second);
51✔
121

122
    auto res = this->sdfg_->edges_.insert(
102✔
123
        {edge.first,
102✔
124
         std::unique_ptr<control_flow::InterstateEdge>(new control_flow::InterstateEdge(
51✔
125
             this->new_element_id(), debug_info, edge.first, src, dst, condition, assignments
51✔
126
         ))}
127
    );
128

129
    assert(res.second);
51✔
130

131
    return *(*res.first).second;
51✔
132
};
×
133

134
void SDFGBuilder::remove_edge(const control_flow::InterstateEdge& edge) {
×
135
    auto desc = edge.edge();
×
136
    this->sdfg_->edges_.erase(desc);
×
137

138
    boost::remove_edge(desc, this->sdfg_->graph_);
×
139
};
×
140

141
std::tuple<control_flow::State&, control_flow::State&, control_flow::State&> SDFGBuilder::add_loop(
1✔
142
    const control_flow::State& state,
143
    sdfg::symbolic::Symbol iterator,
144
    sdfg::symbolic::Expression init,
145
    sdfg::symbolic::Condition cond,
146
    sdfg::symbolic::Expression update,
147
    const DebugInfo& debug_info
148
) {
149
    // Init: iterator = init
150
    auto& init_state = this->add_state_after(state, true, debug_info);
1✔
151
    const graph::Edge init_edge_desc = (*this->sdfg_->in_edges(init_state).begin()).edge_;
1✔
152
    auto& init_edge = this->sdfg_->edges_[init_edge_desc];
1✔
153
    init_edge->assignments_.insert({iterator, init});
1✔
154

155
    // Final state
156
    auto& final_state = this->add_state_after(init_state, false, debug_info);
1✔
157

158
    // Init -> early_exit -> final
159
    auto& early_exit_state = this->add_state(false, debug_info);
1✔
160
    this->add_edge(init_state, early_exit_state, symbolic::Not(cond));
1✔
161
    this->add_edge(early_exit_state, final_state);
1✔
162

163
    // Init -> header -> body
164
    auto& header_state = this->add_state(false, debug_info);
1✔
165
    this->add_edge(init_state, header_state, cond);
1✔
166

167
    auto& body_state = this->add_state(false, debug_info);
1✔
168
    this->add_edge(header_state, body_state);
1✔
169

170
    auto& update_state = this->add_state(false, debug_info);
1✔
171
    this->add_edge(body_state, update_state, {{iterator, update}});
1✔
172

173
    // Back edge and exit edge
174
    this->add_edge(update_state, header_state, cond);
1✔
175
    this->add_edge(update_state, final_state, symbolic::Not(cond));
1✔
176

177
    return {init_state, body_state, final_state};
1✔
178
};
×
179

180
/***** Section: Dataflow Graph *****/
181

182
data_flow::AccessNode& SDFGBuilder::
183
    add_access(control_flow::State& state, const std::string& data, const DebugInfo& debug_info) {
6✔
184
    // Check: Data exists
185
    if (!this->subject().exists(data)) {
6✔
186
        throw InvalidSDFGException("Data does not exist in SDFG: " + data);
×
187
    }
188

189
    auto& dataflow = state.dataflow();
6✔
190
    auto vertex = boost::add_vertex(dataflow.graph_);
6✔
191
    auto res = dataflow.nodes_.insert(
12✔
192
        {vertex,
6✔
193
         std::unique_ptr<
6✔
194
             data_flow::AccessNode>(new data_flow::AccessNode(this->new_element_id(), debug_info, vertex, dataflow, data)
6✔
195
         )}
196
    );
197

198
    return dynamic_cast<data_flow::AccessNode&>(*(res.first->second));
6✔
199
};
×
200

201
data_flow::Tasklet& SDFGBuilder::add_tasklet(
3✔
202
    control_flow::State& state,
203
    const data_flow::TaskletCode code,
204
    const std::pair<std::string, sdfg::types::Scalar>& output,
205
    const std::vector<std::pair<std::string, sdfg::types::Scalar>>& inputs,
206
    const DebugInfo& debug_info
207
) {
208
    // Check: Duplicate inputs
209
    std::unordered_set<std::string> input_names;
3✔
210
    for (auto& input : inputs) {
8✔
211
        if (!input.first.starts_with("_in")) {
5✔
212
            continue;
2✔
213
        }
214
        if (input_names.find(input.first) != input_names.end()) {
3✔
215
            throw InvalidSDFGException("Input " + input.first + " already exists in SDFG");
×
216
        }
217
        input_names.insert(input.first);
3✔
218
    }
219

220
    auto& dataflow = state.dataflow();
3✔
221
    auto vertex = boost::add_vertex(dataflow.graph_);
3✔
222
    auto res = dataflow.nodes_.insert(
6✔
223
        {vertex,
3✔
224
         std::unique_ptr<data_flow::Tasklet>(new data_flow::Tasklet(
6✔
225
             this->new_element_id(), debug_info, vertex, dataflow, code, output, inputs, symbolic::__true__()
3✔
226
         ))}
227
    );
228

229
    return dynamic_cast<data_flow::Tasklet&>(*(res.first->second));
3✔
230
};
3✔
231

232
data_flow::Memlet& SDFGBuilder::add_memlet(
6✔
233
    control_flow::State& state,
234
    data_flow::DataFlowNode& src,
235
    const std::string& src_conn,
236
    data_flow::DataFlowNode& dst,
237
    const std::string& dst_conn,
238
    const data_flow::Subset& subset,
239
    const DebugInfo& debug_info
240
) {
241
    auto& function_ = this->function();
6✔
242

243
    // Check - Case 1: Access Node -> Access Node
244
    // - src_conn or dst_conn must be refs. The other must be void.
245
    // - The side of the memlet that is void, is dereferenced.
246
    // - The dst type must always be a pointer after potential dereferencing.
247
    // - The src type can be any type after dereferecing (&dereferenced_src_type).
248
    if (dynamic_cast<data_flow::AccessNode*>(&src) && dynamic_cast<data_flow::AccessNode*>(&dst)) {
6✔
249
        auto& src_node = dynamic_cast<data_flow::AccessNode&>(src);
×
250
        auto& dst_node = dynamic_cast<data_flow::AccessNode&>(dst);
×
251
        if (src_conn == "refs") {
×
252
            if (dst_conn != "void") {
×
253
                throw InvalidSDFGException("Invalid dst connector: " + dst_conn);
×
254
            }
255

256
            auto& dst_type = types::infer_type(function_, function_.type(dst_node.data()), subset);
×
257
            if (!dynamic_cast<const types::Pointer*>(&dst_type)) {
×
258
                throw InvalidSDFGException("dst type must be a pointer");
×
259
            }
260

261
            auto& src_type = function_.type(src_node.data());
×
262
            if (!dynamic_cast<const types::Pointer*>(&src_type)) {
×
263
                throw InvalidSDFGException("src type must be a pointer");
×
264
            }
265
        } else if (src_conn == "void") {
×
266
            if (dst_conn != "refs") {
×
267
                throw InvalidSDFGException("Invalid dst connector: " + dst_conn);
×
268
            }
269

NEW
270
            if (symbolic::is_pointer(symbolic::symbol(src_node.data())) || helpers::is_number(src_node.data())) {
×
271
                throw InvalidSDFGException("src_conn is void: src cannot be a raw pointer");
×
272
            }
273

274
            // Trivially correct but checks inference
275
            auto& src_type = types::infer_type(function_, function_.type(src_node.data()), subset);
×
276
            types::Pointer ref_type(src_type);
×
277
            if (!dynamic_cast<const types::Pointer*>(&ref_type)) {
278
                throw InvalidSDFGException("src type must be a pointer");
279
            }
280

281
            auto& dst_type = function_.type(dst_node.data());
×
282
            if (!dynamic_cast<const types::Pointer*>(&dst_type)) {
×
283
                throw InvalidSDFGException("dst type must be a pointer");
×
284
            }
285
        } else {
×
286
            throw InvalidSDFGException("Invalid src connector: " + src_conn);
×
287
        }
288
    } else if (dynamic_cast<data_flow::AccessNode*>(&src) && dynamic_cast<data_flow::Tasklet*>(&dst)) {
6✔
289
        auto& src_node = dynamic_cast<data_flow::AccessNode&>(src);
3✔
290
        auto& dst_node = dynamic_cast<data_flow::Tasklet&>(dst);
3✔
291
        if (src_conn != "void") {
3✔
292
            throw InvalidSDFGException("src_conn must be void. Found: " + src_conn);
×
293
        }
294
        bool found = false;
3✔
295
        for (auto& input : dst_node.inputs()) {
3✔
296
            if (input.first == dst_conn) {
3✔
297
                found = true;
3✔
298
                break;
3✔
299
            }
300
        }
301
        if (!found) {
3✔
302
            throw InvalidSDFGException("dst_conn not found in tasklet: " + dst_conn);
×
303
        }
304
        auto& element_type = types::infer_type(function_, function_.type(src_node.data()), subset);
3✔
305
        if (!dynamic_cast<const types::Scalar*>(&element_type)) {
3✔
306
            throw InvalidSDFGException("Tasklets inputs must be scalars");
×
307
        }
308
    } else if (dynamic_cast<data_flow::Tasklet*>(&src) && dynamic_cast<data_flow::AccessNode*>(&dst)) {
6✔
309
        auto& src_node = dynamic_cast<data_flow::Tasklet&>(src);
3✔
310
        auto& dst_node = dynamic_cast<data_flow::AccessNode&>(dst);
3✔
311
        if (src_conn != src_node.output().first) {
3✔
312
            throw InvalidSDFGException("src_conn must match tasklet output name");
×
313
        }
314
        if (dst_conn != "void") {
3✔
315
            throw InvalidSDFGException("dst_conn must be void. Found: " + dst_conn);
×
316
        }
317

318
        auto& element_type = types::infer_type(function_, function_.type(dst_node.data()), subset);
3✔
319
        if (!dynamic_cast<const types::Scalar*>(&element_type)) {
3✔
320
            throw InvalidSDFGException("Tasklet output must be a scalar");
×
321
        }
322
    } else if (dynamic_cast<data_flow::AccessNode*>(&src) && dynamic_cast<data_flow::LibraryNode*>(&dst)) {
3✔
323
        auto& dst_node = dynamic_cast<data_flow::LibraryNode&>(dst);
×
324
        if (src_conn != "void") {
×
325
            throw InvalidSDFGException("src_conn must be void. Found: " + src_conn);
×
326
        }
327
        bool found = false;
×
328
        for (auto& input : dst_node.inputs()) {
×
329
            if (input == dst_conn) {
×
330
                found = true;
×
331
                break;
×
332
            }
333
        }
334
        if (!found) {
×
335
            throw InvalidSDFGException("dst_conn not found in library node: " + dst_conn);
×
336
        }
NEW
337
    } else if (dynamic_cast<data_flow::LibraryNode*>(&src) && dynamic_cast<data_flow::AccessNode*>(&dst)) {
×
338
        auto& src_node = dynamic_cast<data_flow::LibraryNode&>(src);
×
339
        if (dst_conn != "void") {
×
340
            throw InvalidSDFGException("dst_conn must be void. Found: " + dst_conn);
×
341
        }
342
        bool found = false;
×
343
        for (auto& output : src_node.outputs()) {
×
344
            if (output == src_conn) {
×
345
                found = true;
×
346
                break;
×
347
            }
348
        }
349
        if (!found) {
×
350
            throw InvalidSDFGException("src_conn not found in library node: " + src_conn);
×
351
        }
352
    } else {
×
353
        throw InvalidSDFGException("Invalid src or dst node type");
×
354
    }
355

356
    auto& dataflow = state.dataflow();
6✔
357
    auto edge = boost::add_edge(src.vertex_, dst.vertex_, dataflow.graph_);
6✔
358
    auto res = dataflow.edges_.insert(
12✔
359
        {edge.first,
12✔
360
         std::unique_ptr<data_flow::Memlet>(new data_flow::Memlet(
6✔
361
             this->new_element_id(), debug_info, edge.first, dataflow, src, src_conn, dst, dst_conn, subset
6✔
362
         ))}
363
    );
364

365
    return dynamic_cast<data_flow::Memlet&>(*(res.first->second));
6✔
366
};
×
367

368
} // namespace builder
369
} // 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

© 2025 Coveralls, Inc