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

daisytuner / docc / 30928647003

04 Aug 2026 04:20PM UTC coverage: 64.854% (+0.005%) from 64.849%
30928647003

push

github

web-flow
Merge pull request #931 from daisytuner/blas-expansion-constants

check alpha/beta values in GEMM and BatchedGEMM expansions

131 of 153 new or added lines in 3 files covered. (85.62%)

3 existing lines in 1 file now uncovered.

45774 of 70580 relevant lines covered (64.85%)

722.53 hits per line

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

59.52
/sdfg/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
#include "symengine/subs.h"
10

11
namespace sdfg {
12
namespace data_flow {
13

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

29
      };
9,754✔
30

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

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

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

67
                // Criterion: Non-void connector must be an output of the code node
68
                if (std::find(code_node->outputs().begin(), code_node->outputs().end(), this->src_conn_) ==
6,741✔
69
                    code_node->outputs().end()) {
6,741✔
70
                    throw InvalidSDFGException(
×
71
                        "Memlet " + std::to_string(element_id_) + " attached to non-existent " + this->src_conn_ +
×
72
                        " connector on #" + std::to_string(code_node->element_id())
×
73
                    );
×
74
                }
×
75
            } else {
6,741✔
76
                throw InvalidSDFGException(
×
77
                    "Memlet: Computation memlets must have void connector at source or destination"
×
78
                );
×
79
            }
×
80

81
            // If tensor, check that the type is consistenly defined
82
            if (this->base_type_->type_id() == types::TypeID::Tensor) {
22,842✔
83
                auto& tensor_type = dynamic_cast<const types::Tensor&>(*this->base_type_);
7,713✔
84
                if (tensor_type.is_scalar()) {
7,713✔
85
                    if (auto const_node = dynamic_cast<const data_flow::ConstantNode*>(data_node)) {
162✔
86
                        if (const_node->type().type_id() != types::TypeID::Scalar) {
14✔
87
                            throw InvalidSDFGException(
×
88
                                "Memlet: Scalar tensors must reference scalar buffers. Base type: " +
×
89
                                this->base_type_->print() + " Buffer type: " + const_node->type().print()
×
90
                            );
×
91
                        }
×
92
                    } else {
148✔
93
                        auto& buffer_type = function.type(data_node->data());
148✔
94
                        if (buffer_type.type_id() != types::TypeID::Scalar) {
148✔
95
                            throw InvalidSDFGException(
×
96
                                "Memlet: Scalar tensors must reference scalar buffers. Base type: " +
×
97
                                this->base_type_->print() + " Buffer type: " + buffer_type.print()
×
98
                            );
×
99
                        }
×
100
                    }
148✔
101
                } else {
7,551✔
102
                    auto& buffer_type = function.type(data_node->data());
7,551✔
103
                    if (buffer_type.type_id() != types::TypeID::Pointer) {
7,551✔
104
                        throw InvalidSDFGException(
×
105
                            "Memlet: Non-scalar tensors must reference pointer buffers. Base type: " +
×
106
                            this->base_type_->print() + " Buffer type: " + buffer_type.print()
×
107
                        );
×
108
                    }
×
109
                    if (this->subset_.size() > tensor_type.shape().size()) {
7,551✔
110
                        throw InvalidSDFGException(
×
111
                            "Memlet: Subset dimensions must match base type dimensions. Base type: " +
×
112
                            this->base_type_->print() + " Subset Dim: " + std::to_string(this->subset_.size())
×
113
                        );
×
114
                    }
×
115
                    if (tensor_type.shape().size() != tensor_type.strides().size()) {
7,551✔
116
                        throw InvalidSDFGException(
×
117
                            "Memlet: Tensor types must have the same number of shape and stride dimensions. Base "
×
118
                            "type: " +
×
119
                            this->base_type_->print()
×
120
                        );
×
121
                    }
×
122
                }
7,551✔
123
            }
7,713✔
124
            break;
22,842✔
125
        }
22,842✔
126
        case MemletType::Reference: {
22,842✔
127
            // Criterion: Destination must be an access node with a pointer type
128
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
404✔
129
            if (!dst_node) {
404✔
130
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node destination");
×
131
            }
×
132
            auto dst_data = dst_node->data();
404✔
133
            // Criterion: Destination must be non-constant
134
            if (helpers::is_number(dst_data) || symbolic::is_nullptr(symbolic::symbol(dst_data))) {
404✔
135
                throw InvalidSDFGException("Memlet: Reference memlets must have a non-constant destination");
×
136
            }
×
137

138
            // Criterion: Destination must be a pointer
139
            auto& dst_type = function.type(dst_data);
404✔
140
            if (dst_type.type_id() != types::TypeID::Pointer) {
404✔
141
                throw InvalidSDFGException("Memlet: Reference memlets must have a pointer destination");
×
142
            }
×
143

144
            // Criterion: Source must be an access node
145
            if (this->src_conn_ != "void") {
404✔
146
                throw InvalidSDFGException("Memlet: Reference memlets must have a void source");
×
147
            }
×
148
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
404✔
149
            if (!src_node) {
404✔
150
                throw InvalidSDFGException("Memlet: Reference memlets must have an access node source");
×
151
            }
×
152

153
            // Case: Constant
154
            if (helpers::is_number(src_node->data()) || symbolic::is_nullptr(symbolic::symbol(src_node->data()))) {
404✔
155
                if (!this->subset_.empty()) {
4✔
156
                    throw InvalidSDFGException("Memlet: Reference memlets for raw addresses must not have a subset");
×
157
                }
×
158
                return;
4✔
159
            }
4✔
160

161
            // Case: Container
162
            // Criterion: Must be contiguous memory reference
163
            // Throws exception if not contiguous
164
            types::infer_type(function, *this->base_type_, this->subset_);
400✔
165
            break;
400✔
166
        }
404✔
167
        case MemletType::Dereference_Src: {
27✔
168
            if (this->src_conn_ != "void") {
27✔
169
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void destination");
×
170
            }
×
171

172
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
27✔
173
            if (!src_node) {
27✔
174
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
175
            }
×
176
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
27✔
177
            if (!dst_node) {
27✔
178
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
179
            }
×
180

181
            // Criterion: Dereference memlets must have '0' as the only dimension
182
            if (this->subset_.size() != 1) {
27✔
183
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
184
            }
×
185
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
27✔
186
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
187
            }
×
188

189
            // Criterion: Source must be a pointer
190
            if (auto const_node = dynamic_cast<const ConstantNode*>(src_node)) {
27✔
191
                if (const_node->type().type_id() != types::TypeID::Pointer &&
×
192
                    const_node->type().type_id() != types::TypeID::Scalar) {
×
193
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
194
                }
×
195
            } else {
27✔
196
                auto src_data = src_node->data();
27✔
197
                auto& src_type = function.type(src_data);
27✔
198
                if (src_type.type_id() != types::TypeID::Pointer) {
27✔
199
                    throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer source");
×
200
                }
×
201
            }
27✔
202

203
            // Criterion: Must be typed pointer
204
            auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
27✔
205
            if (!base_pointer_type) {
27✔
206
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
207
            }
×
208
            if (!base_pointer_type->has_pointee_type()) {
27✔
209
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
210
            }
×
211

212
            break;
27✔
213
        }
27✔
214
        case MemletType::Dereference_Dst: {
27✔
215
            if (this->dst_conn_ != "void") {
18✔
216
                throw InvalidSDFGException("Memlet: Dereference memlets must have a void source");
×
217
            }
×
218

219
            auto src_node = dynamic_cast<const AccessNode*>(&this->src_);
18✔
220
            if (!src_node) {
18✔
221
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node source");
×
222
            }
×
223
            auto dst_node = dynamic_cast<const AccessNode*>(&this->dst_);
18✔
224
            if (!dst_node) {
18✔
225
                throw InvalidSDFGException("Memlet: Dereference memlets must have an access node destination");
×
226
            }
×
227

228
            // Criterion: Dereference memlets must have '0' as the only dimension
229
            if (this->subset_.size() != 1) {
18✔
230
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
231
            }
×
232
            if (!symbolic::eq(this->subset_[0], symbolic::zero())) {
18✔
233
                throw InvalidSDFGException("Memlet: Dereference memlets must have '0' as the only dimension");
×
234
            }
×
235

236
            // Criterion: src type cannot be a function
237
            const sdfg::types::IType* src_type;
18✔
238
            if (auto const_node = dynamic_cast<const data_flow::ConstantNode*>(src_node)) {
18✔
239
                src_type = &const_node->type();
2✔
240
            } else {
16✔
241
                src_type = &function.type(src_node->data());
16✔
242
            }
16✔
243
            if (src_type->type_id() == types::TypeID::Function) {
18✔
244
                throw InvalidSDFGException("Memlet: Dereference memlets cannot have source of type Function");
×
245
            }
×
246

247
            // Criterion: Destination must be a pointer
248
            if (auto const_node = dynamic_cast<const ConstantNode*>(dst_node)) {
18✔
249
                throw InvalidSDFGException("Memlet: Dereference memlets must have a non-constant destination");
×
250
            }
×
251
            auto dst_data = dst_node->data();
18✔
252
            auto& dst_type = function.type(dst_data);
18✔
253
            if (dst_type.type_id() != types::TypeID::Pointer) {
18✔
254
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointer destination");
×
255
            }
×
256

257
            // Criterion: Must be typed pointer
258
            auto base_pointer_type = dynamic_cast<const types::Pointer*>(this->base_type_.get());
18✔
259
            if (!base_pointer_type) {
18✔
260
                throw InvalidSDFGException("Memlet: Dereference memlets must have a typed pointer base type");
×
261
            }
×
262
            if (!base_pointer_type->has_pointee_type()) {
18✔
263
                throw InvalidSDFGException("Memlet: Dereference memlets must have a pointee type");
×
264
            }
×
265

266
            break;
18✔
267
        }
18✔
268
        default:
18✔
269
            throw InvalidSDFGException("Memlet: Invalid memlet type");
×
270
    }
23,291✔
271
};
23,291✔
272

273
const graph::Edge Memlet::edge() const { return this->edge_; };
2,007✔
274

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

277
DataFlowGraph& Memlet::get_parent() { return *this->parent_; };
925✔
278

279
MemletType Memlet::type() const {
41,461✔
280
    if (this->dst_conn_ == "ref") {
41,461✔
281
        return Reference;
626✔
282
    } else if (this->dst_conn_ == "deref") {
40,835✔
283
        return Dereference_Src;
92✔
284
    } else if (this->src_conn_ == "deref") {
40,743✔
285
        return Dereference_Dst;
61✔
286
    } else {
40,682✔
287
        return Computational;
40,682✔
288
    }
40,682✔
289
}
41,461✔
290

291
bool Memlet::is_src_read() const {
9✔
292
    if (src_conn_ == "void" || src_conn_ == "deref") { // anything else is not an access node on the input
9✔
293
        auto t = type();
9✔
294
        if (t == Computational) {
9✔
295
            return true;
9✔
296
        }
9✔
297
        if (t == Dereference_Dst || t == Dereference_Src) {
×
298
            return true;
×
299
        }
×
300
        if (t == Reference && !subset_.empty() && base_type_ && base_type_->type_id() == types::TypeID::Pointer) {
×
301
            return true; // we hide the read of src for pointer types
×
302
        }
×
303
    }
×
304
    return false;
×
305
}
9✔
306

307
bool Memlet::is_src_direct_read() const {
×
308
    if (src_conn_ == "void" || src_conn_ == "deref") { // anything else is not an access node on the input
×
309
        auto t = type();
×
310
        if (t == Computational && base_type_ && (base_type_->type_id() != types::TypeID::Pointer || subset_.empty())) {
×
311
            return true;
×
312
        }
×
313
        if (t == Dereference_Dst) {
×
314
            return true;
×
315
        }
×
316
    }
×
317
    return false;
×
318
}
×
319

320
static bool is_type_with_indirect_accesses(types::TypeID id) {
343✔
321
    return (
343✔
322
        id == types::TypeID::Pointer || id == types::TypeID::Array || id == types::TypeID::Structure ||
343✔
323
        id == types::TypeID::Tensor
343✔
324
    );
343✔
325
}
343✔
326

327
bool Memlet::is_src_pointed_to_read() const {
200✔
328
    if (src_conn_ == "void" || src_conn_ == "deref") {
200✔
329
        auto t = type();
200✔
330
        if (t == Dereference_Src) {
200✔
331
            return true;
×
332
        }
×
333
        if (t == Computational && is_type_with_indirect_accesses(base_type_->type_id()) && !subset_.empty()) {
200✔
334
            return true; // implicitly reads src, because we are crazy
151✔
335
        }
151✔
336
    }
200✔
337
    return false;
49✔
338
}
200✔
339

340
bool Memlet::is_src_address_leak() const {
703✔
341
    if (src_conn_ == "void" || src_conn_ == "deref") {
703✔
342
        auto t = type();
703✔
343
        if (t == Reference) {
703✔
344
            if (subset_.empty()) {
×
345
                return true;
×
346
            }
×
347
            if (!subset_.empty() && base_type_ && base_type_->type_id() != types::TypeID::Pointer) {
×
348
                return true;
×
349
            }
×
350
        }
×
351
    }
703✔
352
    return false;
703✔
353
}
703✔
354

355
bool Memlet::is_src_pointed_to_address_leak(const types::IType& src_type) const {
1,555✔
356
    if (src_conn_ == "void" || src_conn_ == "deref") {
1,555✔
357
        auto t = type();
1,555✔
358
        if (src_type.type_id() == types::TypeID::Pointer) { // even if we use it as integer
1,555✔
359
            if (t == Computational && base_type_ && base_type_->type_id() == types::TypeID::Scalar) { // reinterpret as
1,132✔
360
                                                                                                      // not pointer,
361
                                                                                                      // but the
362
                                                                                                      // pointer is
363
                                                                                                      // still read
364
                return true;
2✔
365
            }
2✔
366
            if (t == Dereference_Dst) {
1,130✔
367
                return true;
2✔
368
            }
2✔
369
        }
1,130✔
370
        if (base_type_ && base_type_->type_id() == types::TypeID::Pointer) { // read as pointer, so more hidden things
1,551✔
371
                                                                             // possible
372
            if (t == Reference && !subset_.empty()) { // = address calc of ptr + subsets
1,148✔
373
                return true;
2✔
374
            }
2✔
375
            if (t == Dereference_Dst) { // straight reads the contents of the ptr
1,146✔
376
                return true;
×
377
            }
×
378
            if (t == Computational && subset().empty()) {
1,146✔
379
                return true;
76✔
380
            }
76✔
381
        }
1,146✔
382
    }
1,551✔
383
    return false;
1,473✔
384
}
1,555✔
385

386
bool Memlet::is_dst_write() const {
374✔
387
    if (dst_conn_ == "void" || dst_conn_ == "deref" || dst_conn_ == "ref") { // everyting else is not an access node at
374✔
388
                                                                             // dst
389
        auto t = type();
374✔
390
        if (t == Reference) {
374✔
391
            return true;
1✔
392
        }
1✔
393
        if (t == Computational) { // we already checked that dst is access node. So subset & type must be for that
373✔
394
            if (base_type_ && (base_type_->type_id() != types::TypeID::Pointer || subset_.empty())) {
372✔
395
                return true; // we either write to dst contents or if its a pointer, not to sth. indirect
227✔
396
            }
227✔
397
        }
372✔
398
        if (t == Dereference_Src) {
146✔
399
            return true;
×
400
        }
×
401
    }
146✔
402
    return false;
146✔
403
}
374✔
404

405
bool Memlet::is_dst_read() const {
×
406
    if (dst_conn_ == "void" || dst_conn_ == "deref" || dst_conn_ == "ref") {
×
407
        // everyting else is not an access node at dst
408
        auto t = type();
×
409
        if (t == Dereference_Dst) {
×
410
            return true;
×
411
        }
×
412
        if (t == Computational) { // we already checked that dst is access node. So subset & type must be for that
×
413
            if (base_type_ && base_type_->type_id() == types::TypeID::Pointer && !subset_.empty()) {
×
414
                return true; // we use dst only as base address for the actual write
×
415
            }
×
416
        }
×
417
    }
×
418
    return false;
×
419
}
×
420

421
bool Memlet::is_dst_pointed_to_write() const {
171✔
422
    if (dst_conn_ == "void" || dst_conn_ == "deref" || dst_conn_ == "ref") {
171✔
423
        auto t = type();
171✔
424
        if (t == Dereference_Dst) {
171✔
425
            return true;
×
426
        }
×
427
        if (t == Computational) { // we already checked that dst is access node. So subset & type must be for that
171✔
428
            if (!subset_.empty() && base_type_ && is_type_with_indirect_accesses(base_type_->type_id())) {
171✔
429
                return true; // we use dst only as base address for the actual write
143✔
430
            }
143✔
431
        }
171✔
432
    }
171✔
433
    return false;
28✔
434
}
171✔
435

436
bool Memlet::is_src_constant(double value) const {
26✔
437
    if (src_conn_ == "void") {
26✔
438
        auto t = type();
26✔
439
        if (t == Computational) {
26✔
440
            auto* const_node = dynamic_cast<const ConstantNode*>(&this->src_);
26✔
441
            if (const_node != nullptr) {
26✔
442
                try {
26✔
443
                    return std::stod(const_node->data()) == value;
26✔
444
                } catch (const std::exception&) {
26✔
NEW
445
                    return false;
×
NEW
446
                }
×
447
            }
26✔
448
        }
26✔
449
    }
26✔
NEW
450
    return false;
×
451
}
26✔
452

NEW
453
bool Memlet::is_src_constant(int64_t value) const {
×
NEW
454
    if (src_conn_ == "void") {
×
NEW
455
        auto t = type();
×
NEW
456
        if (t == Computational) {
×
NEW
457
            auto* const_node = dynamic_cast<const ConstantNode*>(&this->src_);
×
NEW
458
            if (const_node != nullptr) {
×
NEW
459
                try {
×
NEW
460
                    size_t pos = 0;
×
NEW
461
                    const auto& data = const_node->data();
×
NEW
462
                    int64_t parsed = std::stoll(data, &pos);
×
463
                    // Reject partial parses (e.g. floats like "1.0") to keep integer matching exact.
NEW
464
                    return pos == data.size() && parsed == value;
×
NEW
465
                } catch (const std::exception&) {
×
NEW
466
                    return false;
×
NEW
467
                }
×
NEW
468
            }
×
NEW
469
        }
×
NEW
470
    }
×
NEW
471
    return false;
×
NEW
472
}
×
473

474
const DataFlowNode& Memlet::src() const { return this->src_; };
19,313✔
475

476
DataFlowNode& Memlet::src() { return this->src_; };
12,148✔
477

478
const DataFlowNode& Memlet::dst() const { return this->dst_; };
10,611✔
479

480
DataFlowNode& Memlet::dst() { return this->dst_; };
3,905✔
481

482
const std::string& Memlet::src_conn() const { return this->src_conn_; };
763✔
483

484
const std::string& Memlet::dst_conn() const { return this->dst_conn_; };
20,207✔
485

486
const Subset& Memlet::subset() const { return this->subset_; };
23,591✔
487

488
void Memlet::set_subset(const Subset& subset) { this->subset_ = subset; };
188✔
489

490
const types::IType& Memlet::base_type() const { return *this->base_type_; };
11,847✔
491

492
void Memlet::set_base_type(const types::IType& base_type) { this->base_type_ = base_type.clone(); };
171✔
493

494
std::unique_ptr<types::IType> Memlet::result_type(const Function& function) const {
6,419✔
495
    return types::infer_type(function, *this->base_type_, this->subset_);
6,419✔
496
};
6,419✔
497

498
std::unique_ptr<Memlet> Memlet::clone(
499
    size_t element_id, const graph::Edge& edge, DataFlowGraph& parent, DataFlowNode& src, DataFlowNode& dst
500
) const {
17✔
501
    return std::unique_ptr<Memlet>(new Memlet(
17✔
502
        element_id,
17✔
503
        this->debug_info_,
17✔
504
        edge,
17✔
505
        parent,
17✔
506
        src,
17✔
507
        this->src_conn_,
17✔
508
        dst,
17✔
509
        this->dst_conn_,
17✔
510
        this->subset_,
17✔
511
        *this->base_type_
17✔
512
    ));
17✔
513
};
17✔
514

515
void Memlet::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
886✔
516
    Subset new_subset;
886✔
517
    for (auto& dim : this->subset_) {
886✔
518
        new_subset.push_back(symbolic::subs(dim, old_expression, new_expression));
766✔
519
    }
766✔
520
    this->subset_ = new_subset;
886✔
521
    this->base_type_->replace_symbols(old_expression, new_expression);
886✔
522
}
886✔
523

524
void Memlet::replace(const symbolic::ExpressionMapping& replacements) {
89✔
525
    this->subset_ = symbolic::substitute(this->subset_, replacements);
89✔
526
    this->base_type_->replace_symbols(replacements);
89✔
527
}
89✔
528

529
} // namespace data_flow
530
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc