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

daisytuner / sdfglib / 18651924023

20 Oct 2025 12:26PM UTC coverage: 60.977% (-0.6%) from 61.539%
18651924023

push

github

web-flow
Merge pull request #286 from daisytuner/reserved-names

removes restricted globals filtering in codegen

8 of 20 new or added lines in 2 files covered. (40.0%)

342 existing lines in 17 files now uncovered.

9174 of 15045 relevant lines covered (60.98%)

92.1 hits per line

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

66.67
/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(
595✔
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,190✔
25
      dst_conn_(dst_conn), subset_(subset), base_type_(base_type.clone()) {
595✔
26

27
      };
595✔
28

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

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

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

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

76
            // Return if library node
77
            if (dynamic_cast<const LibraryNode*>(code_node)) {
1,048✔
78
                return;
35✔
79
            }
80

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

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

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

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

117
            if (src_node->data() == dst_node->data()) {
35✔
UNCOV
118
                throw InvalidSDFGException("Memlet: Reference memlet source and destination cannot be the same");
×
119
            }
120

121
            // Case: Constant
122
            if (helpers::is_number(src_node->data()) || symbolic::is_nullptr(symbolic::symbol(src_node->data()))) {
35✔
123
                if (!this->subset_.empty()) {
4✔
UNCOV
124
                    throw InvalidSDFGException("Memlet: Reference memlets for raw addresses must not have a subset");
×
125
                }
126
                return;
4✔
127
            }
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_);
31✔
133
            break;
31✔
134
        }
35✔
135
        case MemletType::Dereference_Src: {
136
            if (this->src_conn_ != "void") {
13✔
UNCOV
137
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void destination");
×
138
            }
139

140
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
13✔
141
            if (!src_node) {
13✔
142
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
143
            }
144
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
13✔
145
            if (!dst_node) {
13✔
UNCOV
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) {
13✔
UNCOV
151
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
152
            }
153
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
13✔
UNCOV
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)) {
13✔
159
                if (const_node->type().type_id() != types::TypeID::Pointer &&
×
UNCOV
160
                    const_node->type().type_id() != types::TypeID::Scalar) {
×
UNCOV
161
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
162
                }
163
            } else {
×
164
                auto src_data = src_node->data();
13✔
165
                auto& src_type = function.type(src_data);
13✔
166
                if (src_type.type_id() != types::TypeID::Pointer) {
13✔
UNCOV
167
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
168
                }
169
            }
13✔
170

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

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

187
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
10✔
188
            if (!src_node) {
10✔
189
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
190
            }
191
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
10✔
192
            if (!dst_node) {
10✔
UNCOV
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) {
10✔
UNCOV
198
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
199
            }
200
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
10✔
UNCOV
201
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
202
            }
203

204
            // Criterion: Destination must be a pointer
205
            if (auto const_node = dynamic_cast<const ConstantNode*>(dst_node)) {
10✔
UNCOV
206
                throw InvalidSDFGException("Memlet: Dereference memlets must have a non-constant destination");
×
207
            }
208
            auto dst_data = dst_node->data();
10✔
209
            auto& dst_type = function.type(dst_data);
10✔
210
            if (dst_type.type_id() != types::TypeID::Pointer) {
10✔
UNCOV
211
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
212
            }
213

214
            // Criterion: Must be typed pointer
215
            auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
10✔
216
            if (!base_pointer_type) {
10✔
UNCOV
217
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
218
            }
219
            if (!base_pointer_type->has_pointee_type()) {
10✔
UNCOV
220
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
221
            }
222

223
            break;
224
        }
10✔
225
        default:
UNCOV
226
            throw InvalidSDFGException("Memlet: Invalid memlet type");
×
227
    }
228
};
1,106✔
229

230
const graph::Edge Memlet::edge() const { return this->edge_; };
33✔
231

UNCOV
232
const DataFlowGraph& Memlet::get_parent() const { return *this->parent_; };
×
233

UNCOV
234
DataFlowGraph& Memlet::get_parent() { return *this->parent_; };
×
235

236
MemletType Memlet::type() const {
1,980✔
237
    if (this->dst_conn_ == "ref") {
1,980✔
238
        return Reference;
70✔
239
    } else if (this->dst_conn_ == "deref") {
1,910✔
240
        return Dereference_Src;
37✔
241
    } else if (this->src_conn_ == "deref") {
1,873✔
242
        return Dereference_Dst;
37✔
243
    } else {
244
        return Computational;
1,836✔
245
    }
246
}
1,980✔
247

248
const DataFlowNode& Memlet::src() const { return this->src_; };
455✔
249

250
DataFlowNode& Memlet::src() { return this->src_; };
66✔
251

252
const DataFlowNode& Memlet::dst() const { return this->dst_; };
111✔
253

254
DataFlowNode& Memlet::dst() { return this->dst_; };
40✔
255

256
const std::string& Memlet::src_conn() const { return this->src_conn_; };
139✔
257

258
const std::string& Memlet::dst_conn() const { return this->dst_conn_; };
184✔
259

260
const Subset Memlet::subset() const { return this->subset_; };
978✔
261

262
void Memlet::set_subset(const Subset& subset) { this->subset_ = subset; };
13✔
263

264
const types::IType& Memlet::base_type() const { return *this->base_type_; };
527✔
265

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

268
const types::IType& Memlet::result_type(const Function& function) const {
10✔
269
    return types::infer_type(function, *this->base_type_, this->subset_);
10✔
270
};
271

272
std::unique_ptr<Memlet> Memlet::clone(
×
273
    size_t element_id, const graph::Edge& edge, DataFlowGraph& parent, DataFlowNode& src, DataFlowNode& dst
274
) const {
275
    return std::unique_ptr<Memlet>(new Memlet(
×
276
        element_id,
×
277
        this->debug_info_,
×
278
        edge,
×
279
        parent,
×
280
        src,
×
281
        this->src_conn_,
×
UNCOV
282
        dst,
×
283
        this->dst_conn_,
×
UNCOV
284
        this->subset_,
×
UNCOV
285
        *this->base_type_
×
286
    ));
UNCOV
287
};
×
288

289
void Memlet::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
8✔
290
    Subset new_subset;
8✔
291
    for (auto& dim : this->subset_) {
14✔
292
        new_subset.push_back(symbolic::subs(dim, old_expression, new_expression));
6✔
293
    }
294
    this->subset_ = new_subset;
8✔
295
};
8✔
296

297
} // namespace data_flow
298
} // 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