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

daisytuner / sdfglib / 16439520920

22 Jul 2025 08:53AM UTC coverage: 65.927% (+0.8%) from 65.094%
16439520920

Pull #153

github

web-flow
Merge a0eea6968 into abe57c083
Pull Request #153: Restricts memlets to contiguous memory

211 of 300 new or added lines in 29 files covered. (70.33%)

66 existing lines in 7 files now uncovered.

8314 of 12611 relevant lines covered (65.93%)

128.5 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(
502✔
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),
1,004✔
24
      dst_conn_(dst_conn), begin_subset_(subset), end_subset_(subset) {
502✔
25

26
      };
502✔
27

28
Memlet::Memlet(
12✔
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),
24✔
41
      dst_conn_(dst_conn), begin_subset_(begin_subset), end_subset_(end_subset) {
12✔
42

43
      };
12✔
44

45
void Memlet::validate(const Function& function) const {
451✔
46
    // Case 1: Computational Memlet (Tasklet)
47
    if (auto tasklet = dynamic_cast<const Tasklet*>(&this->src_)) {
451✔
48
        if (!dynamic_cast<const AccessNode*>(&this->dst_)) {
292✔
NEW
49
            throw InvalidSDFGException("Memlet: Computational memlet must have an access node destination");
×
50
        }
51
        if (this->dst_conn_ != "void") {
292✔
NEW
52
            throw InvalidSDFGException("Memlet: Computation memlets must have a void destination");
×
53
        }
54
        if (tasklet->output().first != this->src_conn_) {
292✔
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();
292✔
60
        auto& dst_type = function.type(dst_data);
292✔
61
        auto& deref_type = types::infer_type(function, dst_type, this->begin_subset_);
292✔
62
        if (deref_type.type_id() != types::TypeID::Scalar) {
292✔
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_)) {
451✔
68
        if (!dynamic_cast<const AccessNode*>(&this->src_)) {
130✔
NEW
69
            throw InvalidSDFGException("Memlet: Computation memlet must have an access node source");
×
70
        }
71
        if (this->src_conn_ != "void") {
130✔
NEW
72
            throw InvalidSDFGException("Memlet: Computation memlets must have a void source");
×
73
        }
74
        bool found_conn = false;
130✔
75
        for (auto& conn : tasklet->inputs()) {
170✔
76
            if (conn.first == this->dst_conn_) {
170✔
77
                found_conn = true;
130✔
78
                break;
130✔
79
            }
80
        }
81
        if (!found_conn) {
130✔
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();
130✔
87
        auto& src_type = function.type(src_data);
130✔
88
        auto& deref_type = types::infer_type(function, src_type, this->begin_subset_);
130✔
89
        if (deref_type.type_id() != types::TypeID::Scalar) {
130✔
NEW
90
            throw InvalidSDFGException("Memlet: Computation memlets must have a scalar source");
×
91
        }
92
        return;
93
    }
130✔
94

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

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

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

136
    // Case 3: Reference Memlet (Address Calculation)
137
    if (this->dst_conn_ == "ref") {
17✔
138
        if (this->src_conn_ != "void") {
8✔
NEW
139
            throw InvalidSDFGException("Memlet: Reference memlets must have a void source");
×
140
        }
141
        auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
8✔
142
        if (!src_node) {
8✔
NEW
143
            throw InvalidSDFGException("Memlet: Reference memlets must have an access node source");
×
144
        }
145
        auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
8✔
146
        if (!dst_node) {
8✔
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()))) {
8✔
152
            if (!this->begin_subset_.empty()) {
2✔
NEW
153
                throw InvalidSDFGException("Memlet: Reference memlets for raw addresses must not have a subset");
×
154
            }
155
        }
2✔
156

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

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

170
        return;
171
    }
8✔
172

173
    // Case 4: Dereference Memlet (Load/Store from/to pointer)
174
    if (this->src_conn_ == "deref") {
9✔
175
        if (this->dst_conn_ != "void") {
5✔
NEW
176
            throw InvalidSDFGException("Memlet: Dereference memlets must have a void destination");
×
177
        }
178
        auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
5✔
179
        if (!src_node) {
5✔
NEW
180
            throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
181
        }
182
        auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
5✔
183
        if (!dst_node) {
5✔
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) {
5✔
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))) {
5✔
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();
5✔
197
        auto& src_type = function.type(src_data);
5✔
198
        if (src_type.type_id() != types::TypeID::Pointer || helpers::is_number(src_data)) {
5✔
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();
5✔
204
        auto dst_type = dynamic_cast<const types::Pointer*>(&function.type(dst_data));
5✔
205
        if (!dst_type) {
5✔
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))) {
5✔
209
            // Do nothing
210
        } else {
5✔
NEW
211
            throw InvalidSDFGException("Memlet: Dereference memlets must be pointer to source type");
×
212
        }
213

214
        return;
215
    } else if (this->dst_conn_ == "deref") {
9✔
216
        if (this->src_conn_ != "void") {
4✔
NEW
217
            throw InvalidSDFGException("Memlet: Dereference memlets must have a void source");
×
218
        }
219
        auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
4✔
220
        if (!src_node) {
4✔
NEW
221
            throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
222
        }
223
        auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
4✔
224
        if (!dst_node) {
4✔
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) {
4✔
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))) {
4✔
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();
4✔
238
        auto& dst_type = function.type(dst_data);
4✔
239
        if (dst_type.type_id() != types::TypeID::Pointer) {
4✔
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();
4✔
245
        auto src_type = dynamic_cast<const types::Pointer*>(&function.type(src_data));
4✔
246
        if (!src_type) {
4✔
NEW
247
            throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
248
        }
249
        if (src_type->pointee_type() == dst_type) {
4✔
250
            // Do nothing
251
        } else {
4✔
NEW
252
            throw InvalidSDFGException("Memlet: Dereference memlets be pointer to destination type");
×
253
        }
254

255
        return;
256
    }
4✔
257

NEW
258
    throw InvalidSDFGException("Memlet: Invalid memlet connection");
×
259
};
451✔
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 {
702✔
268
    if (this->dst_conn_ == "ref") {
702✔
269
        return Reference;
3✔
270
    } else if (this->dst_conn_ == "deref") {
699✔
271
        return Dereference_Src;
5✔
272
    } else if (this->src_conn_ == "deref") {
694✔
273
        return Dereference_Dst;
4✔
274
    } else {
275
        return Computational;
690✔
276
    }
277
}
702✔
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_; };
263✔
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