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

daisytuner / sdfglib / 15087157738

17 May 2025 04:45PM UTC coverage: 63.608% (-0.02%) from 63.623%
15087157738

push

github

web-flow
Merge pull request #17 from daisytuner/hash-boost

use boost hash function for maps

8631 of 13569 relevant lines covered (63.61%)

483.09 hits per line

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

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

3
namespace sdfg {
4
namespace transformations {
5

6
LoopDistribute::LoopDistribute(structured_control_flow::Sequence& parent,
106✔
7
                               structured_control_flow::For& loop)
8
    : parent_(parent), loop_(loop) {
106✔
9

10
      };
106✔
11

12
std::string LoopDistribute::name() { return "LoopDistribute"; };
×
13

14
bool LoopDistribute::can_be_applied(Schedule& schedule) {
60✔
15
    auto& builder = schedule.builder();
60✔
16
    auto& sdfg = builder.subject();
60✔
17
    auto indvar = this->loop_.indvar();
60✔
18

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

29
    auto& analysis_manager = schedule.analysis_manager();
60✔
30
    auto& users = analysis_manager.get<analysis::Users>();
60✔
31

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

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

46
    // Determine body- and block-local variables
47
    auto body_locals = users.locals(sdfg, body);
60✔
48

49
    analysis::UsersView body_users(users, body);
60✔
50
    auto block_locals = body_users.locals(sdfg, block);
60✔
51

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

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

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

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

75
        // We are left with private containers
76

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

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

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

109
    return true;
46✔
110
};
60✔
111

112
void LoopDistribute::apply(Schedule& schedule) {
46✔
113
    auto& builder = schedule.builder();
46✔
114
    auto& sdfg = builder.subject();
46✔
115

116
    auto indvar = this->loop_.indvar();
46✔
117
    auto condition = this->loop_.condition();
46✔
118
    auto update = this->loop_.update();
46✔
119
    auto init = this->loop_.init();
46✔
120

121
    auto& body = this->loop_.root();
46✔
122
    auto& block = body.at(0).first;
46✔
123

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

126
    auto& analysis_manager = schedule.analysis_manager();
46✔
127
    auto& users = analysis_manager.get<analysis::Users>();
46✔
128
    auto body_locals = users.locals(sdfg, body);
46✔
129

130
    analysis::UsersView body_users(users, body);
46✔
131
    auto block_locals = body_users.locals(sdfg, block);
46✔
132

133
    analysis::UsersView block_users(users, block);
46✔
134

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

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

148
        if (containers.find(container) == containers.end()) {
346✔
149
            continue;
184✔
150
        }
151
        if (dep_type == analysis::Parallelism::READONLY ||
162✔
152
            dep_type == analysis::Parallelism::PARALLEL) {
96✔
153
            continue;
110✔
154
        }
155
        if (block_locals.find(container) != block_locals.end()) {
52✔
156
            continue;
48✔
157
        }
158

159
        shared_containers.insert(container);
4✔
160
    }
161

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

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

191
            // Make array
192
            builder.make_array(shared_container, bound);
4✔
193
        }
194
    }
4✔
195

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

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

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

209
    // Remove block from loop
210
    builder.remove_child(body, block);
46✔
211

212
    analysis_manager.invalidate_all();
46✔
213
};
46✔
214

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