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

daisytuner / sdfglib / 15044057891

15 May 2025 11:42AM UTC coverage: 59.37% (+1.8%) from 57.525%
15044057891

push

github

web-flow
Merge pull request #14 from daisytuner/sanitizers

enables sanitizer on unit tests

63 of 67 new or added lines in 47 files covered. (94.03%)

570 existing lines in 62 files now uncovered.

7356 of 12390 relevant lines covered (59.37%)

505.93 hits per line

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

94.12
/src/transformations/out_local_storage.cpp
1
#include "sdfg/transformations/out_local_storage.h"
2

3
#include <string>
4

5
#include "sdfg/builder/structured_sdfg_builder.h"
6
#include "sdfg/data_flow/memlet.h"
7
#include "sdfg/passes/structured_control_flow/dead_cfg_elimination.h"
8
#include "sdfg/passes/structured_control_flow/sequence_fusion.h"
9
#include "sdfg/symbolic/symbolic.h"
10
#include "sdfg/transformations/utils.h"
11
#include "sdfg/types/array.h"
12
#include "sdfg/types/scalar.h"
13

14
namespace sdfg {
15
namespace transformations {
16

17
OutLocalStorage::OutLocalStorage(structured_control_flow::Sequence& parent,
3✔
18
                                 structured_control_flow::For& loop, std::string container)
19
    : parent_(parent), loop_(loop), container_(container) {};
3✔
20

21
std::string OutLocalStorage::name() { return "OutLocalStorage"; };
×
22

23
bool OutLocalStorage::can_be_applied(Schedule& schedule) {
3✔
24
    auto& analysis_manager = schedule.analysis_manager();
3✔
25
    auto& builder = schedule.builder();
3✔
26

27
    auto& sdfg = builder.subject();
3✔
28
    auto& root = sdfg.root();
3✔
29
    auto& body = this->loop_.root();
3✔
30
    this->requires_array_ = false;
3✔
31

32
    // Criterion: Check if container exists and is used in the loop
33
    auto& users = analysis_manager.get<analysis::Users>();
3✔
34
    analysis::UsersView body_users(users, body);
3✔
35
    if (body_users.uses(this->container_).size() == 0) {
3✔
36
        return false;
1✔
37
    }
38

39
    // Criterion: Check if all accesses to the container within the loop are identical
40
    auto accesses = body_users.uses(this->container_);
2✔
41
    auto first_access = accesses.at(0);
2✔
42
    auto first_subset = first_access->subsets().at(0);
2✔
43
    if (accesses.size() > 1) {
2✔
44
        for (auto access : accesses) {
6✔
45
            if (first_access->subsets().size() != access->subsets().size()) {
4✔
46
                return false;
×
47
            }
48
            for (int i = 0; i < first_access->subsets().size(); i++) {
8✔
49
                auto subset = access->subsets().at(i);
4✔
50
                if (first_subset.size() != subset.size()) {
4✔
51
                    return false;
×
52
                }
53
                for (int j = 0; j < first_subset.size(); j++) {
6✔
54
                    if (!symbolic::eq(first_subset.at(j), subset.at(j))) {
2✔
55
                        return false;
×
56
                    }
57
                }
2✔
58
            }
4✔
59
        }
60
    }
2✔
61

62
    // Criterion: Check if accesses do not depend on containers written in the loop
63
    auto writes = body_users.writes();
2✔
64
    symbolic::SymbolicSet written_containers;
2✔
65
    for (auto write : writes) {
4✔
66
        written_containers.insert(symbolic::symbol(write->container()));
2✔
67
    }
68
    for (auto subset : first_access->subsets()) {
4✔
69
        for (auto access : subset) {
3✔
70
            for (auto atom : symbolic::atoms(access)) {
2✔
71
                if (written_containers.contains(atom)) {
1✔
72
                    return false;
×
73
                }
74
            }
1✔
75
        }
1✔
76
    }
2✔
77

78
    // Soft Criterion: Check if the accesses do not depend on the loop iteration
79
    // Decide if an array or scalar is required
80
    for (auto subset : first_access->subsets()) {
4✔
81
        for (auto access : subset) {
2✔
82
            for (auto atom : symbolic::atoms(access)) {
2✔
83
                if (symbolic::eq(atom, this->loop_.indvar())) {
1✔
84
                    this->requires_array_ = true;
1✔
85
                    break;
1✔
86
                }
87
            }
1✔
88
            if (this->requires_array_) {
1✔
89
                break;
1✔
90
            }
91
        }
1✔
92
        if (this->requires_array_) {
2✔
93
            break;
1✔
94
        }
95
    }
2✔
96

97
    // Criterion: Check if the loop iteration count is known and an Integer when an array is
98
    // required
99
    if (this->requires_array_) {
2✔
100
        auto iteration_count = get_iteration_count(this->loop_);
1✔
101
        if (iteration_count == SymEngine::null) {
1✔
102
            return false;
×
103
        }
104
    }
1✔
105

106
    return true;
2✔
107
};
3✔
108

109
void OutLocalStorage::apply(Schedule& schedule) {
2✔
110
    if (requires_array_) {
2✔
111
        apply_array(schedule);
1✔
112
    } else {
1✔
113
        apply_scalar(schedule);
1✔
114
    }
115

116
    // End of transformation
117

118
    auto& analysis_manager = schedule.analysis_manager();
2✔
119
    analysis_manager.invalidate_all();
2✔
120

121
    passes::SequenceFusion sf_pass;
2✔
122
    passes::DeadCFGElimination dce_pass;
2✔
123
    bool applies = false;
2✔
124
    do {
2✔
125
        applies = false;
2✔
126
        applies |= dce_pass.run(schedule.builder(), analysis_manager);
2✔
127
        applies |= sf_pass.run(schedule.builder(), analysis_manager);
2✔
128
    } while (applies);
2✔
129
};
2✔
130

131
void OutLocalStorage::apply_array(Schedule& schedule) {
1✔
132
    auto& analysis_manager = schedule.analysis_manager();
1✔
133
    auto& builder = schedule.builder();
1✔
134
    auto& sdfg = builder.subject();
1✔
135
    auto& root = sdfg.root();
1✔
136
    auto& users = analysis_manager.get<analysis::Users>();
1✔
137
    auto& parent = builder.parent(loop_);
1✔
138
    auto replacement_name = "__daisy_out_local_storage_" + this->container_;
1✔
139

140
    auto iteration_count = get_iteration_count(this->loop_);
1✔
141
    types::Scalar scalar_type(sdfg.type(this->container_).primitive_type());
1✔
142
    types::Array array_type(scalar_type, iteration_count);
1✔
143
    builder.add_container(replacement_name, array_type);
1✔
144

145
    auto indvar_name = "__daisy_out_local_storage_" + this->loop_.indvar()->get_name();
1✔
146
    types::Scalar indvar_type(sdfg.type(loop_.indvar()->get_name()).primitive_type());
1✔
147
    builder.add_container(indvar_name, indvar_type);
1✔
148
    auto indvar = symbolic::symbol(indvar_name);
1✔
149
    auto init = loop_.init();
1✔
150
    auto update = symbolic::subs(loop_.update(), loop_.indvar(), indvar);
1✔
151
    auto condition = symbolic::subs(loop_.condition(), loop_.indvar(), indvar);
1✔
152

153
    analysis::UsersView body_users(users, loop_.root());
1✔
154
    auto accesses = body_users.uses(this->container_);
1✔
155
    auto first_access = accesses.at(0);
1✔
156
    auto first_subset = first_access->subsets().at(0);
1✔
157
    auto& init_loop = builder.add_for_before(parent, loop_, indvar, condition, init, update).first;
1✔
158
    auto& init_body = init_loop.root();
1✔
159
    auto& init_block = builder.add_block(init_body);
1✔
160
    auto& init_access_read = builder.add_access(init_block, this->container_);
1✔
161
    auto& init_access_write = builder.add_access(init_block, replacement_name);
1✔
162
    auto& init_tasklet = builder.add_tasklet(init_block, data_flow::TaskletCode::assign,
2✔
163
                                             {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
164
    auto& init_memlet_in =
1✔
165
        builder.add_memlet(init_block, init_access_read, "void", init_tasklet, "_in", first_subset);
1✔
166
    init_memlet_in.replace(loop_.indvar(), indvar);
1✔
167
    auto& init_memlet_out =
1✔
168
        builder.add_memlet(init_block, init_tasklet, "_out", init_access_write, "void", {indvar});
1✔
169

170
    auto& reset_loop = builder.add_for_after(parent, loop_, indvar, condition, init, update).first;
1✔
171
    auto& reset_body = reset_loop.root();
1✔
172
    auto& reset_block = builder.add_block(reset_body);
1✔
173
    auto& reset_access_read = builder.add_access(reset_block, replacement_name);
1✔
174
    auto& reset_access_write = builder.add_access(reset_block, this->container_);
1✔
175
    auto& reset_tasklet = builder.add_tasklet(reset_block, data_flow::TaskletCode::assign,
2✔
176
                                              {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
177
    auto& reset_memlet_in =
1✔
178
        builder.add_memlet(reset_block, reset_access_read, "void", reset_tasklet, "_in", {indvar});
1✔
179
    auto& reset_memlet_out = builder.add_memlet(reset_block, reset_tasklet, "_out",
2✔
180
                                                reset_access_write, "void", first_subset);
1✔
181
    reset_memlet_out.replace(loop_.indvar(), indvar);
1✔
182

183
    auto container_users = body_users.uses(this->container_);
1✔
184
    for (auto user : body_users.uses(this->container_)) {
3✔
185
        auto element = user->element();
2✔
186
        if (auto memlet = dynamic_cast<data_flow::Memlet*>(element)) {
2✔
187
            auto& subset = memlet->subset();
×
188
            subset.clear();
×
189
            subset.push_back(this->loop_.indvar());
×
UNCOV
190
        }
×
191
    }
192
    loop_.replace(symbolic::symbol(this->container_), symbolic::symbol(replacement_name));
1✔
193
};
1✔
194

195
void OutLocalStorage::apply_scalar(Schedule& schedule) {
1✔
196
    auto& analysis_manager = schedule.analysis_manager();
1✔
197
    auto& builder = schedule.builder();
1✔
198
    auto& sdfg = builder.subject();
1✔
199
    auto& root = sdfg.root();
1✔
200
    auto& users = analysis_manager.get<analysis::Users>();
1✔
201
    auto& parent = builder.parent(loop_);
1✔
202
    auto replacement_name = "__daisy_out_local_storage_" + this->container_;
1✔
203

204
    types::Scalar scalar_type(sdfg.type(this->container_).primitive_type());
1✔
205
    builder.add_container(replacement_name, scalar_type);
1✔
206

207
    analysis::UsersView body_users(users, loop_.root());
1✔
208
    auto accesses = body_users.uses(this->container_);
1✔
209
    auto first_access = accesses.at(0);
1✔
210
    auto first_subset = first_access->subsets().at(0);
1✔
211
    auto& init_block = builder.add_block_before(parent, loop_).first;
1✔
212
    auto& init_access_read = builder.add_access(init_block, this->container_);
1✔
213
    auto& init_access_write = builder.add_access(init_block, replacement_name);
1✔
214
    auto& init_tasklet = builder.add_tasklet(init_block, data_flow::TaskletCode::assign,
2✔
215
                                             {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
216
    auto& init_memlet_in =
1✔
217
        builder.add_memlet(init_block, init_access_read, "void", init_tasklet, "_in", first_subset);
1✔
218
    auto& init_memlet_out =
1✔
219
        builder.add_memlet(init_block, init_tasklet, "_out", init_access_write, "void", {});
1✔
220

221
    auto& reset_block = builder.add_block_after(parent, loop_).first;
1✔
222
    auto& reset_access_read = builder.add_access(reset_block, replacement_name);
1✔
223
    auto& reset_access_write = builder.add_access(reset_block, this->container_);
1✔
224
    auto& reset_tasklet = builder.add_tasklet(reset_block, data_flow::TaskletCode::assign,
2✔
225
                                              {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
226
    auto& reset_memlet_in =
1✔
227
        builder.add_memlet(reset_block, reset_access_read, "void", reset_tasklet, "_in", {});
1✔
228
    auto& reset_memlet_out = builder.add_memlet(reset_block, reset_tasklet, "_out",
2✔
229
                                                reset_access_write, "void", first_subset);
1✔
230

231
    this->loop_.replace(symbolic::symbol(this->container_), symbolic::symbol(replacement_name));
1✔
232
};
1✔
233

234
}  // namespace transformations
235
}  // 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