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

daisytuner / sdfglib / 16069945621

04 Jul 2025 08:56AM UTC coverage: 64.375% (-0.2%) from 64.606%
16069945621

push

github

web-flow
Merge pull request #137 from daisytuner/clang-format

runs clang-format on codebase

609 of 827 new or added lines in 63 files covered. (73.64%)

46 existing lines in 30 files now uncovered.

8578 of 13325 relevant lines covered (64.38%)

177.24 hits per line

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

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

3
#include <cassert>
4
#include <cstddef>
5
#include <string>
6

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

17
namespace sdfg {
18
namespace transformations {
19

20
OutLocalStorage::OutLocalStorage(structured_control_flow::StructuredLoop& loop, std::string container)
3✔
21
    : loop_(loop), container_(container) {};
3✔
22

23
std::string OutLocalStorage::name() const { return "OutLocalStorage"; };
×
24

25
bool OutLocalStorage::can_be_applied(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
3✔
26
    auto& body = this->loop_.root();
3✔
27
    this->requires_array_ = false;
3✔
28

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

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

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

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

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

103
    return true;
2✔
104
};
3✔
105

106
void OutLocalStorage::apply(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
2✔
107
    if (requires_array_) {
2✔
108
        apply_array(builder, analysis_manager);
1✔
109
    } else {
1✔
110
        apply_scalar(builder, analysis_manager);
1✔
111
    }
112

113
    // End of transformation
114

115
    analysis_manager.invalidate_all();
2✔
116

117
    passes::SequenceFusion sf_pass;
2✔
118
    passes::DeadCFGElimination dce_pass;
2✔
119
    bool applies = false;
2✔
120
    do {
2✔
121
        applies = false;
2✔
122
        applies |= dce_pass.run(builder, analysis_manager);
2✔
123
        applies |= sf_pass.run(builder, analysis_manager);
2✔
124
    } while (applies);
2✔
125
};
2✔
126

127
void OutLocalStorage::apply_array(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
1✔
128
    auto& sdfg = builder.subject();
1✔
129
    auto& users = analysis_manager.get<analysis::Users>();
1✔
130
    auto& parent = builder.parent(loop_);
1✔
131
    auto replacement_name = "__daisy_out_local_storage_" + this->container_;
1✔
132

133
    auto iteration_count = get_iteration_count(this->loop_);
1✔
134
    types::Scalar scalar_type(sdfg.type(this->container_).primitive_type());
1✔
135
    types::Array array_type(scalar_type, iteration_count);
1✔
136
    builder.add_container(replacement_name, array_type);
1✔
137

138
    auto indvar_name = "__daisy_out_local_storage_" + this->loop_.indvar()->get_name();
1✔
139
    types::Scalar indvar_type(sdfg.type(loop_.indvar()->get_name()).primitive_type());
1✔
140
    builder.add_container(indvar_name, indvar_type);
1✔
141
    auto indvar = symbolic::symbol(indvar_name);
1✔
142
    auto init = loop_.init();
1✔
143
    auto update = symbolic::subs(loop_.update(), loop_.indvar(), indvar);
1✔
144
    auto condition = symbolic::subs(loop_.condition(), loop_.indvar(), indvar);
1✔
145

146
    analysis::UsersView body_users(users, loop_.root());
1✔
147
    auto accesses = body_users.uses(this->container_);
1✔
148
    auto first_access = accesses.at(0);
1✔
149
    auto first_subset = first_access->subsets().at(0);
1✔
150
    auto& init_loop = builder.add_for_before(parent, loop_, indvar, condition, init, update).first;
1✔
151
    auto& init_body = init_loop.root();
1✔
152
    auto& init_block = builder.add_block(init_body);
1✔
153
    auto& init_access_read = builder.add_access(init_block, this->container_);
1✔
154
    auto& init_access_write = builder.add_access(init_block, replacement_name);
1✔
155
    auto& init_tasklet =
1✔
156
        builder.add_tasklet(init_block, data_flow::TaskletCode::assign, {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
157
    auto& init_memlet_in = builder.add_memlet(init_block, init_access_read, "void", init_tasklet, "_in", first_subset);
1✔
158
    init_memlet_in.replace(loop_.indvar(), indvar);
1✔
159
    builder.add_memlet(init_block, init_tasklet, "_out", init_access_write, "void", {indvar});
1✔
160

161
    auto& reset_loop = builder.add_for_after(parent, loop_, indvar, condition, init, update).first;
1✔
162
    auto& reset_body = reset_loop.root();
1✔
163
    auto& reset_block = builder.add_block(reset_body);
1✔
164
    auto& reset_access_read = builder.add_access(reset_block, replacement_name);
1✔
165
    auto& reset_access_write = builder.add_access(reset_block, this->container_);
1✔
166
    auto& reset_tasklet =
1✔
167
        builder.add_tasklet(reset_block, data_flow::TaskletCode::assign, {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
168
    builder.add_memlet(reset_block, reset_access_read, "void", reset_tasklet, "_in", {indvar});
1✔
169
    auto& reset_memlet_out =
1✔
170
        builder.add_memlet(reset_block, reset_tasklet, "_out", reset_access_write, "void", first_subset);
1✔
171
    reset_memlet_out.replace(loop_.indvar(), indvar);
1✔
172

173
    for (auto user : body_users.uses(this->container_)) {
3✔
174
        auto element = user->element();
2✔
175
        if (auto memlet = dynamic_cast<data_flow::Memlet*>(element)) {
2✔
176
            auto& subset = memlet->subset();
×
177
            subset.clear();
×
178
            subset.push_back(this->loop_.indvar());
×
179
        }
×
180
    }
181
    loop_.replace(symbolic::symbol(this->container_), symbolic::symbol(replacement_name));
1✔
182
};
1✔
183

184
void OutLocalStorage::apply_scalar(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
1✔
185
    auto& sdfg = builder.subject();
1✔
186
    auto& users = analysis_manager.get<analysis::Users>();
1✔
187
    auto& parent = builder.parent(loop_);
1✔
188
    auto replacement_name = "__daisy_out_local_storage_" + this->container_;
1✔
189

190
    types::Scalar scalar_type(sdfg.type(this->container_).primitive_type());
1✔
191
    builder.add_container(replacement_name, scalar_type);
1✔
192

193
    analysis::UsersView body_users(users, loop_.root());
1✔
194
    auto accesses = body_users.uses(this->container_);
1✔
195
    auto first_access = accesses.at(0);
1✔
196
    auto first_subset = first_access->subsets().at(0);
1✔
197
    auto& init_block = builder.add_block_before(parent, loop_).first;
1✔
198
    auto& init_access_read = builder.add_access(init_block, this->container_);
1✔
199
    auto& init_access_write = builder.add_access(init_block, replacement_name);
1✔
200
    auto& init_tasklet =
1✔
201
        builder.add_tasklet(init_block, data_flow::TaskletCode::assign, {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
202
    builder.add_memlet(init_block, init_access_read, "void", init_tasklet, "_in", first_subset);
1✔
203
    builder.add_memlet(init_block, init_tasklet, "_out", init_access_write, "void", {});
1✔
204

205
    auto& reset_block = builder.add_block_after(parent, loop_).first;
1✔
206
    auto& reset_access_read = builder.add_access(reset_block, replacement_name);
1✔
207
    auto& reset_access_write = builder.add_access(reset_block, this->container_);
1✔
208
    auto& reset_tasklet =
1✔
209
        builder.add_tasklet(reset_block, data_flow::TaskletCode::assign, {"_out", scalar_type}, {{"_in", scalar_type}});
1✔
210
    builder.add_memlet(reset_block, reset_access_read, "void", reset_tasklet, "_in", {});
1✔
211
    builder.add_memlet(reset_block, reset_tasklet, "_out", reset_access_write, "void", first_subset);
1✔
212

213
    this->loop_.replace(symbolic::symbol(this->container_), symbolic::symbol(replacement_name));
1✔
214
};
1✔
215

216
void OutLocalStorage::to_json(nlohmann::json& j) const {
×
217
    j["transformation_type"] = this->name();
×
218
    j["loop_element_id"] = loop_.element_id();
×
219
    j["container"] = container_;
×
220
};
×
221

NEW
222
OutLocalStorage OutLocalStorage::from_json(builder::StructuredSDFGBuilder& builder, const nlohmann::json& desc) {
×
UNCOV
223
    auto loop_id = desc["loop_element_id"].get<size_t>();
×
224
    std::string container = desc["container"].get<std::string>();
×
225
    auto element = builder.find_element_by_id(loop_id);
×
226
    if (!element) {
×
NEW
227
        throw InvalidTransformationDescriptionException("Element with ID " + std::to_string(loop_id) + " not found.");
×
228
    }
229
    auto loop = dynamic_cast<structured_control_flow::StructuredLoop*>(element);
×
230

231
    return OutLocalStorage(*loop, container);
×
232
};
×
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

© 2025 Coveralls, Inc