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

daisytuner / sdfglib / 18690518437

21 Oct 2025 04:19PM UTC coverage: 60.779% (-0.4%) from 61.158%
18690518437

Pull #288

github

web-flow
Merge ccfe2f66e into 41678795b
Pull Request #288: Instrumentation info

107 of 280 new or added lines in 20 files covered. (38.21%)

6 existing lines in 4 files now uncovered.

9397 of 15461 relevant lines covered (60.78%)

91.74 hits per line

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

57.36
/src/codegen/dispatchers/block_dispatcher.cpp
1
#include "sdfg/codegen/dispatchers/block_dispatcher.h"
2

3
#include "sdfg/codegen/dispatchers/node_dispatcher_registry.h"
4
#include "sdfg/codegen/instrumentation/instrumentation_info.h"
5

6
namespace sdfg {
7
namespace codegen {
8

9
BlockDispatcher::BlockDispatcher(
6✔
10
    LanguageExtension& language_extension,
11
    StructuredSDFG& sdfg,
12
    analysis::AnalysisManager& analysis_manager,
13
    structured_control_flow::Block& node,
14
    InstrumentationPlan& instrumentation_plan
15
)
16
    : sdfg::codegen::NodeDispatcher(language_extension, sdfg, analysis_manager, node, instrumentation_plan),
6✔
17
      node_(node) {
6✔
18

19
      };
6✔
20

21
void BlockDispatcher::dispatch_node(
5✔
22
    PrettyPrinter& main_stream, PrettyPrinter& globals_stream, CodeSnippetFactory& library_snippet_factory
23
) {
24
    if (node_.dataflow().nodes().empty()) {
5✔
25
        return;
4✔
26
    }
27

28
    DataFlowDispatcher dispatcher(this->language_extension_, sdfg_, node_.dataflow(), instrumentation_plan_);
1✔
29
    dispatcher.dispatch(main_stream, globals_stream, library_snippet_factory);
1✔
30
};
5✔
31

32
DataFlowDispatcher::DataFlowDispatcher(
10✔
33
    LanguageExtension& language_extension,
34
    const Function& sdfg,
35
    const data_flow::DataFlowGraph& data_flow_graph,
36
    const InstrumentationPlan& instrumentation_plan
37
)
38
    : language_extension_(language_extension), function_(sdfg), data_flow_graph_(data_flow_graph),
10✔
39
      instrumentation_plan_(instrumentation_plan) {
10✔
40

41
      };
10✔
42

43
void DataFlowDispatcher::
44
    dispatch(PrettyPrinter& stream, PrettyPrinter& globals_stream, CodeSnippetFactory& library_snippet_factory) {
10✔
45
    // Dispatch code nodes in topological order
46
    auto nodes = this->data_flow_graph_.topological_sort();
10✔
47
    for (auto& node : nodes) {
35✔
48
        if (auto tasklet = dynamic_cast<const data_flow::Tasklet*>(node)) {
25✔
49
            this->dispatch_tasklet(stream, *tasklet);
3✔
50
        } else if (auto libnode = dynamic_cast<const data_flow::LibraryNode*>(node)) {
25✔
51
            this->dispatch_library_node(stream, globals_stream, library_snippet_factory, *libnode);
1✔
52
        } else if (auto access_node = dynamic_cast<const data_flow::AccessNode*>(node)) {
22✔
53
            for (auto& edge : this->data_flow_graph_.out_edges(*access_node)) {
32✔
54
                if (edge.type() == data_flow::MemletType::Reference) {
11✔
55
                    this->dispatch_ref(stream, edge);
4✔
56
                } else if (edge.type() == data_flow::MemletType::Dereference_Src) {
11✔
57
                    this->dispatch_deref_src(stream, edge);
1✔
58
                } else if (edge.type() == data_flow::MemletType::Dereference_Dst) {
7✔
59
                    this->dispatch_deref_dst(stream, edge);
2✔
60
                }
2✔
61
            }
62
        } else {
21✔
63
            throw InvalidSDFGException("Codegen: Node type not supported");
×
64
        }
65
    }
66
};
10✔
67

68
void DataFlowDispatcher::dispatch_ref(PrettyPrinter& stream, const data_flow::Memlet& memlet) {
4✔
69
    stream << "{" << std::endl;
4✔
70
    stream.setIndent(stream.indent() + 4);
4✔
71

72
    auto& src = dynamic_cast<const data_flow::AccessNode&>(memlet.src());
4✔
73
    auto& dst = dynamic_cast<const data_flow::AccessNode&>(memlet.dst());
4✔
74

75
    auto& subset = memlet.subset();
4✔
76
    auto& base_type = memlet.base_type();
4✔
77

78
    stream << this->language_extension_.access_node(dst);
4✔
79
    stream << " = ";
4✔
80

81
    std::string src_name = this->language_extension_.access_node(src);
4✔
82
    if (dynamic_cast<const data_flow::ConstantNode*>(&src)) {
4✔
83
        stream << src_name;
2✔
84
        stream << this->language_extension_.subset(function_, base_type, subset);
2✔
85
    } else {
2✔
86
        if (base_type.type_id() == types::TypeID::Pointer && !subset.empty()) {
2✔
87
            stream << "&";
1✔
88
            stream << "(" + this->language_extension_.type_cast(src_name, base_type) + ")";
1✔
89
            stream << this->language_extension_.subset(function_, base_type, subset);
1✔
90
        } else {
1✔
91
            stream << "&";
1✔
92
            stream << src_name;
1✔
93
            stream << this->language_extension_.subset(function_, base_type, subset);
1✔
94
        }
95
    }
96

97
    stream << ";";
4✔
98
    stream << std::endl;
4✔
99

100
    stream.setIndent(stream.indent() - 4);
4✔
101
    stream << "}" << std::endl;
4✔
102
};
4✔
103

104
void DataFlowDispatcher::dispatch_deref_src(PrettyPrinter& stream, const data_flow::Memlet& memlet) {
1✔
105
    stream << "{" << std::endl;
1✔
106
    stream.setIndent(stream.indent() + 4);
1✔
107

108
    auto& src = dynamic_cast<const data_flow::AccessNode&>(memlet.src());
1✔
109
    auto& dst = dynamic_cast<const data_flow::AccessNode&>(memlet.dst());
1✔
110
    auto& dst_type = this->function_.type(dst.data());
1✔
111
    auto& base_type = static_cast<const types::Pointer&>(memlet.base_type());
1✔
112

113
    switch (dst_type.type_id()) {
1✔
114
        // first-class values
115
        case types::TypeID::Scalar:
116
        case types::TypeID::Pointer: {
117
            stream << this->language_extension_.access_node(dst);
1✔
118
            stream << " = ";
1✔
119
            stream << "*";
1✔
120

121
            std::string src_name = this->language_extension_.access_node(src);
1✔
122
            stream << "(" << this->language_extension_.type_cast(src_name, base_type) << ")";
1✔
123
            break;
124
        }
1✔
125
        // composite values
126
        case types::TypeID::Array:
127
        case types::TypeID::Structure: {
128
            // Memcpy
129
            std::string dst_name = this->language_extension_.access_node(dst);
×
130
            std::string src_name = this->language_extension_.access_node(src);
×
131
            stream << "memcpy(" << "&" << dst_name;
×
132
            stream << ", ";
×
133
            stream << "(" << src_name << ")";
×
134
            stream << ", ";
×
135
            stream << "sizeof " << dst_name;
×
136
            stream << ")";
×
137
            break;
138
        }
×
139
        case types::TypeID::Reference:
140
        case types::TypeID::Function: {
141
            throw InvalidSDFGException("Memlet: Dereference memlets cannot have reference or function destination types"
×
142
            );
143
        }
144
    }
145
    stream << ";" << std::endl;
1✔
146

147
    stream.setIndent(stream.indent() - 4);
1✔
148
    stream << "}" << std::endl;
1✔
149
};
1✔
150

151
void DataFlowDispatcher::dispatch_deref_dst(PrettyPrinter& stream, const data_flow::Memlet& memlet) {
2✔
152
    stream << "{" << std::endl;
2✔
153
    stream.setIndent(stream.indent() + 4);
2✔
154

155
    auto& src = dynamic_cast<const data_flow::AccessNode&>(memlet.src());
2✔
156
    auto& dst = dynamic_cast<const data_flow::AccessNode&>(memlet.dst());
2✔
157
    const sdfg::types::IType* src_type;
158
    if (auto const_node = dynamic_cast<const data_flow::ConstantNode*>(&src)) {
2✔
159
        src_type = &const_node->type();
1✔
160
    } else {
1✔
161
        src_type = &this->function_.type(src.data());
1✔
162
    }
163
    auto& base_type = static_cast<const types::Pointer&>(memlet.base_type());
2✔
164

165
    switch (src_type->type_id()) {
2✔
166
        // first-class values
167
        case types::TypeID::Scalar:
168
        case types::TypeID::Pointer: {
169
            stream << "*";
2✔
170
            std::string dst_name = this->language_extension_.access_node(dst);
2✔
171
            stream << "(" << this->language_extension_.type_cast(dst_name, base_type) << ")";
2✔
172
            stream << " = ";
2✔
173

174
            stream << this->language_extension_.access_node(src);
2✔
175
            break;
176
        }
2✔
177
        // composite values
178
        case types::TypeID::Array:
179
        case types::TypeID::Structure: {
180
            // Memcpy
181
            std::string src_name = this->language_extension_.access_node(src);
×
182
            std::string dst_name = this->language_extension_.access_node(dst);
×
183
            stream << "memcpy(";
×
184
            stream << "(" << dst_name << ")";
×
185
            stream << ", ";
×
186
            stream << "&" << src_name;
×
187
            stream << ", ";
×
188
            stream << "sizeof " << src_name;
×
189
            stream << ")";
×
190
            break;
191
        }
×
192
        case types::TypeID::Function:
193
        case types::TypeID::Reference: {
194
            throw InvalidSDFGException("Memlet: Dereference memlets cannot have source of type Function or Reference");
×
195
        }
196
    }
197
    stream << ";" << std::endl;
2✔
198

199
    stream.setIndent(stream.indent() - 4);
2✔
200
    stream << "}" << std::endl;
2✔
201
};
2✔
202

203
void DataFlowDispatcher::dispatch_tasklet(PrettyPrinter& stream, const data_flow::Tasklet& tasklet) {
3✔
204
    stream << "{" << std::endl;
3✔
205
    stream.setIndent(stream.indent() + 4);
3✔
206

207
    bool is_unsigned = data_flow::is_unsigned(tasklet.code());
3✔
208

209
    for (auto& iedge : this->data_flow_graph_.in_edges(tasklet)) {
7✔
210
        auto& src = dynamic_cast<const data_flow::AccessNode&>(iedge.src());
4✔
211
        std::string src_name = this->language_extension_.access_node(src);
4✔
212

213
        std::string conn = iedge.dst_conn();
4✔
214
        auto& conn_type = dynamic_cast<const types::Scalar&>(iedge.result_type(this->function_));
4✔
215
        if (is_unsigned) {
4✔
216
            types::Scalar conn_type_unsigned(types::as_unsigned(conn_type.primitive_type()));
×
217
            stream << this->language_extension_.declaration(conn, conn_type_unsigned);
×
218
            stream << " = ";
×
219
        } else {
×
220
            stream << this->language_extension_.declaration(conn, conn_type);
4✔
221
            stream << " = ";
4✔
222
        }
223

224
        // Reinterpret cast for opaque pointers
225
        if (iedge.base_type().type_id() == types::TypeID::Pointer) {
4✔
226
            stream << "(" << this->language_extension_.type_cast(src_name, iedge.base_type()) << ")";
×
227
        } else {
×
228
            stream << src_name;
4✔
229
        }
230

231
        stream << this->language_extension_.subset(function_, iedge.base_type(), iedge.subset()) << ";";
4✔
232
        stream << std::endl;
4✔
233
    }
4✔
234

235
    auto& oedge = *this->data_flow_graph_.out_edges(tasklet).begin();
3✔
236
    std::string out_conn = oedge.src_conn();
3✔
237
    auto& out_conn_type = dynamic_cast<const types::Scalar&>(oedge.result_type(this->function_));
3✔
238
    if (is_unsigned) {
3✔
239
        types::Scalar out_conn_type_unsigned(types::as_unsigned(out_conn_type.primitive_type()));
×
240
        stream << this->language_extension_.declaration(out_conn, out_conn_type_unsigned);
×
241
        stream << ";" << std::endl;
×
242
    } else {
×
243
        stream << this->language_extension_.declaration(out_conn, out_conn_type);
3✔
244
        stream << ";" << std::endl;
3✔
245
    }
246

247

248
    stream << std::endl;
3✔
249
    stream << out_conn << " = ";
3✔
250
    stream << this->language_extension_.tasklet(tasklet) << ";" << std::endl;
3✔
251
    stream << std::endl;
3✔
252

253
    // Write back
254
    for (auto& oedge : this->data_flow_graph_.out_edges(tasklet)) {
6✔
255
        auto& dst = dynamic_cast<const data_flow::AccessNode&>(oedge.dst());
3✔
256

257
        std::string dst_name = this->language_extension_.access_node(dst);
3✔
258

259
        // Reinterpret cast for opaque pointers
260
        if (oedge.base_type().type_id() == types::TypeID::Pointer) {
3✔
261
            stream << "(" << this->language_extension_.type_cast(dst_name, oedge.base_type()) << ")";
×
262
        } else {
×
263
            stream << dst_name;
3✔
264
        }
265

266
        stream << this->language_extension_.subset(function_, oedge.base_type(), oedge.subset()) << " = ";
3✔
267
        stream << oedge.src_conn();
3✔
268
        stream << ";" << std::endl;
3✔
269
    }
3✔
270

271
    stream.setIndent(stream.indent() - 4);
3✔
272
    stream << "}" << std::endl;
3✔
273
};
3✔
274

275
void DataFlowDispatcher::dispatch_library_node(
1✔
276
    PrettyPrinter& stream,
277
    PrettyPrinter& globals_stream,
278
    CodeSnippetFactory& library_snippet_factory,
279
    const data_flow::LibraryNode& libnode
280
) {
281
    auto dispatcher_fn =
282
        LibraryNodeDispatcherRegistry::instance()
2✔
283
            .get_library_node_dispatcher(libnode.code().value() + "::" + libnode.implementation_type().value());
1✔
284
    if (dispatcher_fn) {
1✔
285
        auto dispatcher = dispatcher_fn(this->language_extension_, this->function_, this->data_flow_graph_, libnode);
1✔
286

287
        auto instrument_info = dispatcher->instrumentation_info();
1✔
288
        if (this->instrumentation_plan_.should_instrument(libnode)) {
1✔
NEW
289
            this->instrumentation_plan_.begin_instrumentation(libnode, stream, language_extension_, instrument_info);
×
NEW
290
        }
×
291

292
        dispatcher->dispatch(stream, globals_stream, library_snippet_factory);
1✔
293

294
        if (this->instrumentation_plan_.should_instrument(libnode)) {
1✔
NEW
295
            this->instrumentation_plan_.end_instrumentation(libnode, stream, language_extension_, instrument_info);
×
NEW
296
        }
×
297
    } else {
1✔
298
        throw std::runtime_error(
×
299
            "No library node dispatcher found for library node code: " + std::string(libnode.code().value())
×
300
        );
301
    }
302
};
1✔
303

304
LibraryNodeDispatcher::LibraryNodeDispatcher(
1✔
305
    LanguageExtension& language_extension,
306
    const Function& function,
307
    const data_flow::DataFlowGraph& data_flow_graph,
308
    const data_flow::LibraryNode& node
309
)
310
    : language_extension_(language_extension), function_(function), data_flow_graph_(data_flow_graph), node_(node) {};
1✔
311

312
void LibraryNodeDispatcher::
313
    dispatch(PrettyPrinter& stream, PrettyPrinter& globals_stream, CodeSnippetFactory& library_snippet_factory) {
×
314
    auto& graph = this->node_.get_parent();
×
315

316
    stream << "{" << std::endl;
×
317
    stream.setIndent(stream.indent() + 4);
×
318

319
    // Define and initialize inputs
320
    for (auto& iedge : graph.in_edges(this->node_)) {
×
321
        auto& src = dynamic_cast<const data_flow::AccessNode&>(iedge.src());
×
322
        std::string src_name = this->language_extension_.access_node(src);
×
323

324
        std::string conn = iedge.dst_conn();
×
325
        auto& conn_type = iedge.result_type(this->function_);
×
326
        if (conn_type.type_id() == types::TypeID::Array || conn_type.type_id() == types::TypeID::Structure) {
×
327
            // Handle array and structure types
328
            stream << this->language_extension_.declaration(conn, conn_type) << ";" << std::endl;
×
NEW
329
            stream << "memcpy(" << "&" << conn << ", " << "&" << src_name
×
NEW
330
                   << this->language_extension_.subset(function_, iedge.base_type(), iedge.subset()) << ", sizeof "
×
NEW
331
                   << conn << ");" << std::endl;
×
332
        } else {
×
333
            stream << this->language_extension_.declaration(conn, conn_type);
×
334
            stream << " = ";
×
335

336
            // Reinterpret cast for opaque pointers
337
            if (dynamic_cast<const data_flow::ConstantNode*>(&src)) {
×
338
                stream << src_name;
×
339
            } else {
×
340
                if (iedge.base_type().type_id() == types::TypeID::Pointer) {
×
341
                    stream << "(" << this->language_extension_.type_cast(src_name, iedge.base_type()) << ")";
×
342
                } else {
×
343
                    stream << src_name;
×
344
                }
345
            }
346

347
            stream << this->language_extension_.subset(function_, iedge.base_type(), iedge.subset()) << ";";
×
348
            stream << std::endl;
×
349
        }
350
    }
×
351

352
    // Define outputs
353
    for (auto& oedge : graph.out_edges(this->node_)) {
×
354
        if (std::find(this->node_.inputs().begin(), this->node_.inputs().end(), oedge.src_conn()) !=
×
355
            this->node_.inputs().end()) {
×
356
            continue;
×
357
        }
358

359
        auto& dst = dynamic_cast<const data_flow::AccessNode&>(oedge.dst());
×
360
        std::string dst_name = this->language_extension_.access_node(dst);
×
361

362
        std::string conn = oedge.src_conn();
×
363
        auto& conn_type = oedge.result_type(this->function_);
×
364
        if (conn_type.type_id() == types::TypeID::Array || conn_type.type_id() == types::TypeID::Structure) {
×
365
            // Handle array and structure types
366
            stream << this->language_extension_.declaration(conn, conn_type) << ";" << std::endl;
×
NEW
367
            stream << "memcpy(" << "&" << conn << ", " << "&" << dst_name
×
NEW
368
                   << this->language_extension_.subset(function_, oedge.base_type(), oedge.subset()) << ", sizeof "
×
NEW
369
                   << conn << ");" << std::endl;
×
370
        } else {
×
371
            stream << this->language_extension_.declaration(conn, conn_type);
×
372
            stream << " = ";
×
373

374
            // Reinterpret cast for opaque pointers
375
            if (oedge.base_type().type_id() == types::TypeID::Pointer) {
×
376
                stream << "(" << this->language_extension_.type_cast(dst_name, oedge.base_type()) << ")";
×
377
            } else {
×
378
                stream << dst_name;
×
379
            }
380

381
            stream << this->language_extension_.subset(function_, oedge.base_type(), oedge.subset()) << ";";
×
382
            stream << std::endl;
×
383
        }
384
    }
×
385

386
    stream << std::endl;
×
387

388
    this->dispatch_code(stream, globals_stream, library_snippet_factory);
×
389

390
    stream << std::endl;
×
391

392
    for (auto& oedge : this->data_flow_graph_.out_edges(this->node_)) {
×
393
        auto& dst = dynamic_cast<const data_flow::AccessNode&>(oedge.dst());
×
394
        if (this->function_.is_external(dst.data())) {
×
395
            continue;
×
396
        }
397

398
        std::string dst_name = this->language_extension_.access_node(dst);
×
399

400
        auto& result_type = oedge.result_type(this->function_);
×
401
        if (result_type.type_id() == types::TypeID::Array || result_type.type_id() == types::TypeID::Structure) {
×
NEW
402
            stream << "memcpy(" << "&" << dst_name
×
NEW
403
                   << this->language_extension_.subset(function_, oedge.base_type(), oedge.subset()) << ", " << "&"
×
NEW
404
                   << oedge.src_conn() << ", sizeof " << oedge.src_conn() << ");" << std::endl;
×
405
        } else {
×
406
            stream << dst_name;
×
407
            stream << this->language_extension_.subset(function_, oedge.base_type(), oedge.subset()) << " = ";
×
408
            stream << oedge.src_conn();
×
409
            stream << ";" << std::endl;
×
410
        }
411
    }
×
412

413
    stream.setIndent(stream.indent() - 4);
×
414
    stream << "}" << std::endl;
×
415
}
×
416

417
InstrumentationInfo LibraryNodeDispatcher::instrumentation_info() const {
1✔
418
    return InstrumentationInfo(ElementType_Unknown, TargetType_SEQUENTIAL, -1, node_.element_id(), {});
1✔
NEW
419
};
×
420

421

422
} // namespace codegen
423
} // 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