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

daisytuner / sdfglib / 16440807098

22 Jul 2025 09:49AM UTC coverage: 66.011% (+0.9%) from 65.094%
16440807098

Pull #153

github

web-flow
Merge 194f87ac9 into abe57c083
Pull Request #153: Introduces different memlet types for computation, references and dereferencing

244 of 352 new or added lines in 30 files covered. (69.32%)

70 existing lines in 7 files now uncovered.

8322 of 12607 relevant lines covered (66.01%)

133.98 hits per line

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

67.71
/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(
490✔
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
)
23
    : Element(element_id, debug_info), edge_(edge), parent_(&parent), src_(src), dst_(dst), src_conn_(src_conn),
980✔
24
      dst_conn_(dst_conn), begin_subset_(subset), end_subset_(subset) {
490✔
25

26
      };
490✔
27

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

43
      };
24✔
44

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

58
        // Criterion: Destination must be a scalar accessed through contiguous memory
59
        auto dst_data = static_cast<const AccessNode&>(this->dst_).data();
624✔
60
        auto& dst_type = function.type(dst_data);
624✔
61
        auto& deref_type = types::infer_type(function, dst_type, this->begin_subset_);
624✔
62
        if (deref_type.type_id() != types::TypeID::Scalar) {
624✔
NEW
63
            throw InvalidSDFGException("Memlet: Computation memlets must have a scalar destination");
×
64
        }
65

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

85
        // Criterion: Source must be a scalar accessed through contiguous memory
86
        auto src_data = static_cast<const AccessNode&>(this->src_).data();
293✔
87
        auto& src_type = function.type(src_data);
293✔
88
        auto& deref_type = types::infer_type(function, src_type, this->begin_subset_);
293✔
89
        if (deref_type.type_id() != types::TypeID::Scalar) {
293✔
NEW
90
            throw InvalidSDFGException("Memlet: Computation memlets must have a scalar source");
×
91
        }
92
        return;
93
    }
293✔
94

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

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

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

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

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

157
        // Criterion: Reference memlets must refer to contiguous memory
158
        auto src_data = src_node->data();
14✔
159
        auto& src_type = function.type(src_data);
14✔
160
        // Throws exception if not contiguous
161
        auto& ref_type = types::infer_type(function, src_type, this->begin_subset_);
14✔
162

163
        // Criterion: Destination must be a pointer
164
        auto dst_data = dst_node->data();
14✔
165
        auto& dst_type = function.type(dst_data);
14✔
166
        if (dst_type.type_id() != types::TypeID::Pointer) {
14✔
NEW
167
            throw InvalidSDFGException("Memlet: Reference memlets must have a pointer destination");
×
168
        }
169

170
        return;
171
    }
14✔
172

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

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

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

202
        // Criterion: Destination must be a pointer to source type
203
        auto dst_data = dst_node->data();
8✔
204
        auto dst_type = dynamic_cast<const types::Pointer*>(&function.type(dst_data));
8✔
205
        if (!dst_type) {
8✔
NEW
206
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
207
        }
208
        if (dst_type->pointee_type() == src_type || symbolic::is_nullptr(symbolic::symbol(src_data))) {
8✔
209
            // Do nothing
210
        } else {
8✔
NEW
211
            throw InvalidSDFGException("Memlet: Dereference memlets must be pointer to source type");
×
212
        }
213

214
        return;
215
    } else if (this->dst_conn_ == "deref") {
14✔
216
        if (this->src_conn_ != "void") {
6✔
NEW
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✔
NEW
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✔
NEW
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✔
NEW
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✔
NEW
233
            throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
234
        }
235

236
        // Criterion: Destination must be a pointer
237
        auto dst_data = dst_node->data();
6✔
238
        auto& dst_type = function.type(dst_data);
6✔
239
        if (dst_type.type_id() != types::TypeID::Pointer) {
6✔
NEW
240
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
241
        }
242

243
        // Criterion: Source must be a pointer to destination type
244
        auto src_data = src_node->data();
6✔
245
        auto src_type = dynamic_cast<const types::Pointer*>(&function.type(src_data));
6✔
246
        if (!src_type) {
6✔
NEW
247
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
248
        }
249
        if (src_type->pointee_type() == dst_type) {
6✔
250
            // Do nothing
251
        } else {
6✔
NEW
252
            throw InvalidSDFGException("Memlet: Dereference memlets be pointer to destination type");
×
253
        }
254

255
        return;
256
    }
6✔
257

NEW
258
    throw InvalidSDFGException("Memlet: Invalid memlet connection");
×
259
};
965✔
260

261
const graph::Edge Memlet::edge() const { return this->edge_; };
18✔
262

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

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

267
MemletType Memlet::type() const {
704✔
268
    if (this->dst_conn_ == "ref") {
704✔
269
        return Reference;
3✔
270
    } else if (this->dst_conn_ == "deref") {
701✔
271
        return Dereference_Src;
5✔
272
    } else if (this->src_conn_ == "deref") {
696✔
273
        return Dereference_Dst;
4✔
274
    } else {
275
        return Computational;
692✔
276
    }
277
}
704✔
278

279
const DataFlowNode& Memlet::src() const { return this->src_; };
250✔
280

281
DataFlowNode& Memlet::src() { return this->src_; };
28✔
282

283
const DataFlowNode& Memlet::dst() const { return this->dst_; };
219✔
284

285
DataFlowNode& Memlet::dst() { return this->dst_; };
27✔
286

287
const std::string& Memlet::src_conn() const { return this->src_conn_; };
261✔
288

289
const std::string& Memlet::dst_conn() const { return this->dst_conn_; };
298✔
290

291
const Subset Memlet::subset() const { return this->begin_subset_; };
949✔
292

293
void Memlet::set_subset(const Subset& subset) {
13✔
294
    this->begin_subset_ = subset;
13✔
295
    this->end_subset_ = subset;
13✔
296
};
13✔
297

298
const Subset Memlet::begin_subset() const { return this->begin_subset_; };
26✔
299

300
const Subset Memlet::end_subset() const { return this->end_subset_; };
26✔
301

302
void Memlet::set_subset(const Subset& begin_subset, const Subset& end_subset) {
×
303
    this->begin_subset_ = begin_subset;
×
304
    this->end_subset_ = end_subset;
×
305
};
×
306

307
bool Memlet::has_range() const {
×
308
    for (size_t i = 0; i < this->begin_subset_.size(); i++) {
×
309
        if (!symbolic::eq(this->begin_subset_[i], this->end_subset_[i])) {
×
310
            return true;
×
311
        }
312
    }
×
313
    return true;
×
314
};
×
315

316
std::unique_ptr<Memlet> Memlet::clone(
×
317
    size_t element_id, const graph::Edge& edge, DataFlowGraph& parent, DataFlowNode& src, DataFlowNode& dst
318
) const {
319
    return std::unique_ptr<Memlet>(new Memlet(
×
320
        element_id,
×
321
        this->debug_info_,
×
322
        edge,
×
323
        parent,
×
324
        src,
×
325
        this->src_conn_,
×
326
        dst,
×
327
        this->dst_conn_,
×
328
        this->begin_subset_,
×
329
        this->end_subset_
×
330
    ));
331
};
×
332

333
void Memlet::replace(const symbolic::Expression& old_expression, const symbolic::Expression& new_expression) {
8✔
334
    for (auto& dim : this->begin_subset_) {
14✔
335
        dim = symbolic::subs(dim, old_expression, new_expression);
6✔
336
    }
337
    for (auto& dim : this->end_subset_) {
14✔
338
        dim = symbolic::subs(dim, old_expression, new_expression);
6✔
339
    }
340
};
8✔
341

342
} // namespace data_flow
343
} // 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