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

daisytuner / sdfglib / 18727774411

22 Oct 2025 07:37PM UTC coverage: 61.468% (-0.3%) from 61.746%
18727774411

push

github

web-flow
Merge pull request #296 from daisytuner/fix-external-prefix

Fixes for building OpenFOAM with DOCC

9 of 19 new or added lines in 6 files covered. (47.37%)

44 existing lines in 4 files now uncovered.

9704 of 15787 relevant lines covered (61.47%)

100.86 hits per line

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

67.28
/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(
618✔
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,236✔
26
      dst_conn_(dst_conn), subset_(subset), base_type_(base_type.clone()) {
618✔
27

28
      };
618✔
29

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

39
    // Validate connections
40
    switch (this->type()) {
1,123✔
41
        case MemletType::Computational: {
42
            // Criterion: Must connect a code node and an access node with void connector at access node
43
            const AccessNode* data_node = nullptr;
1,065✔
44
            const CodeNode* code_node = nullptr;
1,065✔
45
            if (this->src_conn_ == "void") {
1,065✔
46
                data_node = dynamic_cast<const AccessNode*>(&this->src_);
628✔
47
                code_node = dynamic_cast<const CodeNode*>(&this->dst_);
628✔
48
                if (!data_node || !code_node) {
628✔
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,256✔
55
                    code_node->inputs().end()) {
628✔
56
                    throw InvalidSDFGException("Memlet: Computation memlets must have an input in the code node");
×
57
                }
58
            } else if (this->dst_conn_ == "void") {
1,065✔
59
                data_node = dynamic_cast<const AccessNode*>(&this->dst_);
437✔
60
                code_node = dynamic_cast<const CodeNode*>(&this->src_);
437✔
61
                if (!data_node || !code_node) {
437✔
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_) ==
874✔
68
                    code_node->outputs().end()) {
437✔
69
                    throw InvalidSDFGException("Memlet: Computation memlets must have an output in the code node");
×
70
                }
71
            } else {
437✔
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)) {
1,065✔
79
                return;
38✔
80
            }
81

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

216
            // Criterion: Destination must be a pointer
217
            if (auto const_node = dynamic_cast<const ConstantNode*>(dst_node)) {
10✔
218
                throw InvalidSDFGException("Memlet: Dereference memlets must have a non-constant destination");
×
219
            }
220
            auto dst_data = dst_node->data();
10✔
221
            auto& dst_type = function.type(dst_data);
10✔
222
            if (dst_type.type_id() != types::TypeID::Pointer) {
10✔
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());
10✔
228
            if (!base_pointer_type) {
10✔
229
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
230
            }
231
            if (!base_pointer_type->has_pointee_type()) {
10✔
232
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
233
            }
234

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

242
const graph::Edge Memlet::edge() const { return this->edge_; };
36✔
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 {
2,139✔
249
    if (this->dst_conn_ == "ref") {
2,139✔
250
        return Reference;
70✔
251
    } else if (this->dst_conn_ == "deref") {
2,069✔
252
        return Dereference_Src;
37✔
253
    } else if (this->src_conn_ == "deref") {
2,032✔
254
        return Dereference_Dst;
37✔
255
    } else {
256
        return Computational;
1,995✔
257
    }
258
}
2,139✔
259

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

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

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

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

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

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

272
const Subset Memlet::subset() const { return this->subset_; };
1,630✔
273

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

276
const types::IType& Memlet::base_type() const { return *this->base_type_; };
702✔
277

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

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

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

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

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