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

daisytuner / sdfglib / 20764569418

06 Jan 2026 10:50PM UTC coverage: 62.168% (+21.4%) from 40.764%
20764569418

push

github

web-flow
Merge pull request #433 from daisytuner/clang-coverage

updates clang coverage flags

14988 of 24109 relevant lines covered (62.17%)

88.57 hits per line

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

58.8
/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/type.h"
8
#include "sdfg/types/utils.h"
9

10
namespace sdfg {
11
namespace data_flow {
12

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

28
      };
1,965✔
29

30
void Memlet::validate(const Function& function) const {
2,565✔
31
    // Validate subset
32
    for (const auto& dim : this->subset_) {
2,565✔
33
        // Null ptr check
34
        if (dim.is_null()) {
1,503✔
35
            throw InvalidSDFGException("Memlet: Subset dimensions cannot be null");
×
36
        }
×
37
    }
1,503✔
38

39
    // Validate connections
40
    switch (this->type()) {
2,565✔
41
        case MemletType::Computational: {
2,417✔
42
            // Criterion: Must connect a code node and an access node with void connector at access node
43
            const AccessNode* data_node = nullptr;
2,417✔
44
            const CodeNode* code_node = nullptr;
2,417✔
45
            if (this->src_conn_ == "void") {
2,417✔
46
                data_node = dynamic_cast<const AccessNode*>(&this->src_);
1,404✔
47
                code_node = dynamic_cast<const CodeNode*>(&this->dst_);
1,404✔
48
                if (!data_node || !code_node) {
1,404✔
49
                    throw InvalidSDFGException("Memlet: Computation memlets must connect a code node and an access node"
×
50
                    );
×
51
                }
×
52

53
                // Criterion: Non-void connector must be an input of the code node
54
                if (std::find(code_node->inputs().begin(), code_node->inputs().end(), this->dst_conn_) ==
1,404✔
55
                    code_node->inputs().end()) {
1,404✔
56
                    throw InvalidSDFGException("Memlet: Computation memlets must have an input in the code node");
×
57
                }
×
58
            } else if (this->dst_conn_ == "void") {
1,404✔
59
                data_node = dynamic_cast<const AccessNode*>(&this->dst_);
1,013✔
60
                code_node = dynamic_cast<const CodeNode*>(&this->src_);
1,013✔
61
                if (!data_node || !code_node) {
1,013✔
62
                    throw InvalidSDFGException("Memlet: Computation memlets must connect a code node and an access node"
×
63
                    );
×
64
                }
×
65

66
                // Criterion: Non-void connector must be an output of the code node
67
                if (std::find(code_node->outputs().begin(), code_node->outputs().end(), this->src_conn_) ==
1,013✔
68
                    code_node->outputs().end()) {
1,013✔
69
                    throw InvalidSDFGException("Memlet: Computation memlets must have an output in the code node");
×
70
                }
×
71
            } else {
1,013✔
72
                throw InvalidSDFGException(
×
73
                    "Memlet: Computation memlets must have void connector at source or destination"
×
74
                );
×
75
            }
×
76

77
            // Return if library node
78
            if (dynamic_cast<const LibraryNode*>(code_node)) {
2,417✔
79
                return;
702✔
80
            }
702✔
81

82
            // Criterion: edge must be contiguous memory
83
            auto& inferred_type = types::infer_type(function, *this->base_type_, this->subset_);
1,715✔
84

85
            // Criterion: Inferred type must be a scalar
86
            if (inferred_type.type_id() != types::TypeID::Scalar) {
1,715✔
87
                throw InvalidSDFGException(
×
88
                    "Memlet: Computation memlets resolve to scalar type. Base type: " + this->base_type_->print() +
×
89
                    " Subset Dim: " + std::to_string(this->subset_.size())
×
90
                );
×
91
            }
×
92
            break;
1,715✔
93
        }
1,715✔
94
        case MemletType::Reference: {
1,715✔
95
            // Criterion: Destination must be an access node with a pointer type
96
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
110✔
97
            if (!dst_node) {
110✔
98
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node destination");
×
99
            }
×
100
            auto dst_data = dst_node->data();
110✔
101
            // Criterion: Destination must be non-constant
102
            if (helpers::is_number(dst_data) || symbolic::is_nullptr(symbolic::symbol(dst_data))) {
110✔
103
                throw InvalidSDFGException("Memlet: Reference memlets must have a non-constant destination");
×
104
            }
×
105

106
            // Criterion: Destination must be a pointer
107
            auto& dst_type = function.type(dst_data);
110✔
108
            if (dst_type.type_id() != types::TypeID::Pointer) {
110✔
109
                throw InvalidSDFGException("Memlet: Reference memlets must have a pointer destination");
×
110
            }
×
111

112
            // Criterion: Source must be an access node
113
            if (this->src_conn_ != "void") {
110✔
114
                throw InvalidSDFGException("Memlet: Reference memlets must have a void source");
×
115
            }
×
116
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
110✔
117
            if (!src_node) {
110✔
118
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node source");
×
119
            }
×
120

121
            // Case: Constant
122
            if (helpers::is_number(src_node->data()) || symbolic::is_nullptr(symbolic::symbol(src_node->data()))) {
110✔
123
                if (!this->subset_.empty()) {
4✔
124
                    throw InvalidSDFGException("Memlet: Reference memlets for raw addresses must not have a subset");
×
125
                }
×
126
                return;
4✔
127
            }
4✔
128

129
            // Case: Container
130
            // Criterion: Must be contiguous memory reference
131
            // Throws exception if not contiguous
132
            types::infer_type(function, *this->base_type_, this->subset_);
106✔
133
            break;
106✔
134
        }
110✔
135
        case MemletType::Dereference_Src: {
26✔
136
            if (this->src_conn_ != "void") {
26✔
137
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void destination");
×
138
            }
×
139

140
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
26✔
141
            if (!src_node) {
26✔
142
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
143
            }
×
144
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
26✔
145
            if (!dst_node) {
26✔
146
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
147
            }
×
148

149
            // Criterion: Dereference memlets must have '0' as the only dimension
150
            if (this->subset_.size() != 1) {
26✔
151
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
152
            }
×
153
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
26✔
154
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
155
            }
×
156

157
            // Criterion: Source must be a pointer
158
            if (auto const_node = dynamic_cast<const ConstantNode*>(src_node)) {
26✔
159
                if (const_node->type().type_id() != types::TypeID::Pointer &&
×
160
                    const_node->type().type_id() != types::TypeID::Scalar) {
×
161
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
162
                }
×
163
            } else {
26✔
164
                auto src_data = src_node->data();
26✔
165
                auto& src_type = function.type(src_data);
26✔
166
                if (src_type.type_id() != types::TypeID::Pointer) {
26✔
167
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
168
                }
×
169
            }
26✔
170

171
            // Criterion: Must be typed pointer
172
            auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
26✔
173
            if (!base_pointer_type) {
26✔
174
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
175
            }
×
176
            if (!base_pointer_type->has_pointee_type()) {
26✔
177
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
178
            }
×
179

180
            break;
26✔
181
        }
26✔
182
        case MemletType::Dereference_Dst: {
26✔
183
            if (this->dst_conn_ != "void") {
12✔
184
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void source");
×
185
            }
×
186

187
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
12✔
188
            if (!src_node) {
12✔
189
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
190
            }
×
191
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
12✔
192
            if (!dst_node) {
12✔
193
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
194
            }
×
195

196
            // Criterion: Dereference memlets must have '0' as the only dimension
197
            if (this->subset_.size() != 1) {
12✔
198
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
199
            }
×
200
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
12✔
201
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
202
            }
×
203

204
            // Criterion: src type cannot be a function
205
            const sdfg::types::IType* src_type;
12✔
206
            if (auto const_node = dynamic_cast<const data_flow::ConstantNode*>(src_node)) {
12✔
207
                src_type = &const_node->type();
2✔
208
            } else {
10✔
209
                src_type = &function.type(src_node->data());
10✔
210
            }
10✔
211
            if (src_type->type_id() == types::TypeID::Function) {
12✔
212
                throw InvalidSDFGException("Memlet: Dereference memlets cannot have source of type Function");
×
213
            }
×
214

215
            // Criterion: Destination must be a pointer
216
            if (auto const_node = dynamic_cast<const ConstantNode*>(dst_node)) {
12✔
217
                throw InvalidSDFGException("Memlet: Dereference memlets must have a non-constant destination");
×
218
            }
×
219
            auto dst_data = dst_node->data();
12✔
220
            auto& dst_type = function.type(dst_data);
12✔
221
            if (dst_type.type_id() != types::TypeID::Pointer) {
12✔
222
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
223
            }
×
224

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

234
            break;
12✔
235
        }
12✔
236
        default:
12✔
237
            throw InvalidSDFGException("Memlet: Invalid memlet type");
×
238
    }
2,565✔
239
};
2,565✔
240

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

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

245
DataFlowGraph& Memlet::get_parent() { return *this->parent_; };
1✔
246

247
MemletType Memlet::type() const {
4,018✔
248
    if (this->dst_conn_ == "ref") {
4,018✔
249
        return Reference;
217✔
250
    } else if (this->dst_conn_ == "deref") {
3,801✔
251
        return Dereference_Src;
82✔
252
    } else if (this->src_conn_ == "deref") {
3,719✔
253
        return Dereference_Dst;
46✔
254
    } else {
3,673✔
255
        return Computational;
3,673✔
256
    }
3,673✔
257
}
4,018✔
258

259
const DataFlowNode& Memlet::src() const { return this->src_; };
1,006✔
260

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

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

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

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

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

271
const Subset& Memlet::subset() const { return this->subset_; };
2,259✔
272

273
void Memlet::set_subset(const Subset& subset) { this->subset_ = subset; };
32✔
274

275
const types::IType& Memlet::base_type() const { return *this->base_type_; };
1,556✔
276

277
void Memlet::set_base_type(const types::IType& base_type) { this->base_type_ = base_type.clone(); };
21✔
278

279
const types::IType& Memlet::result_type(const Function& function) const {
588✔
280
    return types::infer_type(function, *this->base_type_, this->subset_);
588✔
281
};
588✔
282

283
std::unique_ptr<Memlet> Memlet::clone(
284
    size_t element_id, const graph::Edge& edge, DataFlowGraph& parent, DataFlowNode& src, DataFlowNode& dst
285
) const {
×
286
    return std::unique_ptr<Memlet>(new Memlet(
×
287
        element_id,
×
288
        this->debug_info_,
×
289
        edge,
×
290
        parent,
×
291
        src,
×
292
        this->src_conn_,
×
293
        dst,
×
294
        this->dst_conn_,
×
295
        this->subset_,
×
296
        *this->base_type_
×
297
    ));
×
298
};
×
299

300
void Memlet::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
9✔
301
    Subset new_subset;
9✔
302
    for (auto& dim : this->subset_) {
9✔
303
        new_subset.push_back(symbolic::subs(dim, old_expression, new_expression));
6✔
304
    }
6✔
305
    this->subset_ = new_subset;
9✔
306
};
9✔
307

308
} // namespace data_flow
309
} // 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