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

daisytuner / sdfglib / 15731283590

18 Jun 2025 11:12AM UTC coverage: 64.351% (-0.2%) from 64.576%
15731283590

Pull #86

github

web-flow
Merge 99df43790 into 32b5d7ae4
Pull Request #86: Add optimizer functionality

144 of 227 new or added lines in 9 files covered. (63.44%)

453 existing lines in 14 files now uncovered.

8125 of 12626 relevant lines covered (64.35%)

153.57 hits per line

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

0.0
/src/transformations/loop_distribute.cpp
1
#include "sdfg/transformations/loop_distribute.h"
2

3
#include "sdfg/analysis/data_parallelism_analysis.h"
4
#include "sdfg/analysis/scope_analysis.h"
5
#include "sdfg/deepcopy/structured_sdfg_deep_copy.h"
6

7
namespace sdfg {
8
namespace transformations {
9

NEW
10
LoopDistribute::LoopDistribute(structured_control_flow::StructuredLoop& loop)
×
NEW
11
    : loop_(loop) {
×
12

13
      };
×
14

NEW
15
std::string LoopDistribute::name() const { return "LoopDistribute"; };
×
16

17
bool LoopDistribute::can_be_applied(builder::StructuredSDFGBuilder& builder,
×
18
                                    analysis::AnalysisManager& analysis_manager) {
19
    auto indvar = this->loop_.indvar();
×
20

21
    // Criterion: Block -> Loop
UNCOV
22
    auto& body = this->loop_.root();
×
23
    if (body.size() < 2) {
×
24
        return false;
×
25
    }
UNCOV
26
    auto& block = body.at(0).first;
×
27
    if (!body.at(0).second.assignments().empty()) {
×
28
        return false;
×
29
    }
30

UNCOV
31
    auto& users = analysis_manager.get<analysis::Users>();
×
32

33
    // Determine block-related containers
UNCOV
34
    std::unordered_set<std::string> containers;
×
35
    analysis::UsersView block_users(users, block);
×
36
    for (auto& user : block_users.uses()) {
×
37
        containers.insert(user->container());
×
38
    }
39

40
    // Criterion: loop is data-parallel w.r.t containers
UNCOV
41
    auto& analysis = analysis_manager.get<analysis::DataParallelismAnalysis>();
×
42
    auto& dependencies = analysis.get(loop_);
×
43
    if (dependencies.size() == 0) {
×
44
        return false;
×
45
    }
46

47
    // Determine body- and block-local variables
UNCOV
48
    auto body_locals = users.locals(body);
×
49
    auto block_locals = users.locals(block);
×
50

51
    analysis::UsersView body_users(users, body);
×
52

53
    // Check if all dependencies can be resolved
UNCOV
54
    bool can_be_distributed = true;
×
55
    for (auto& dep : dependencies) {
×
56
        auto& container = dep.first;
×
57
        auto& dep_type = dep.second;
×
58

59
        // Criterion: If container not used in block, ignore
UNCOV
60
        if (containers.find(container) == containers.end()) {
×
61
            continue;
×
62
        }
63

64
        // Criterion: Containers must be parallel
UNCOV
65
        if (dep_type < analysis::Parallelism::PARALLEL) {
×
66
            can_be_distributed = false;
×
67
            break;
×
68
        }
69

70
        // Criterion: Readonly and parallel containers -> no action
UNCOV
71
        if (dep_type == analysis::Parallelism::READONLY ||
×
72
            dep_type == analysis::Parallelism::PARALLEL) {
×
73
            continue;
×
74
        }
75

76
        // We are left with private containers
77

78
        // Criterion: If container is only used inside block, no action
UNCOV
79
        if (block_locals.find(container) != block_locals.end()) {
×
80
            continue;
×
81
        }
82
        // Criterion: If container is used outside the loop, we fail
UNCOV
83
        if (body_locals.find(container) == body_locals.end()) {
×
84
            can_be_distributed = false;
×
85
            break;
×
86
        }
87

88
        // Criterion: Container must only be used as access node
UNCOV
89
        for (auto& user : body_users.uses(container)) {
×
90
            if (dynamic_cast<data_flow::AccessNode*>(user->element()) == nullptr) {
×
91
                can_be_distributed = false;
×
92
                break;
×
93
            }
94
        }
UNCOV
95
        if (!can_be_distributed) {
×
96
            break;
×
97
        }
98

99
        // Criterion: Bound must be integer
UNCOV
100
        auto bound = analysis::DataParallelismAnalysis::bound(this->loop_);
×
101
        if (bound == SymEngine::null || !SymEngine::is_a<SymEngine::Integer>(*bound)) {
×
102
            can_be_distributed = false;
×
103
            break;
×
104
        }
UNCOV
105
    }
×
106
    if (!can_be_distributed) {
×
107
        return false;
×
108
    }
109

UNCOV
110
    return true;
×
111
};
×
112

UNCOV
113
void LoopDistribute::apply(builder::StructuredSDFGBuilder& builder,
×
114
                           analysis::AnalysisManager& analysis_manager) {
UNCOV
115
    auto& sdfg = builder.subject();
×
116

UNCOV
117
    auto indvar = this->loop_.indvar();
×
118
    auto condition = this->loop_.condition();
×
119
    auto update = this->loop_.update();
×
120
    auto init = this->loop_.init();
×
121

UNCOV
122
    auto& body = this->loop_.root();
×
123
    auto& block = body.at(0).first;
×
124

125
    // We might need to extend containers to loop dimension
126

UNCOV
127
    auto& users = analysis_manager.get<analysis::Users>();
×
128
    auto body_locals = users.locals(body);
×
129
    auto block_locals = users.locals(block);
×
130

131
    analysis::UsersView body_users(users, body);
×
132
    analysis::UsersView block_users(users, block);
×
133

134
    // Determine block-related containers
UNCOV
135
    std::unordered_set<std::string> containers;
×
UNCOV
136
    for (auto& user : block_users.uses()) {
×
137
        containers.insert(user->container());
×
138
    }
139

UNCOV
140
    std::unordered_set<std::string> shared_containers;
×
UNCOV
141
    auto& analysis = analysis_manager.get<analysis::DataParallelismAnalysis>();
×
142
    auto& dependencies = analysis.get(loop_);
×
143
    for (auto& dep : dependencies) {
×
144
        auto& container = dep.first;
×
145
        auto& dep_type = dep.second;
×
146

147
        if (containers.find(container) == containers.end()) {
×
UNCOV
148
            continue;
×
149
        }
150
        if (dep_type == analysis::Parallelism::READONLY ||
×
UNCOV
151
            dep_type == analysis::Parallelism::PARALLEL) {
×
152
            continue;
×
153
        }
154
        if (block_locals.find(container) != block_locals.end()) {
×
UNCOV
155
            continue;
×
156
        }
157

UNCOV
158
        shared_containers.insert(container);
×
159
    }
160

UNCOV
161
    if (!shared_containers.empty()) {
×
UNCOV
162
        auto bound = analysis::DataParallelismAnalysis::bound(this->loop_);
×
163
        for (auto& shared_container : shared_containers) {
×
164
            auto& type = sdfg.type(shared_container);
×
165

166
            // Add loop dimension to subset
UNCOV
167
            for (auto& user : body_users.uses(shared_container)) {
×
UNCOV
168
                auto& access_node = static_cast<data_flow::AccessNode&>(*user->element());
×
169
                auto& graph = access_node.get_parent();
×
170
                for (auto& edge : graph.in_edges(access_node)) {
×
171
                    data_flow::Subset new_subset = {indvar};
×
172
                    if (!dynamic_cast<const types::Scalar*>(&type)) {
×
173
                        for (auto& dim : edge.subset()) {
×
174
                            new_subset.push_back(dim);
×
175
                        }
176
                    }
×
UNCOV
177
                    edge.subset() = new_subset;
×
178
                }
×
179
                for (auto& edge : graph.out_edges(access_node)) {
×
180
                    data_flow::Subset new_subset = {indvar};
×
181
                    if (!dynamic_cast<const types::Scalar*>(&type)) {
×
182
                        for (auto& dim : edge.subset()) {
×
183
                            new_subset.push_back(dim);
×
184
                        }
185
                    }
×
UNCOV
186
                    edge.subset() = new_subset;
×
187
                }
×
188
            }
189

190
            // Make array
UNCOV
191
            builder.make_array(shared_container, bound);
×
192
        }
193
    }
×
194

195
    auto& scope_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
×
UNCOV
196
    auto parent =
×
NEW
197
        static_cast<structured_control_flow::Sequence*>(scope_analysis.parent_scope(&loop_));
×
198

199
    // Copy loop
NEW
200
    auto& new_loop =
×
201
        builder.add_for_before(*parent, this->loop_, indvar, condition, init, update).first;
×
202

NEW
203
    auto& new_body = new_loop.root();
×
UNCOV
204
    deepcopy::StructuredSDFGDeepCopy copies(builder, new_body, block);
×
205
    copies.copy();
×
206

207
    // Replace indvar in new loop
UNCOV
208
    std::string new_indvar = builder.find_new_name(indvar->get_name());
×
UNCOV
209
    builder.add_container(new_indvar, sdfg.type(indvar->get_name()));
×
210
    new_loop.replace(indvar, symbolic::symbol(new_indvar));
×
211

212
    // Remove block from loop
UNCOV
213
    builder.remove_child(body, block);
×
214

215
    analysis_manager.invalidate_all();
×
UNCOV
216
};
×
217

218
void LoopDistribute::to_json(nlohmann::json& j) const {
×
UNCOV
219
    std::cout << "Serializing LoopTiling transformation to JSON" << std::endl;
×
NEW
220
    std::cout << "Writing transformation type: " << this->name() << std::endl;
×
NEW
221
    j["transformation_type"] = this->name();
×
NEW
222
    std::cout << "Writing loop element ID " << std::endl;
×
NEW
223
    j["loop_element_id"] = loop_.element_id();
×
NEW
224
};
×
225

NEW
226
LoopDistribute LoopDistribute::from_json(builder::StructuredSDFGBuilder& builder,
×
227
                                         const nlohmann::json& desc) {
NEW
228
    auto loop_id = desc["loop_element_id"].get<size_t>();
×
NEW
229
    auto element = builder.find_element_by_id(loop_id);
×
NEW
230
    if (!element) {
×
NEW
231
        throw InvalidTransformationDescriptionException("Element with ID " +
×
NEW
232
                                                        std::to_string(loop_id) + " not found.");
×
233
    }
NEW
234
    auto loop = dynamic_cast<structured_control_flow::For*>(element);
×
235

NEW
236
    return LoopDistribute(*loop);
×
NEW
237
};
×
238

239
}  // namespace transformations
240
}  // 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