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

daisytuner / sdfglib / 15512392058

07 Jun 2025 10:47PM UTC coverage: 62.261% (+4.8%) from 57.416%
15512392058

push

github

web-flow
Merge pull request #63 from daisytuner/schedules

Schedules

152 of 194 new or added lines in 24 files covered. (78.35%)

39 existing lines in 7 files now uncovered.

7467 of 11993 relevant lines covered (62.26%)

127.08 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/deepcopy/structured_sdfg_deep_copy.h"
5

6
namespace sdfg {
7
namespace transformations {
8

9
LoopDistribute::LoopDistribute(structured_control_flow::Sequence& parent,
×
10
                               structured_control_flow::StructuredLoop& loop)
11
    : parent_(parent), loop_(loop) {
×
12

13
      };
×
14

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

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

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

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

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

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

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

51
    analysis::UsersView body_users(users, body);
×
52
    auto block_locals = body_users.locals(sdfg, block);
×
53

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

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

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

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

77
        // We are left with private containers
78

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

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

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

111
    return true;
×
112
};
×
113

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

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

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

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

128
    auto& users = analysis_manager.get<analysis::Users>();
×
129
    auto body_locals = users.locals(sdfg, body);
×
130

131
    analysis::UsersView body_users(users, body);
×
132
    auto block_locals = body_users.locals(sdfg, block);
×
133

134
    analysis::UsersView block_users(users, block);
×
135

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

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

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

160
        shared_containers.insert(container);
×
161
    }
162

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

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

192
            // Make array
193
            builder.make_array(shared_container, bound);
×
194
        }
195
    }
×
196

197
    // Copy loop
198
    auto& new_loop =
×
199
        builder.add_for_before(parent_, this->loop_, indvar, condition, init, update).first;
×
200

201
    auto& new_body = new_loop.root();
×
202
    deepcopy::StructuredSDFGDeepCopy copies(builder, new_body, block);
×
203
    copies.copy();
×
204

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

210
    // Remove block from loop
211
    builder.remove_child(body, block);
×
212

213
    analysis_manager.invalidate_all();
×
214
};
×
215

216
}  // namespace transformations
217
}  // 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