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

daisytuner / sdfglib / 16861237397

10 Aug 2025 12:12PM UTC coverage: 64.492% (+0.006%) from 64.486%
16861237397

push

github

web-flow
Merge pull request #185 from daisytuner/memlets-tasklets

References and Memlets: Validation

102 of 146 new or added lines in 7 files covered. (69.86%)

2 existing lines in 1 file now uncovered.

8965 of 13901 relevant lines covered (64.49%)

124.44 hits per line

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

69.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(
519✔
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,038✔
25
      dst_conn_(dst_conn), begin_subset_(subset), end_subset_(subset), base_type_(base_type.clone()) {
519✔
26

27
      };
519✔
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,059✔
48
    switch (this->type()) {
1,059✔
49
        case MemletType::Computational: {
50
            // Criterion: Must connect a code node and an access node with void connector at access node
51
            const AccessNode* data_node = nullptr;
1,021✔
52
            const CodeNode* code_node = nullptr;
1,021✔
53
            if (this->src_conn_ == "void") {
1,021✔
54
                data_node = dynamic_cast<const AccessNode*>(&this->src_);
353✔
55
                code_node = dynamic_cast<const CodeNode*>(&this->dst_);
353✔
56
                if (!data_node || !code_node) {
353✔
NEW
57
                    throw InvalidSDFGException("Memlet: Computation memlets must connect a code node and an access node"
×
58
                    );
59
                }
60

61
                // Criterion: Non-void connector must be an input of the code node
62
                if (std::find(code_node->inputs().begin(), code_node->inputs().end(), this->dst_conn_) ==
706✔
63
                    code_node->inputs().end()) {
353✔
NEW
64
                    throw InvalidSDFGException("Memlet: Computation memlets must have an input in the code node");
×
65
                }
66
            } else if (this->dst_conn_ == "void") {
1,021✔
67
                data_node = dynamic_cast<const AccessNode*>(&this->dst_);
668✔
68
                code_node = dynamic_cast<const CodeNode*>(&this->src_);
668✔
69
                if (!data_node || !code_node) {
668✔
NEW
70
                    throw InvalidSDFGException("Memlet: Computation memlets must connect a code node and an access node"
×
71
                    );
72
                }
73

74
                // Criterion: Non-void connector must be an output of the code node
75
                if (std::find(code_node->outputs().begin(), code_node->outputs().end(), this->src_conn_) ==
1,336✔
76
                    code_node->outputs().end()) {
668✔
NEW
77
                    throw InvalidSDFGException("Memlet: Computation memlets must have an output in the code node");
×
78
                }
79
            } else {
668✔
NEW
80
                throw InvalidSDFGException(
×
NEW
81
                    "Memlet: Computation memlets must have void connector at source or destination"
×
82
                );
83
            }
84

85
            // Criterion: edge must be contiguous memory
86
            auto& inferred_type = types::infer_type(function, *this->base_type_, this->begin_subset_);
1,021✔
87

88
            // Return if library node
89
            if (dynamic_cast<const LibraryNode*>(code_node)) {
1,021✔
90
                return;
37✔
91
            }
92

93
            // Criterion: Inferred type must be a scalar
94
            if (inferred_type.type_id() != types::TypeID::Scalar) {
984✔
NEW
95
                throw InvalidSDFGException("Memlet: Computation memlets must have a scalar destination");
×
96
            }
97
            break;
984✔
98
        }
99
        case MemletType::Reference: {
100
            // Criterion: Destination must be an access node with a pointer type
101
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
20✔
102
            if (!dst_node) {
20✔
NEW
103
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node destination");
×
104
            }
105
            auto dst_data = dst_node->data();
20✔
106
            // Criterion: Destination must be non-constant
107
            if (helpers::is_number(dst_data) || symbolic::is_nullptr(symbolic::symbol(dst_data))) {
20✔
NEW
108
                throw InvalidSDFGException("Memlet: Reference memlets must have a non-constant destination");
×
109
            }
110

111
            // Criterion: Destination must be a pointer
112
            auto& dst_type = function.type(dst_data);
20✔
113
            if (dst_type.type_id() != types::TypeID::Pointer) {
20✔
NEW
114
                throw InvalidSDFGException("Memlet: Reference memlets must have a pointer destination");
×
115
            }
116

117
            // Criterion: Source must be an access node
118
            if (this->src_conn_ != "void") {
20✔
NEW
119
                throw InvalidSDFGException("Memlet: Reference memlets must have a void source");
×
120
            }
121
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
20✔
122
            if (!src_node) {
20✔
NEW
123
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node source");
×
124
            }
125

126
            // Case: Constant
127
            if (helpers::is_number(src_node->data()) || symbolic::is_nullptr(symbolic::symbol(src_node->data()))) {
20✔
128
                if (!this->begin_subset_.empty()) {
4✔
NEW
129
                    throw InvalidSDFGException("Memlet: Reference memlets for raw addresses must not have a subset");
×
130
                }
131
                return;
4✔
132
            }
133

134
            // Case: Container
135
            // Criterion: Must be contiguous memory reference
136
            // Throws exception if not contiguous
137
            types::infer_type(function, *this->base_type_, this->begin_subset_);
16✔
138
            break;
16✔
139
        }
20✔
140
        case MemletType::Dereference_Src: {
141
            if (this->src_conn_ != "void") {
10✔
NEW
142
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void destination");
×
143
            }
144

145
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
10✔
146
            if (!src_node) {
10✔
NEW
147
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
148
            }
149
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
10✔
150
            if (!dst_node) {
10✔
NEW
151
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
152
            }
153

154
            // Criterion: Dereference memlets must have '0' as the only dimension
155
            if (this->begin_subset_.size() != 1) {
10✔
NEW
156
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
157
            }
158
            if (!symbolic::eq(this->begin_subset_[0], symbolic::zero())) {
10✔
NEW
159
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
160
            }
161

162
            // Criterion: Source must be a pointer
163
            auto src_data = src_node->data();
10✔
164
            auto& src_type = function.type(src_data);
10✔
165
            if (src_type.type_id() != types::TypeID::Pointer || helpers::is_number(src_data) ||
20✔
166
                symbolic::is_nullptr(symbolic::symbol(src_data))) {
10✔
NEW
167
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
168
            }
169

170
            // Criterion: Destination must be a pointer to source type
171
            auto dst_data = dst_node->data();
10✔
172
            auto& dst_type = function.type(dst_data);
10✔
173
            if (dst_type.type_id() != types::TypeID::Pointer || helpers::is_number(dst_data) ||
20✔
174
                symbolic::is_nullptr(symbolic::symbol(dst_data))) {
10✔
NEW
175
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
176
            }
177

178
            // Criterion: Must be typed pointer
179
            auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
10✔
180
            if (!base_pointer_type) {
10✔
NEW
181
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
182
            }
183
            if (!base_pointer_type->has_pointee_type()) {
10✔
NEW
184
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
185
            }
186

187
            break;
188
        }
10✔
189
        case MemletType::Dereference_Dst: {
190
            if (this->dst_conn_ != "void") {
8✔
NEW
191
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void source");
×
192
            }
193

194
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
8✔
195
            if (!src_node) {
8✔
NEW
196
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
197
            }
198
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
8✔
199
            if (!dst_node) {
8✔
NEW
200
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
201
            }
202

203
            // Criterion: Dereference memlets must have '0' as the only dimension
204
            if (this->begin_subset_.size() != 1) {
8✔
NEW
205
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
206
            }
207
            if (!symbolic::eq(this->begin_subset_[0], symbolic::zero())) {
8✔
NEW
208
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
209
            }
210

211
            // Criterion: Source must be a pointer
212
            auto src_data = src_node->data();
8✔
213
            auto& src_type = function.type(src_data);
8✔
214
            if (src_type.type_id() != types::TypeID::Pointer || helpers::is_number(src_data)) {
8✔
NEW
215
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
216
            }
217

218
            // Criterion: Destination must be a pointer to source type
219
            auto dst_data = dst_node->data();
8✔
220
            auto& dst_type = function.type(dst_data);
8✔
221
            if (dst_type.type_id() != types::TypeID::Pointer || helpers::is_number(dst_data) ||
16✔
222
                symbolic::is_nullptr(symbolic::symbol(dst_data))) {
8✔
NEW
223
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
224
            }
225

226
            // Criterion: Must be typed pointer
227
            auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
8✔
228
            if (!base_pointer_type) {
8✔
NEW
229
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
230
            }
231
            if (!base_pointer_type->has_pointee_type()) {
8✔
NEW
232
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
233
            }
234

235
            break;
236
        }
8✔
237
        default:
NEW
238
            throw InvalidSDFGException("Memlet: Invalid memlet type");
×
239
    }
240
};
1,059✔
241

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

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

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

248
MemletType Memlet::type() const {
1,811✔
249
    if (this->dst_conn_ == "ref") {
1,811✔
250
        return Reference;
27✔
251
    } else if (this->dst_conn_ == "deref") {
1,784✔
252
        return Dereference_Src;
16✔
253
    } else if (this->src_conn_ == "deref") {
1,768✔
254
        return Dereference_Dst;
12✔
255
    } else {
256
        return Computational;
1,756✔
257
    }
258
}
1,811✔
259

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

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

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

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

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

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

272
const Subset Memlet::subset() const { return this->begin_subset_; };
798✔
273

274
void Memlet::set_subset(const Subset& subset) {
15✔
275
    this->begin_subset_ = subset;
15✔
276
    this->end_subset_ = subset;
15✔
277
};
15✔
278

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

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

283
void Memlet::set_subset(const Subset& begin_subset, const Subset& end_subset) {
×
284
    this->begin_subset_ = begin_subset;
×
285
    this->end_subset_ = end_subset;
×
286
};
×
287

288
bool Memlet::has_range() const {
4✔
289
    for (size_t i = 0; i < this->begin_subset_.size(); i++) {
8✔
290
        if (!symbolic::eq(this->begin_subset_[i], this->end_subset_[i])) {
4✔
291
            return true;
×
292
        }
293
    }
4✔
294
    return false;
4✔
295
};
4✔
296

297
const types::IType& Memlet::base_type() const { return *this->base_type_; };
290✔
298

299
void Memlet::set_base_type(const types::IType& base_type) { this->base_type_ = base_type.clone(); };
11✔
300

301
const types::IType& Memlet::result_type(const Function& function) const {
22✔
302
    return types::infer_type(function, *this->base_type_, this->begin_subset_);
22✔
303
};
304

305
std::unique_ptr<Memlet> Memlet::clone(
×
306
    size_t element_id, const graph::Edge& edge, DataFlowGraph& parent, DataFlowNode& src, DataFlowNode& dst
307
) const {
308
    return std::unique_ptr<Memlet>(new Memlet(
×
309
        element_id,
×
310
        this->debug_info_,
×
311
        edge,
×
312
        parent,
×
313
        src,
×
314
        this->src_conn_,
×
315
        dst,
×
316
        this->dst_conn_,
×
317
        this->begin_subset_,
×
318
        this->end_subset_,
×
319
        *this->base_type_
×
320
    ));
321
};
×
322

323
void Memlet::replace(const symbolic::Expression& old_expression, const symbolic::Expression& new_expression) {
8✔
324
    for (auto& dim : this->begin_subset_) {
14✔
325
        dim = symbolic::subs(dim, old_expression, new_expression);
6✔
326
    }
327
    for (auto& dim : this->end_subset_) {
14✔
328
        dim = symbolic::subs(dim, old_expression, new_expression);
6✔
329
    }
330
};
8✔
331

332
} // namespace data_flow
333
} // 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