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

daisytuner / sdfglib / 15656007340

14 Jun 2025 08:51PM UTC coverage: 13.234% (-49.9%) from 63.144%
15656007340

Pull #76

github

web-flow
Merge 9586c8161 into 413c53212
Pull Request #76: New Loop Dependency Analysis

361 of 465 new or added lines in 7 files covered. (77.63%)

6215 existing lines in 110 files now uncovered.

1612 of 12181 relevant lines covered (13.23%)

13.64 hits per line

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

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

3
#include "sdfg/analysis/data_parallelism_analysis.h"
4
#include "sdfg/analysis/loop_analysis.h"
5
#include "sdfg/deepcopy/structured_sdfg_deep_copy.h"
6
#include "sdfg/structured_control_flow/structured_loop.h"
7

8
namespace sdfg {
9
namespace transformations {
10

11
enum class LoopSlicingType { Init, Bound, Split_Lt, Split_Le };
12

UNCOV
13
LoopSlicing::LoopSlicing(structured_control_flow::Sequence& parent,
×
14
                         structured_control_flow::StructuredLoop& loop)
UNCOV
15
    : parent_(parent), loop_(loop) {
×
16

UNCOV
17
      };
×
18

19
std::string LoopSlicing::name() { return "LoopSlicing"; };
×
20

UNCOV
21
bool LoopSlicing::can_be_applied(builder::StructuredSDFGBuilder& builder,
×
22
                                 analysis::AnalysisManager& analysis_manager) {
UNCOV
23
    auto& sdfg = builder.subject();
×
24

UNCOV
25
    auto& loop_analysis = analysis_manager.get<analysis::LoopAnalysis>();
×
UNCOV
26
    if (!loop_analysis.is_contiguous(&loop_)) {
×
27
        return false;
×
28
    }
29

30
    // Collect moving symbols
UNCOV
31
    std::unordered_set<std::string> moving_symbols;
×
UNCOV
32
    auto& all_users = analysis_manager.get<analysis::Users>();
×
UNCOV
33
    auto& body = loop_.root();
×
UNCOV
34
    analysis::UsersView users(all_users, body);
×
UNCOV
35
    for (auto& entry : users.writes()) {
×
36
        auto& type = sdfg.type(entry->container());
×
37
        if (!dynamic_cast<const types::Scalar*>(&type)) {
×
38
            continue;
×
39
        }
40
        if (!types::is_integer(type.primitive_type())) {
×
41
            continue;
×
42
        }
43
        moving_symbols.insert(entry->container());
×
44
    }
45

46
    // Check if loop is sliced by if-elses
UNCOV
47
    auto indvar = loop_.indvar();
×
UNCOV
48
    for (size_t i = 0; i < body.size(); i++) {
×
UNCOV
49
        auto child = body.at(i);
×
UNCOV
50
        if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
×
UNCOV
51
            if (child.second.assignments().size() > 0) {
×
52
                return false;
×
53
            }
UNCOV
54
            if (if_else->size() != 2) {
×
55
                return false;
×
56
            }
57

58
            // Validate condition
UNCOV
59
            auto branch_1 = if_else->at(0);
×
UNCOV
60
            auto condition_1 = branch_1.second;
×
UNCOV
61
            if (!symbolic::uses(condition_1, indvar)) {
×
62
                return false;
×
63
            }
UNCOV
64
            auto condition_2 = if_else->at(1).second;
×
UNCOV
65
            if (!symbolic::eq(condition_1, condition_2->logical_not())) {
×
66
                return false;
×
67
            }
UNCOV
68
            for (auto& atom : symbolic::atoms(condition_1)) {
×
UNCOV
69
                auto sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(atom);
×
UNCOV
70
                if (moving_symbols.find(sym->get_name()) != moving_symbols.end()) {
×
71
                    return false;
×
72
                }
UNCOV
73
            }
×
UNCOV
74
            auto bound = analysis::DataParallelismAnalysis::bound(loop_);
×
UNCOV
75
            if (bound == SymEngine::null) {
×
76
                return false;
×
77
            }
78

79
            // Case: indvar == init
UNCOV
80
            if (symbolic::eq(condition_1, symbolic::Eq(indvar, loop_.init()))) {
×
UNCOV
81
                return true;
×
82
            }
83

84
            // Case: indvar == bound - 1
85
            if (symbolic::eq(condition_1,
×
86
                             symbolic::Eq(indvar, symbolic::sub(bound, symbolic::one())))) {
×
87
                return true;
×
88
            }
89

90
            // Case: indvar < new_bound
91
            if (SymEngine::is_a<SymEngine::StrictLessThan>(*condition_1)) {
×
92
                return true;
×
93
            }
94

95
            // Case: indvar <= new_bound
96
            if (SymEngine::is_a<SymEngine::LessThan>(*condition_1)) {
×
97
                return true;
×
98
            }
99

100
            return false;
×
UNCOV
101
        }
×
102
    }
×
103

104
    return false;
×
UNCOV
105
};
×
106

UNCOV
107
void LoopSlicing::apply(builder::StructuredSDFGBuilder& builder,
×
108
                        analysis::AnalysisManager& analysis_manager) {
UNCOV
109
    auto& sdfg = builder.subject();
×
110

UNCOV
111
    auto& body = loop_.root();
×
UNCOV
112
    auto indvar = loop_.indvar();
×
113

114
    // Collect loop locals
UNCOV
115
    auto& users = analysis_manager.get<analysis::Users>();
×
UNCOV
116
    auto locals = users.locals(sdfg, body);
×
117

118
    // Find the if-else that slices the loop
UNCOV
119
    structured_control_flow::IfElse* if_else = nullptr;
×
UNCOV
120
    size_t if_else_index = 0;
×
UNCOV
121
    for (size_t i = 0; i < body.size(); i++) {
×
UNCOV
122
        auto child = body.at(i);
×
UNCOV
123
        auto if_else_ = dynamic_cast<structured_control_flow::IfElse*>(&child.first);
×
UNCOV
124
        if (if_else_) {
×
UNCOV
125
            if_else_index = i;
×
UNCOV
126
            if_else = if_else_;
×
UNCOV
127
            break;
×
128
        }
129
    }
×
UNCOV
130
    if (if_else == nullptr) {
×
131
        throw InvalidSDFGException("LoopSlicing: Expected IfElse");
×
132
    }
133

UNCOV
134
    auto branch_1 = if_else->at(0);
×
UNCOV
135
    auto condition_1 = branch_1.second;
×
UNCOV
136
    auto bound = analysis::DataParallelismAnalysis::bound(loop_);
×
137

UNCOV
138
    LoopSlicingType slice_type = LoopSlicingType::Init;
×
UNCOV
139
    if (symbolic::eq(condition_1, symbolic::Eq(indvar, loop_.init()))) {
×
UNCOV
140
        slice_type = LoopSlicingType::Init;
×
UNCOV
141
    } else if (symbolic::eq(condition_1,
×
142
                            symbolic::Eq(indvar, symbolic::sub(bound, symbolic::one())))) {
×
143
        slice_type = LoopSlicingType::Bound;
×
144
    } else if (SymEngine::is_a<SymEngine::StrictLessThan>(*condition_1)) {
×
145
        slice_type = LoopSlicingType::Split_Lt;
×
146
    } else if (SymEngine::is_a<SymEngine::LessThan>(*condition_1)) {
×
147
        slice_type = LoopSlicingType::Split_Le;
×
148
    }
×
149

150
    // Slice loop
UNCOV
151
    auto indvar_slice_str = builder.find_new_name(indvar->get_name());
×
UNCOV
152
    builder.add_container(indvar_slice_str, sdfg.type(indvar->get_name()));
×
UNCOV
153
    auto indvar_slice = SymEngine::symbol(indvar_slice_str);
×
UNCOV
154
    structured_control_flow::For* loop_slice = nullptr;
×
UNCOV
155
    structured_control_flow::For* loop_slice_2 = nullptr;
×
UNCOV
156
    switch (slice_type) {
×
157
        case LoopSlicingType::Init: {
UNCOV
158
            auto init_slice = loop_.init();
×
159
            auto condition_slice =
UNCOV
160
                symbolic::Lt(indvar_slice, symbolic::add(loop_.init(), symbolic::one()));
×
UNCOV
161
            auto increment_slice = symbolic::add(indvar_slice, symbolic::one());
×
UNCOV
162
            loop_slice = &builder
×
UNCOV
163
                              .add_for_before(parent_, loop_, indvar_slice, condition_slice,
×
164
                                              init_slice, increment_slice)
UNCOV
165
                              .first;
×
UNCOV
166
            loop_slice_2 =
×
UNCOV
167
                &builder
×
UNCOV
168
                     .add_for_after(parent_, loop_, loop_.indvar(), loop_.condition(),
×
UNCOV
169
                                    symbolic::add(loop_.init(), symbolic::one()), loop_.update())
×
UNCOV
170
                     .first;
×
171
            break;
UNCOV
172
        }
×
173
        case LoopSlicingType::Bound: {
174
            auto init_slice = symbolic::sub(bound, symbolic::one());
×
175
            auto condition_slice = symbolic::subs(loop_.condition(), loop_.indvar(), indvar_slice);
×
176
            auto increment_slice = symbolic::add(indvar_slice, symbolic::one());
×
177
            loop_slice = &builder
×
178
                              .add_for_after(parent_, loop_, indvar_slice, condition_slice,
×
179
                                             init_slice, increment_slice)
180
                              .first;
×
181
            loop_slice_2 = &builder
×
182
                                .add_for_before(
×
183
                                    parent_, loop_, loop_.indvar(),
×
184
                                    symbolic::Lt(loop_.indvar(),
×
185
                                                 symbolic::sub(loop_.condition(), symbolic::one())),
×
186
                                    loop_.init(), loop_.update())
×
187
                                .first;
×
188
            break;
189
        }
×
190
        case LoopSlicingType::Split_Lt: {
191
            auto init_slice = loop_.init();
×
192
            auto condition_slice =
193
                symbolic::And(symbolic::subs(condition_1, indvar, indvar_slice),
×
194
                              symbolic::subs(loop_.condition(), indvar, indvar_slice));
×
195
            auto increment_slice = symbolic::add(indvar_slice, symbolic::one());
×
196
            loop_slice = &builder
×
197
                              .add_for_before(parent_, loop_, indvar_slice, condition_slice,
×
198
                                              init_slice, increment_slice)
199
                              .first;
×
200

201
            auto condition_bound =
202
                SymEngine::rcp_static_cast<const SymEngine::StrictLessThan>(condition_1);
×
203
            auto condition_bound_args = condition_bound->get_args();
×
204
            auto condition_bound_args_bound = condition_bound_args.at(0);
×
205
            if (symbolic::eq(condition_bound_args_bound, loop_.indvar())) {
×
206
                condition_bound_args_bound = condition_bound_args.at(1);
×
207
            }
×
208

209
            loop_slice_2 = &builder
×
210
                                .add_for_after(parent_, loop_, loop_.indvar(), loop_.condition(),
×
211
                                               condition_bound_args_bound, loop_.update())
×
212
                                .first;
×
213
            break;
214
        }
×
215
        case LoopSlicingType::Split_Le: {
216
            auto init_slice = loop_.init();
×
217
            auto condition_slice =
218
                symbolic::And(symbolic::subs(condition_1, indvar, indvar_slice),
×
219
                              symbolic::subs(loop_.condition(), indvar, indvar_slice));
×
220
            auto increment_slice = symbolic::add(indvar_slice, symbolic::one());
×
221
            loop_slice = &builder
×
222
                              .add_for_before(parent_, loop_, indvar_slice, condition_slice,
×
223
                                              init_slice, increment_slice)
224
                              .first;
×
225

226
            auto condition_bound =
227
                SymEngine::rcp_static_cast<const SymEngine::StrictLessThan>(condition_1);
×
228
            auto condition_bound_args = condition_bound->get_args();
×
229
            auto condition_bound_args_bound = condition_bound_args.at(0);
×
230
            if (symbolic::eq(condition_bound_args_bound, loop_.indvar())) {
×
231
                condition_bound_args_bound = condition_bound_args.at(1);
×
232
            }
×
233

234
            loop_slice_2 =
×
235
                &builder
×
236
                     .add_for_after(parent_, loop_, loop_.indvar(), loop_.condition(),
×
237
                                    symbolic::add(condition_bound_args_bound, symbolic::one()),
×
238
                                    loop_.update())
×
239
                     .first;
×
240
            break;
241
        }
×
242
    }
243

244
    // Move loop locals to the new loop slice
UNCOV
245
    auto& body_slice = loop_slice->root();
×
246

UNCOV
247
    deepcopy::StructuredSDFGDeepCopy deep_copy(builder, body_slice, body);
×
UNCOV
248
    deep_copy.copy();
×
UNCOV
249
    auto& body_body_slice =
×
UNCOV
250
        dynamic_cast<structured_control_flow::Sequence&>(body_slice.at(0).first);
×
251

UNCOV
252
    auto& if_else_slice =
×
UNCOV
253
        dynamic_cast<structured_control_flow::IfElse&>(body_body_slice.at(if_else_index).first);
×
UNCOV
254
    auto& slice = builder.add_sequence_before(body_body_slice, if_else_slice).first;
×
255

UNCOV
256
    deepcopy::StructuredSDFGDeepCopy deep_copy_slice(builder, slice, if_else_slice.at(0).first);
×
UNCOV
257
    deep_copy_slice.copy();
×
258

UNCOV
259
    builder.remove_child(body_body_slice, if_else_index + 1);
×
260

UNCOV
261
    body_body_slice.replace(indvar, indvar_slice);
×
262

263
    // Update remaining loop
UNCOV
264
    builder.remove_case(*if_else, 0);
×
265

UNCOV
266
    auto& else_slice = builder.add_sequence_before(body, *if_else).first;
×
UNCOV
267
    deepcopy::StructuredSDFGDeepCopy deep_copy_else(builder, else_slice, if_else->at(0).first);
×
UNCOV
268
    deep_copy_else.copy();
×
269

UNCOV
270
    builder.remove_child(body, if_else_index + 1);
×
271

272
    // Rename all loop-local variables to break artificial dependencies
UNCOV
273
    for (auto& local : locals) {
×
274
        auto new_local = builder.find_new_name(local);
×
275
        builder.add_container(new_local, sdfg.type(local));
×
276
        loop_slice->root().replace(symbolic::symbol(local), symbolic::symbol(new_local));
×
277
    }
×
278

279
    // Move loop locals to the new loop
UNCOV
280
    builder.insert_children(loop_slice_2->root(), loop_.root(), 0);
×
UNCOV
281
    builder.remove_child(parent_, loop_);
×
282

UNCOV
283
    analysis_manager.invalidate_all();
×
UNCOV
284
};
×
285

286
}  // namespace transformations
287
}  // 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