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

daisytuner / sdfglib / 17698271146

13 Sep 2025 03:06PM UTC coverage: 60.505% (+1.2%) from 59.335%
17698271146

push

github

web-flow
Merge pull request #219 from daisytuner/stdlib-nodes

stdlib Library Nodes and ConstantNodes

640 of 1885 new or added lines in 107 files covered. (33.95%)

107 existing lines in 40 files now uncovered.

9443 of 15607 relevant lines covered (60.5%)

106.96 hits per line

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

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

27
      };
658✔
28

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

38
    // Validate connections
39
    switch (this->type()) {
1,104✔
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,058✔
43
            const CodeNode* code_node = nullptr;
1,058✔
44
            if (this->src_conn_ == "void") {
1,058✔
45
                data_node = dynamic_cast<const AccessNode*>(&this->src_);
514✔
46
                code_node = dynamic_cast<const CodeNode*>(&this->dst_);
514✔
47
                if (!data_node || !code_node) {
514✔
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,028✔
54
                    code_node->inputs().end()) {
514✔
55
                    throw InvalidSDFGException("Memlet: Computation memlets must have an input in the code node");
×
56
                }
57
            } else if (this->dst_conn_ == "void") {
1,058✔
58
                data_node = dynamic_cast<const AccessNode*>(&this->dst_);
544✔
59
                code_node = dynamic_cast<const CodeNode*>(&this->src_);
544✔
60
                if (!data_node || !code_node) {
544✔
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_) ==
1,088✔
67
                    code_node->outputs().end()) {
544✔
68
                    throw InvalidSDFGException("Memlet: Computation memlets must have an output in the code node");
×
69
                }
70
            } else {
544✔
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,058✔
78
                return;
45✔
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_);
21✔
93
            if (!dst_node) {
21✔
94
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node destination");
×
95
            }
96
            auto dst_data = dst_node->data();
21✔
97
            // Criterion: Destination must be non-constant
98
            if (helpers::is_number(dst_data) || symbolic::is_nullptr(symbolic::symbol(dst_data))) {
21✔
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);
21✔
104
            if (dst_type.type_id() != types::TypeID::Pointer) {
21✔
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") {
21✔
110
                throw InvalidSDFGException("Memlet: Reference memlets must have a void source");
×
111
            }
112
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
21✔
113
            if (!src_node) {
21✔
114
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node source");
×
115
            }
116

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

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

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

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

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

167
            // Criterion: Destination must be a pointer to source type
168
            auto dst_data = dst_node->data();
15✔
169
            auto& dst_type = function.type(dst_data);
15✔
170
            if (dst_type.type_id() != types::TypeID::Pointer) {
15✔
UNCOV
171
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
172
            }
173

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

183
            break;
184
        }
15✔
185
        case MemletType::Dereference_Dst: {
186
            if (this->dst_conn_ != "void") {
10✔
187
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void source");
×
188
            }
189

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

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

207
            // Criterion: Source must be a pointer
208
            if (auto const_node = dynamic_cast<const ConstantNode*>(src_node)) {
10✔
209
                if (const_node->type().type_id() != types::TypeID::Pointer &&
2✔
NEW
210
                    const_node->type().type_id() != types::TypeID::Scalar) {
×
NEW
211
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
212
                }
213
            } else {
2✔
214
                auto src_data = src_node->data();
8✔
215
                auto& src_type = function.type(src_data);
8✔
216
                if (src_type.type_id() != types::TypeID::Pointer) {
8✔
NEW
217
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
218
                }
219
            }
8✔
220

221
            // Criterion: Destination must be a pointer to source type
222
            auto dst_data = dst_node->data();
10✔
223
            auto& dst_type = function.type(dst_data);
10✔
224
            if (dst_type.type_id() != types::TypeID::Pointer) {
10✔
UNCOV
225
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
226
            }
227

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

237
            break;
238
        }
10✔
239
        default:
240
            throw InvalidSDFGException("Memlet: Invalid memlet type");
×
241
    }
242
};
1,104✔
243

244
const graph::Edge Memlet::edge() const { return this->edge_; };
45✔
245

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

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

250
MemletType Memlet::type() const {
1,915✔
251
    if (this->dst_conn_ == "ref") {
1,915✔
252
        return Reference;
32✔
253
    } else if (this->dst_conn_ == "deref") {
1,883✔
254
        return Dereference_Src;
38✔
255
    } else if (this->src_conn_ == "deref") {
1,845✔
256
        return Dereference_Dst;
26✔
257
    } else {
258
        return Computational;
1,819✔
259
    }
260
}
1,915✔
261

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

264
DataFlowNode& Memlet::src() { return this->src_; };
46✔
265

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

268
DataFlowNode& Memlet::dst() { return this->dst_; };
34✔
269

270
const std::string& Memlet::src_conn() const { return this->src_conn_; };
297✔
271

272
const std::string& Memlet::dst_conn() const { return this->dst_conn_; };
355✔
273

274
const Subset Memlet::subset() const { return this->subset_; };
1,088✔
275

276
void Memlet::set_subset(const Subset& subset) { this->subset_ = subset; };
15✔
277

278
const types::IType& Memlet::base_type() const { return *this->base_type_; };
318✔
279

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

282
const types::IType& Memlet::result_type(const Function& function) const {
29✔
283
    return types::infer_type(function, *this->base_type_, this->subset_);
29✔
284
};
285

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

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

311
} // namespace data_flow
312
} // 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