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

daisytuner / sdfglib / 17656823807

11 Sep 2025 08:42PM UTC coverage: 60.447% (+1.1%) from 59.335%
17656823807

Pull #219

github

web-flow
Merge d5416236f into 6c1992b40
Pull Request #219: stdlib Library Nodes and ConstantNodes

460 of 1635 new or added lines in 81 files covered. (28.13%)

93 existing lines in 35 files now uncovered.

9385 of 15526 relevant lines covered (60.45%)

107.21 hits per line

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

67.08
/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
    switch (this->type()) {
1,104✔
31
        case MemletType::Computational: {
32
            // Criterion: Must connect a code node and an access node with void connector at access node
33
            const AccessNode* data_node = nullptr;
1,058✔
34
            const CodeNode* code_node = nullptr;
1,058✔
35
            if (this->src_conn_ == "void") {
1,058✔
36
                data_node = dynamic_cast<const AccessNode*>(&this->src_);
514✔
37
                code_node = dynamic_cast<const CodeNode*>(&this->dst_);
514✔
38
                if (!data_node || !code_node) {
514✔
39
                    throw InvalidSDFGException("Memlet: Computation memlets must connect a code node and an access node"
×
40
                    );
41
                }
42

43
                // Criterion: Non-void connector must be an input of the code node
44
                if (std::find(code_node->inputs().begin(), code_node->inputs().end(), this->dst_conn_) ==
1,028✔
45
                    code_node->inputs().end()) {
514✔
46
                    throw InvalidSDFGException("Memlet: Computation memlets must have an input in the code node");
×
47
                }
48
            } else if (this->dst_conn_ == "void") {
1,058✔
49
                data_node = dynamic_cast<const AccessNode*>(&this->dst_);
544✔
50
                code_node = dynamic_cast<const CodeNode*>(&this->src_);
544✔
51
                if (!data_node || !code_node) {
544✔
52
                    throw InvalidSDFGException("Memlet: Computation memlets must connect a code node and an access node"
×
53
                    );
54
                }
55

56
                // Criterion: Non-void connector must be an output of the code node
57
                if (std::find(code_node->outputs().begin(), code_node->outputs().end(), this->src_conn_) ==
1,088✔
58
                    code_node->outputs().end()) {
544✔
59
                    throw InvalidSDFGException("Memlet: Computation memlets must have an output in the code node");
×
60
                }
61
            } else {
544✔
62
                throw InvalidSDFGException(
×
63
                    "Memlet: Computation memlets must have void connector at source or destination"
×
64
                );
65
            }
66

67
            // Return if library node
68
            if (dynamic_cast<const LibraryNode*>(code_node)) {
1,058✔
69
                return;
45✔
70
            }
71

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

75
            // Criterion: Inferred type must be a scalar
76
            if (inferred_type.type_id() != types::TypeID::Scalar) {
1,013✔
77
                throw InvalidSDFGException("Memlet: Computation memlets must have a scalar destination");
×
78
            }
79
            break;
1,013✔
80
        }
81
        case MemletType::Reference: {
82
            // Criterion: Destination must be an access node with a pointer type
83
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
21✔
84
            if (!dst_node) {
21✔
85
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node destination");
×
86
            }
87
            auto dst_data = dst_node->data();
21✔
88
            // Criterion: Destination must be non-constant
89
            if (helpers::is_number(dst_data) || symbolic::is_nullptr(symbolic::symbol(dst_data))) {
21✔
90
                throw InvalidSDFGException("Memlet: Reference memlets must have a non-constant destination");
×
91
            }
92

93
            // Criterion: Destination must be a pointer
94
            auto& dst_type = function.type(dst_data);
21✔
95
            if (dst_type.type_id() != types::TypeID::Pointer) {
21✔
96
                throw InvalidSDFGException("Memlet: Reference memlets must have a pointer destination");
×
97
            }
98

99
            // Criterion: Source must be an access node
100
            if (this->src_conn_ != "void") {
21✔
101
                throw InvalidSDFGException("Memlet: Reference memlets must have a void source");
×
102
            }
103
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
21✔
104
            if (!src_node) {
21✔
105
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node source");
×
106
            }
107

108
            // Case: Constant
109
            if (helpers::is_number(src_node->data()) || symbolic::is_nullptr(symbolic::symbol(src_node->data()))) {
21✔
110
                if (!this->subset_.empty()) {
4✔
111
                    throw InvalidSDFGException("Memlet: Reference memlets for raw addresses must not have a subset");
×
112
                }
113
                return;
4✔
114
            }
115

116
            // Case: Container
117
            // Criterion: Must be contiguous memory reference
118
            // Throws exception if not contiguous
119
            types::infer_type(function, *this->base_type_, this->subset_);
17✔
120
            break;
17✔
121
        }
21✔
122
        case MemletType::Dereference_Src: {
123
            if (this->src_conn_ != "void") {
15✔
124
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void destination");
×
125
            }
126

127
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
15✔
128
            if (!src_node) {
15✔
129
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
130
            }
131
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
15✔
132
            if (!dst_node) {
15✔
133
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
134
            }
135

136
            // Criterion: Dereference memlets must have '0' as the only dimension
137
            if (this->subset_.size() != 1) {
15✔
138
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
139
            }
140
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
15✔
141
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
142
            }
143

144
            // Criterion: Source must be a pointer
145
            if (auto const_node = dynamic_cast<const ConstantNode*>(src_node)) {
15✔
NEW
146
                if (const_node->type().type_id() != types::TypeID::Pointer &&
×
NEW
147
                    const_node->type().type_id() != types::TypeID::Scalar) {
×
NEW
148
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
149
                }
NEW
150
            } else {
×
151
                auto src_data = src_node->data();
15✔
152
                auto& src_type = function.type(src_data);
15✔
153
                if (src_type.type_id() != types::TypeID::Pointer) {
15✔
NEW
154
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
155
                }
156
            }
15✔
157

158
            // Criterion: Destination must be a pointer to source type
159
            auto dst_data = dst_node->data();
15✔
160
            auto& dst_type = function.type(dst_data);
15✔
161
            if (dst_type.type_id() != types::TypeID::Pointer) {
15✔
UNCOV
162
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
163
            }
164

165
            // Criterion: Must be typed pointer
166
            auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
15✔
167
            if (!base_pointer_type) {
15✔
168
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
169
            }
170
            if (!base_pointer_type->has_pointee_type()) {
15✔
171
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
172
            }
173

174
            break;
175
        }
15✔
176
        case MemletType::Dereference_Dst: {
177
            if (this->dst_conn_ != "void") {
10✔
178
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void source");
×
179
            }
180

181
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
10✔
182
            if (!src_node) {
10✔
183
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
184
            }
185
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
10✔
186
            if (!dst_node) {
10✔
187
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
188
            }
189

190
            // Criterion: Dereference memlets must have '0' as the only dimension
191
            if (this->subset_.size() != 1) {
10✔
192
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
193
            }
194
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
10✔
195
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
196
            }
197

198
            // Criterion: Source must be a pointer
199
            if (auto const_node = dynamic_cast<const ConstantNode*>(src_node)) {
10✔
200
                if (const_node->type().type_id() != types::TypeID::Pointer &&
2✔
NEW
201
                    const_node->type().type_id() != types::TypeID::Scalar) {
×
NEW
202
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
203
                }
204
            } else {
2✔
205
                auto src_data = src_node->data();
8✔
206
                auto& src_type = function.type(src_data);
8✔
207
                if (src_type.type_id() != types::TypeID::Pointer) {
8✔
NEW
208
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
209
                }
210
            }
8✔
211

212
            // Criterion: Destination must be a pointer to source type
213
            auto dst_data = dst_node->data();
10✔
214
            auto& dst_type = function.type(dst_data);
10✔
215
            if (dst_type.type_id() != types::TypeID::Pointer) {
10✔
UNCOV
216
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
217
            }
218

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

228
            break;
229
        }
10✔
230
        default:
231
            throw InvalidSDFGException("Memlet: Invalid memlet type");
×
232
    }
233
};
1,104✔
234

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

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

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

241
MemletType Memlet::type() const {
1,915✔
242
    if (this->dst_conn_ == "ref") {
1,915✔
243
        return Reference;
32✔
244
    } else if (this->dst_conn_ == "deref") {
1,883✔
245
        return Dereference_Src;
38✔
246
    } else if (this->src_conn_ == "deref") {
1,845✔
247
        return Dereference_Dst;
26✔
248
    } else {
249
        return Computational;
1,819✔
250
    }
251
}
1,915✔
252

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

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

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

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

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

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

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

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

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

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

273
const types::IType& Memlet::result_type(const Function& function) const {
29✔
274
    return types::infer_type(function, *this->base_type_, this->subset_);
29✔
275
};
276

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

294
void Memlet::replace(const symbolic::Expression& old_expression, const symbolic::Expression& new_expression) {
8✔
295
    for (auto& dim : this->subset_) {
14✔
296
        dim = symbolic::subs(dim, old_expression, new_expression);
6✔
297
    }
298
};
8✔
299

300
} // namespace data_flow
301
} // 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

© 2025 Coveralls, Inc