• 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

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

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

13
      };
×
14

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

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

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

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

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

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

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

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

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

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

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

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

74
        // We are left with private containers
75

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

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

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

108
    return true;
×
109
};
×
110

NEW
111
void LoopDistribute::apply(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
×
UNCOV
112
    auto& sdfg = builder.subject();
×
113

114
    auto indvar = this->loop_.indvar();
×
115
    auto condition = this->loop_.condition();
×
116
    auto update = this->loop_.update();
×
117
    auto init = this->loop_.init();
×
118

119
    auto& body = this->loop_.root();
×
120
    auto& block = body.at(0).first;
×
121

122
    // We might need to extend containers to loop dimension
123

124
    auto& users = analysis_manager.get<analysis::Users>();
×
125
    auto body_locals = users.locals(body);
×
126
    auto block_locals = users.locals(block);
×
127

128
    analysis::UsersView body_users(users, body);
×
129
    analysis::UsersView block_users(users, block);
×
130

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

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

144
        if (containers.find(container) == containers.end()) {
×
145
            continue;
×
146
        }
NEW
147
        if (dep_type == analysis::Parallelism::READONLY || dep_type == analysis::Parallelism::PARALLEL) {
×
148
            continue;
×
149
        }
150
        if (block_locals.find(container) != block_locals.end()) {
×
151
            continue;
×
152
        }
153

154
        shared_containers.insert(container);
×
155
    }
156

157
    if (!shared_containers.empty()) {
×
158
        auto bound = analysis::DataParallelismAnalysis::bound(this->loop_);
×
159
        for (auto& shared_container : shared_containers) {
×
160
            auto& type = sdfg.type(shared_container);
×
161

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

186
            // Make array
187
            builder.make_array(shared_container, bound);
×
188
        }
189
    }
×
190

191
    auto& scope_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
×
NEW
192
    auto parent = static_cast<structured_control_flow::Sequence*>(scope_analysis.parent_scope(&loop_));
×
193

194
    // Copy loop
NEW
195
    auto& new_loop = builder.add_for_before(*parent, this->loop_, indvar, condition, init, update).first;
×
196

197
    auto& new_body = new_loop.root();
×
198
    deepcopy::StructuredSDFGDeepCopy copies(builder, new_body, block);
×
199
    copies.copy();
×
200

201
    // Replace indvar in new loop
202
    std::string new_indvar = builder.find_new_name(indvar->get_name());
×
203
    builder.add_container(new_indvar, sdfg.type(indvar->get_name()));
×
204
    new_loop.replace(indvar, symbolic::symbol(new_indvar));
×
205

206
    // Remove block from loop
207
    builder.remove_child(body, block);
×
208

209
    analysis_manager.invalidate_all();
×
210
};
×
211

212
void LoopDistribute::to_json(nlohmann::json& j) const {
×
213
    j["transformation_type"] = this->name();
×
214
    j["loop_element_id"] = loop_.element_id();
×
215
};
×
216

NEW
217
LoopDistribute LoopDistribute::from_json(builder::StructuredSDFGBuilder& builder, const nlohmann::json& desc) {
×
UNCOV
218
    auto loop_id = desc["loop_element_id"].get<size_t>();
×
219
    auto element = builder.find_element_by_id(loop_id);
×
220
    if (!element) {
×
NEW
221
        throw InvalidTransformationDescriptionException("Element with ID " + std::to_string(loop_id) + " not found.");
×
222
    }
223
    auto loop = dynamic_cast<structured_control_flow::For*>(element);
×
224

225
    return LoopDistribute(*loop);
×
226
};
×
227

228
} // namespace transformations
229
} // 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