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

daisytuner / sdfglib / 16779684622

06 Aug 2025 02:21PM UTC coverage: 64.3% (-1.0%) from 65.266%
16779684622

push

github

web-flow
Merge pull request #172 from daisytuner/opaque-pointers

Opaque pointers, typed memlets, untyped tasklet connectors

330 of 462 new or added lines in 38 files covered. (71.43%)

382 existing lines in 30 files now uncovered.

8865 of 13787 relevant lines covered (64.3%)

116.73 hits per line

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

69.9
/src/data_flow/memlet.cpp
1
#include <sdfg/data_flow/memlet.h>
2

3
#include "sdfg/data_flow/library_node.h"
4
#include "sdfg/data_flow/tasklet.h"
5
#include "sdfg/function.h"
6
#include "sdfg/symbolic/symbolic.h"
7
#include "sdfg/types/utils.h"
8

9
namespace sdfg {
10
namespace data_flow {
11

12
Memlet::Memlet(
505✔
13
    size_t element_id,
14
    const DebugInfo& debug_info,
15
    const graph::Edge& edge,
16
    DataFlowGraph& parent,
17
    DataFlowNode& src,
18
    const std::string& src_conn,
19
    DataFlowNode& dst,
20
    const std::string& dst_conn,
21
    const Subset& subset,
22
    const types::IType& base_type
23
)
24
    : Element(element_id, debug_info), edge_(edge), parent_(&parent), src_(src), dst_(dst), src_conn_(src_conn),
1,010✔
25
      dst_conn_(dst_conn), begin_subset_(subset), end_subset_(subset), base_type_(base_type.clone()) {
505✔
26

27
      };
505✔
28

29
Memlet::Memlet(
41✔
30
    size_t element_id,
31
    const DebugInfo& debug_info,
32
    const graph::Edge& edge,
33
    DataFlowGraph& parent,
34
    DataFlowNode& src,
35
    const std::string& src_conn,
36
    DataFlowNode& dst,
37
    const std::string& dst_conn,
38
    const Subset& begin_subset,
39
    const Subset& end_subset,
40
    const types::IType& base_type
41
)
42
    : Element(element_id, debug_info), edge_(edge), parent_(&parent), src_(src), dst_(dst), src_conn_(src_conn),
82✔
43
      dst_conn_(dst_conn), begin_subset_(begin_subset), end_subset_(end_subset), base_type_(base_type.clone()) {
41✔
44

45
      };
41✔
46

47
void Memlet::validate(const Function& function) const {
1,019✔
48
    // Case 1: Computational Memlet (Tasklet)
49
    if (auto tasklet = dynamic_cast<const Tasklet*>(&this->src_)) {
1,019✔
50
        if (!dynamic_cast<const AccessNode*>(&this->dst_)) {
636✔
51
            throw InvalidSDFGException("Memlet: Computational memlet must have an access node destination");
×
52
        }
53
        if (this->dst_conn_ != "void") {
636✔
54
            throw InvalidSDFGException("Memlet: Computation memlets must have a void destination");
×
55
        }
56
        if (tasklet->output() != this->src_conn_) {
636✔
57
            throw InvalidSDFGException("Memlet: Computation memlet must have an output in the tasklet");
×
58
        }
59

60
        // Criterion: Must be a scalar
61
        auto& deref_type = types::infer_type(function, *this->base_type_, this->begin_subset_);
636✔
62
        if (deref_type.type_id() != types::TypeID::Scalar) {
636✔
63
            throw InvalidSDFGException("Memlet: Computation memlets must have a scalar destination");
×
64
        }
65

66
        return;
636✔
67
    } else if (auto tasklet = dynamic_cast<const Tasklet*>(&this->dst_)) {
383✔
68
        if (!dynamic_cast<const AccessNode*>(&this->src_)) {
316✔
69
            throw InvalidSDFGException("Memlet: Computation memlet must have an access node source");
×
70
        }
71
        if (this->src_conn_ != "void") {
316✔
72
            throw InvalidSDFGException("Memlet: Computation memlets must have a void source");
×
73
        }
74
        bool found_conn = false;
316✔
75
        for (auto& conn : tasklet->inputs()) {
428✔
76
            if (conn == this->dst_conn_) {
428✔
77
                found_conn = true;
316✔
78
                break;
316✔
79
            }
80
        }
81
        if (!found_conn) {
316✔
82
            throw InvalidSDFGException("Memlet: Computation memlet must have an input in the tasklet");
×
83
        }
84

85
        // Criterion: Must be a scalar
86
        auto& deref_type = types::infer_type(function, *this->base_type_, this->begin_subset_);
316✔
87
        if (deref_type.type_id() != types::TypeID::Scalar) {
316✔
88
            throw InvalidSDFGException("Memlet: Computation memlets must have a scalar source");
×
89
        }
90
        return;
316✔
91
    }
92

93
    // Case 2: Computational Memlet (LibraryNode)
94
    if (auto libnode = dynamic_cast<const LibraryNode*>(&this->src_)) {
67✔
95
        if (!dynamic_cast<const AccessNode*>(&this->dst_)) {
16✔
96
            throw InvalidSDFGException("Memlet: Computational memlet must have an access node destination");
×
97
        }
98
        if (this->dst_conn_ != "void") {
16✔
99
            throw InvalidSDFGException("Memlet: Computation memlets must have a void destination");
×
100
        }
101

102
        bool found_conn = false;
16✔
103
        for (auto& conn : libnode->outputs()) {
16✔
104
            if (conn == this->src_conn_) {
16✔
105
                found_conn = true;
16✔
106
                break;
16✔
107
            }
108
        }
109
        if (!found_conn) {
16✔
110
            throw InvalidSDFGException("Memlet: Computation memlet must have an output in the library node");
×
111
        }
112
        return;
16✔
113
    } else if (auto libnode = dynamic_cast<const LibraryNode*>(&this->dst_)) {
51✔
114
        if (!dynamic_cast<const AccessNode*>(&this->src_)) {
21✔
115
            throw InvalidSDFGException("Memlet: Computational memlet must have an access node source");
×
116
        }
117
        if (this->src_conn_ != "void") {
21✔
118
            throw InvalidSDFGException("Memlet: Computation memlets must have a void source");
×
119
        }
120

121
        bool found_conn = false;
21✔
122
        for (auto& conn : libnode->inputs()) {
27✔
123
            if (conn == this->dst_conn_) {
27✔
124
                found_conn = true;
21✔
125
                break;
21✔
126
            }
127
        }
128
        if (!found_conn) {
21✔
129
            throw InvalidSDFGException("Memlet: Computation memlet must have an input in the library node");
×
130
        }
131
        return;
21✔
132
    }
133

134
    // Case 3: Reference Memlet (Address Calculation)
135
    if (this->dst_conn_ == "ref") {
30✔
136
        if (this->src_conn_ != "void") {
16✔
137
            throw InvalidSDFGException("Memlet: Reference memlets must have a void source");
×
138
        }
139
        auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
16✔
140
        if (!src_node) {
16✔
141
            throw InvalidSDFGException("Memlet: Reference memlets must have an access node source");
×
142
        }
143
        auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
16✔
144
        if (!dst_node) {
16✔
145
            throw InvalidSDFGException("Memlet: Reference memlets must have an access node destination");
×
146
        }
147

148
        // Criterion: Reference memlets for raw addresses must not have a subset
149
        if (helpers::is_number(src_node->data()) || symbolic::is_nullptr(symbolic::symbol(src_node->data()))) {
16✔
150
            if (!this->begin_subset_.empty()) {
4✔
151
                throw InvalidSDFGException("Memlet: Reference memlets for raw addresses must not have a subset");
×
152
            }
153
        }
4✔
154

155
        // Criterion: Destination must be a pointer
156
        auto dst_data = dst_node->data();
16✔
157
        auto& dst_type = function.type(dst_data);
16✔
158
        if (dst_type.type_id() != types::TypeID::Pointer) {
16✔
159
            throw InvalidSDFGException("Memlet: Reference memlets must have a pointer destination");
×
160
        }
161

162
        // Criterion: Must be a contiguous memory reference
163
        // Throws exception if not contiguous
164
        auto& ref_type = types::infer_type(function, *this->base_type_, this->begin_subset_);
16✔
165

166
        return;
167
    }
16✔
168

169
    // Case 4: Dereference Memlet (Load/Store from/to pointer)
170
    if (this->src_conn_ == "deref") {
14✔
171
        if (this->dst_conn_ != "void") {
8✔
172
            throw InvalidSDFGException("Memlet: Dereference memlets must have a void destination");
×
173
        }
174
        auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
8✔
175
        if (!src_node) {
8✔
176
            throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
177
        }
178
        auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
8✔
179
        if (!dst_node) {
8✔
180
            throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
181
        }
182

183
        // Criterion: Dereference memlets must have '0' as the only dimension
184
        if (this->begin_subset_.size() != 1) {
8✔
185
            throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
186
        }
187
        if (!symbolic::eq(this->begin_subset_[0], symbolic::integer(0))) {
8✔
188
            throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
189
        }
190

191
        // Criterion: Source must be a pointer
192
        auto src_data = src_node->data();
8✔
193
        auto& src_type = function.type(src_data);
8✔
194
        if (src_type.type_id() != types::TypeID::Pointer || helpers::is_number(src_data)) {
8✔
195
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
196
        }
197

198
        // Criterion: Destination must be a pointer to source type
199
        auto dst_data = dst_node->data();
8✔
200
        auto& dst_type = function.type(dst_data);
8✔
201
        if (dst_type.type_id() != types::TypeID::Pointer) {
8✔
UNCOV
202
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
203
        }
204

205
        // Criterion: Must be typed pointer
206
        auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
8✔
207
        if (!base_pointer_type) {
8✔
NEW
208
            throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
209
        }
210
        if (!base_pointer_type->has_pointee_type()) {
8✔
NEW
211
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
212
        }
213

214
        return;
215
    } else if (this->dst_conn_ == "deref") {
14✔
216
        if (this->src_conn_ != "void") {
6✔
217
            throw InvalidSDFGException("Memlet: Dereference memlets must have a void source");
×
218
        }
219
        auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
6✔
220
        if (!src_node) {
6✔
221
            throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
222
        }
223
        auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
6✔
224
        if (!dst_node) {
6✔
225
            throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
226
        }
227

228
        // Criterion: Dereference memlets must have '0' as the only dimension
229
        if (this->begin_subset_.size() != 1) {
6✔
230
            throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
231
        }
232
        if (!symbolic::eq(this->begin_subset_[0], symbolic::integer(0))) {
6✔
233
            throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
234
        }
235

236
        // Criterion: Source must be a pointer
237
        auto src_data = src_node->data();
6✔
238
        auto& src_type = function.type(src_data);
6✔
239
        if (src_type.type_id() != types::TypeID::Pointer || helpers::is_number(src_data)) {
6✔
NEW
240
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
241
        }
242

243
        // Criterion: Destination must be a pointer to source type
244
        auto dst_data = dst_node->data();
6✔
245
        auto& dst_type = function.type(dst_data);
6✔
246
        if (dst_type.type_id() != types::TypeID::Pointer) {
6✔
247
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
248
        }
249

250
        // Criterion: Must be typed pointer
251
        auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
6✔
252
        if (!base_pointer_type) {
6✔
NEW
253
            throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
254
        }
255
        if (!base_pointer_type->has_pointee_type()) {
6✔
NEW
256
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
257
        }
258

259
        return;
260
    }
6✔
261

262
    throw InvalidSDFGException("Memlet: Invalid memlet connection");
×
263
};
1,019✔
264

265
const graph::Edge Memlet::edge() const { return this->edge_; };
35✔
266

267
const DataFlowGraph& Memlet::get_parent() const { return *this->parent_; };
×
268

269
DataFlowGraph& Memlet::get_parent() { return *this->parent_; };
×
270

271
MemletType Memlet::type() const {
711✔
272
    if (this->dst_conn_ == "ref") {
711✔
273
        return Reference;
6✔
274
    } else if (this->dst_conn_ == "deref") {
705✔
275
        return Dereference_Src;
5✔
276
    } else if (this->src_conn_ == "deref") {
700✔
277
        return Dereference_Dst;
4✔
278
    } else {
279
        return Computational;
696✔
280
    }
281
}
711✔
282

283
const DataFlowNode& Memlet::src() const { return this->src_; };
276✔
284

285
DataFlowNode& Memlet::src() { return this->src_; };
33✔
286

287
const DataFlowNode& Memlet::dst() const { return this->dst_; };
230✔
288

289
DataFlowNode& Memlet::dst() { return this->dst_; };
30✔
290

291
const std::string& Memlet::src_conn() const { return this->src_conn_; };
282✔
292

293
const std::string& Memlet::dst_conn() const { return this->dst_conn_; };
326✔
294

295
const Subset Memlet::subset() const { return this->begin_subset_; };
765✔
296

297
void Memlet::set_subset(const Subset& subset) {
15✔
298
    this->begin_subset_ = subset;
15✔
299
    this->end_subset_ = subset;
15✔
300
};
15✔
301

302
const Subset Memlet::begin_subset() const { return this->begin_subset_; };
250✔
303

304
const Subset Memlet::end_subset() const { return this->end_subset_; };
255✔
305

306
void Memlet::set_subset(const Subset& begin_subset, const Subset& end_subset) {
×
307
    this->begin_subset_ = begin_subset;
×
308
    this->end_subset_ = end_subset;
×
309
};
×
310

311
bool Memlet::has_range() const {
4✔
312
    for (size_t i = 0; i < this->begin_subset_.size(); i++) {
8✔
313
        if (!symbolic::eq(this->begin_subset_[i], this->end_subset_[i])) {
4✔
314
            return true;
×
315
        }
316
    }
4✔
317
    return false;
4✔
318
};
4✔
319

320
const types::IType& Memlet::base_type() const { return *this->base_type_; };
288✔
321

322
void Memlet::set_base_type(const types::IType& base_type) { this->base_type_ = base_type.clone(); };
13✔
323

324
const types::IType& Memlet::result_type(const Function& function) const {
22✔
325
    return types::infer_type(function, *this->base_type_, this->begin_subset_);
22✔
326
};
327

UNCOV
328
std::unique_ptr<Memlet> Memlet::clone(
×
329
    size_t element_id, const graph::Edge& edge, DataFlowGraph& parent, DataFlowNode& src, DataFlowNode& dst
330
) const {
331
    return std::unique_ptr<Memlet>(new Memlet(
×
332
        element_id,
×
333
        this->debug_info_,
×
334
        edge,
×
335
        parent,
×
336
        src,
×
337
        this->src_conn_,
×
338
        dst,
×
339
        this->dst_conn_,
×
340
        this->begin_subset_,
×
NEW
341
        this->end_subset_,
×
NEW
342
        *this->base_type_
×
343
    ));
344
};
×
345

346
void Memlet::replace(const symbolic::Expression& old_expression, const symbolic::Expression& new_expression) {
8✔
347
    for (auto& dim : this->begin_subset_) {
14✔
348
        dim = symbolic::subs(dim, old_expression, new_expression);
6✔
349
    }
350
    for (auto& dim : this->end_subset_) {
14✔
351
        dim = symbolic::subs(dim, old_expression, new_expression);
6✔
352
    }
353
};
8✔
354

355
} // namespace data_flow
356
} // 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