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

daisytuner / sdfglib / 20498791379

24 Dec 2025 12:27PM UTC coverage: 39.109% (+0.05%) from 39.061%
20498791379

push

github

web-flow
Merge pull request #406 from daisytuner/loop-info-inst

move loopnest index into loop info

13537 of 44946 branches covered (30.12%)

Branch coverage included in aggregate %.

15 of 46 new or added lines in 9 files covered. (32.61%)

1 existing line in 1 file now uncovered.

11669 of 19504 relevant lines covered (59.83%)

84.09 hits per line

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

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

3
#include "sdfg/analysis/loop_analysis.h"
4
#include "sdfg/codegen/dispatchers/node_dispatcher_registry.h"
5
#include "sdfg/codegen/instrumentation/instrumentation_info.h"
6
#include "sdfg/types/structure.h"
7

8
namespace sdfg {
9
namespace codegen {
10

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

23
      };
6✔
24

25
void BlockDispatcher::dispatch_node(
5✔
26
    PrettyPrinter& main_stream, PrettyPrinter& globals_stream, CodeSnippetFactory& library_snippet_factory
27
) {
28
    if (node_.dataflow().nodes().empty()) {
5✔
29
        return;
4✔
30
    }
31

32
    DataFlowDispatcher dispatcher(this->language_extension_, sdfg_, node_.dataflow(), instrumentation_plan_);
1✔
33
    dispatcher.dispatch(main_stream, globals_stream, library_snippet_factory);
1✔
34
};
5✔
35

36
DataFlowDispatcher::DataFlowDispatcher(
10✔
37
    LanguageExtension& language_extension,
38
    const Function& sdfg,
39
    const data_flow::DataFlowGraph& data_flow_graph,
40
    const InstrumentationPlan& instrumentation_plan
41
)
42
    : language_extension_(language_extension), function_(sdfg), data_flow_graph_(data_flow_graph),
10✔
43
      instrumentation_plan_(instrumentation_plan) {
10✔
44

45
      };
10✔
46

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

72
void DataFlowDispatcher::dispatch_ref(PrettyPrinter& stream, const data_flow::Memlet& memlet) {
4✔
73
    stream << "{" << std::endl;
4✔
74
    stream.setIndent(stream.indent() + 4);
4✔
75

76
    auto& src = dynamic_cast<const data_flow::AccessNode&>(memlet.src());
4!
77
    auto& dst = dynamic_cast<const data_flow::AccessNode&>(memlet.dst());
4!
78

79
    auto& subset = memlet.subset();
4✔
80
    auto& base_type = memlet.base_type();
4✔
81

82
    stream << this->language_extension_.access_node(dst);
4!
83
    stream << " = ";
4✔
84

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

101
    stream << ";";
4!
102
    stream << std::endl;
4!
103

104
    stream.setIndent(stream.indent() - 4);
4!
105
    stream << "}" << std::endl;
4!
106
};
4✔
107

108
void DataFlowDispatcher::dispatch_deref_src(PrettyPrinter& stream, const data_flow::Memlet& memlet) {
1✔
109
    stream << "{" << std::endl;
1✔
110
    stream.setIndent(stream.indent() + 4);
1✔
111

112
    auto& src = dynamic_cast<const data_flow::AccessNode&>(memlet.src());
1!
113
    auto& dst = dynamic_cast<const data_flow::AccessNode&>(memlet.dst());
1!
114
    auto& dst_type = this->function_.type(dst.data());
1✔
115
    auto& base_type = static_cast<const types::Pointer&>(memlet.base_type());
1✔
116

117
    switch (dst_type.type_id()) {
1!
118
        // first-class values
119
        case types::TypeID::Scalar:
120
        case types::TypeID::Pointer: {
121
            stream << this->language_extension_.access_node(dst);
1!
122
            stream << " = ";
1✔
123
            stream << "*";
1✔
124

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

151
    stream.setIndent(stream.indent() - 4);
1✔
152
    stream << "}" << std::endl;
1✔
153
};
1✔
154

155
void DataFlowDispatcher::dispatch_deref_dst(PrettyPrinter& stream, const data_flow::Memlet& memlet) {
2✔
156
    stream << "{" << std::endl;
2✔
157
    stream.setIndent(stream.indent() + 4);
2✔
158

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

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

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

203
    stream.setIndent(stream.indent() - 4);
2✔
204
    stream << "}" << std::endl;
2✔
205
};
2✔
206

207
void DataFlowDispatcher::dispatch_tasklet(PrettyPrinter& stream, const data_flow::Tasklet& tasklet) {
3✔
208
    stream << "{" << std::endl;
3✔
209
    stream.setIndent(stream.indent() + 4);
3✔
210

211
    bool is_unsigned = data_flow::is_unsigned(tasklet.code());
3✔
212

213
    for (auto& iedge : this->data_flow_graph_.in_edges(tasklet)) {
7✔
214
        auto& src = dynamic_cast<const data_flow::AccessNode&>(iedge.src());
4!
215
        std::string src_name = this->language_extension_.access_node(src);
4✔
216

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

228
        // Reinterpret cast for opaque pointers
229
        if (iedge.base_type().type_id() == types::TypeID::Pointer) {
4!
230
            stream << "(" << this->language_extension_.type_cast(src_name, iedge.base_type()) << ")";
×
231
        } else {
×
232
            stream << src_name;
4!
233
        }
234

235
        stream << this->language_extension_.subset(iedge.base_type(), iedge.subset()) << ";";
4!
236
        stream << std::endl;
4!
237
    }
4✔
238

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

251

252
    stream << std::endl;
3!
253
    stream << out_conn << " = ";
3!
254
    stream << this->language_extension_.tasklet(tasklet) << ";" << std::endl;
3!
255
    stream << std::endl;
3!
256

257
    // Write back
258
    for (auto& oedge : this->data_flow_graph_.out_edges(tasklet)) {
6!
259
        auto& dst = dynamic_cast<const data_flow::AccessNode&>(oedge.dst());
3!
260

261
        std::string dst_name = this->language_extension_.access_node(dst);
3!
262

263
        // Reinterpret cast for opaque pointers
264
        if (oedge.base_type().type_id() == types::TypeID::Pointer) {
3!
265
            stream << "(" << this->language_extension_.type_cast(dst_name, oedge.base_type()) << ")";
×
266
        } else {
×
267
            stream << dst_name;
3!
268
        }
269

270
        stream << this->language_extension_.subset(oedge.base_type(), oedge.subset()) << " = ";
3!
271
        stream << oedge.src_conn();
3!
272
        stream << ";" << std::endl;
3!
273
    }
3✔
274

275
    stream.setIndent(stream.indent() - 4);
3!
276
    stream << "}" << std::endl;
3!
277
};
3✔
278

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

292
        bool should_instrument = this->instrumentation_plan_.should_instrument(libnode);
1!
293
        std::optional<InstrumentationInfo> instrument_info;
1✔
294
        if (should_instrument) {
1!
295
            instrument_info = dispatcher->instrumentation_info();
×
296
            this->instrumentation_plan_
×
297
                .begin_instrumentation(libnode, stream, language_extension_, instrument_info.value());
×
298
        }
×
299

300
        dispatcher->dispatch(stream, globals_stream, library_snippet_factory);
1!
301

302
        if (should_instrument) {
1!
303
            this->instrumentation_plan_
×
304
                .end_instrumentation(libnode, stream, language_extension_, instrument_info.value());
×
305
        }
×
306
        dispatcher->end_node(stream, applied);
1!
307
    } else {
1✔
308
        throw std::runtime_error(
×
309
            "No library node dispatcher found for library node code: " + std::string(libnode.code().value())
×
310
        );
311
    }
312
};
1✔
313

314
LibraryNodeDispatcher::LibraryNodeDispatcher(
1✔
315
    LanguageExtension& language_extension,
316
    const Function& function,
317
    const data_flow::DataFlowGraph& data_flow_graph,
318
    const data_flow::LibraryNode& node
319
)
320
    : language_extension_(language_extension), function_(function), data_flow_graph_(data_flow_graph), node_(node) {};
1✔
321

322
void LibraryNodeDispatcher::
323
    dispatch(PrettyPrinter& stream, PrettyPrinter& globals_stream, CodeSnippetFactory& library_snippet_factory) {
×
324
    auto& graph = this->node_.get_parent();
×
325

326
    stream << "{" << std::endl;
×
327
    stream.setIndent(stream.indent() + 4);
×
328

329
    // Define and initialize inputs
330
    for (auto& iedge : graph.in_edges(this->node_)) {
×
331
        auto& src = dynamic_cast<const data_flow::AccessNode&>(iedge.src());
×
332
        std::string src_name = this->language_extension_.access_node(src);
×
333

334
        std::string conn = iedge.dst_conn();
×
335
        auto& conn_type = iedge.result_type(this->function_);
×
336
        if (conn_type.type_id() == types::TypeID::Array ||
×
337
            (conn_type.type_id() == types::TypeID::Structure &&
×
338
             !static_cast<const types::Structure&>(conn_type).is_pointer_like())) {
×
339
            // Handle array and structure types
340
            stream << this->language_extension_.declaration(conn, conn_type) << ";" << std::endl;
×
341
            stream << "memcpy(" << "&" << conn << ", " << "&" << src_name
×
342
                   << this->language_extension_.subset(iedge.base_type(), iedge.subset()) << ", sizeof " << conn << ");"
×
343
                   << std::endl;
×
344
        } else {
×
345
            stream << this->language_extension_.declaration(conn, conn_type);
×
346
            stream << " = ";
×
347

348
            // Reinterpret cast for opaque pointers
349
            if (dynamic_cast<const data_flow::ConstantNode*>(&src)) {
×
350
                stream << src_name;
×
351
            } else {
×
352
                if (iedge.base_type().type_id() == types::TypeID::Pointer) {
×
353
                    stream << "(" << this->language_extension_.type_cast(src_name, iedge.base_type()) << ")";
×
354
                } else {
×
355
                    stream << src_name;
×
356
                }
357
            }
358

359
            stream << this->language_extension_.subset(iedge.base_type(), iedge.subset()) << ";";
×
360
            stream << std::endl;
×
361
        }
362
    }
×
363

364
    // Define outputs
365
    for (auto& oedge : graph.out_edges(this->node_)) {
×
366
        if (std::find(this->node_.inputs().begin(), this->node_.inputs().end(), oedge.src_conn()) !=
×
367
            this->node_.inputs().end()) {
×
368
            continue;
×
369
        }
370

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

374
        std::string conn = oedge.src_conn();
×
375
        auto& conn_type = oedge.result_type(this->function_);
×
376
        if (conn_type.type_id() == types::TypeID::Array || conn_type.type_id() == types::TypeID::Structure) {
×
377
            // Handle array and structure types
378
            stream << this->language_extension_.declaration(conn, conn_type) << ";" << std::endl;
×
379
            stream << "memcpy(" << "&" << conn << ", " << "&" << dst_name
×
380
                   << this->language_extension_.subset(oedge.base_type(), oedge.subset()) << ", sizeof " << conn << ");"
×
381
                   << std::endl;
×
382
        } else {
×
383
            stream << this->language_extension_.declaration(conn, conn_type);
×
384
            stream << " = ";
×
385

386
            // Reinterpret cast for opaque pointers
387
            if (oedge.base_type().type_id() == types::TypeID::Pointer) {
×
388
                stream << "(" << this->language_extension_.type_cast(dst_name, oedge.base_type()) << ")";
×
389
            } else {
×
390
                stream << dst_name;
×
391
            }
392

393
            stream << this->language_extension_.subset(oedge.base_type(), oedge.subset()) << ";";
×
394
            stream << std::endl;
×
395
        }
396
    }
×
397

398
    stream << std::endl;
×
399

400
    this->dispatch_code(stream, globals_stream, library_snippet_factory);
×
401

402
    stream << std::endl;
×
403

404
    for (auto& oedge : this->data_flow_graph_.out_edges(this->node_)) {
×
405
        auto& dst = dynamic_cast<const data_flow::AccessNode&>(oedge.dst());
×
406
        if (this->function_.is_external(dst.data())) {
×
407
            continue;
×
408
        }
409

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

412
        auto& result_type = oedge.result_type(this->function_);
×
413
        if (result_type.type_id() == types::TypeID::Array || result_type.type_id() == types::TypeID::Structure) {
×
414
            stream << "memcpy(" << "&" << dst_name
×
415
                   << this->language_extension_.subset(oedge.base_type(), oedge.subset()) << ", " << "&"
×
416
                   << oedge.src_conn() << ", sizeof " << oedge.src_conn() << ");" << std::endl;
×
417
        } else {
×
418
            stream << dst_name;
×
419
            stream << this->language_extension_.subset(oedge.base_type(), oedge.subset()) << " = ";
×
420
            stream << oedge.src_conn();
×
421
            stream << ";" << std::endl;
×
422
        }
423
    }
×
424

425
    stream.setIndent(stream.indent() - 4);
×
426
    stream << "}" << std::endl;
×
427
}
×
428

429
InstrumentationInfo LibraryNodeDispatcher::instrumentation_info() const {
×
NEW
430
    return InstrumentationInfo(node_.element_id(), ElementType_Unknown, TargetType_SEQUENTIAL);
×
431
};
×
432

433

434
} // namespace codegen
435
} // 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