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

daisytuner / sdfglib / 21096957773

17 Jan 2026 03:52PM UTC coverage: 64.681% (-0.05%) from 64.728%
21096957773

Pull #459

github

web-flow
Merge e45cad2bb into b09ddf4fd
Pull Request #459: Adds OMPScheduler and PollyScheduler

144 of 253 new or added lines in 11 files covered. (56.92%)

42 existing lines in 1 file now uncovered.

19147 of 29602 relevant lines covered (64.68%)

393.62 hits per line

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

50.0
/opt/src/transformations/polly_transform.cpp
1
//===- ScheduleOptimizer.cpp - Calculate an optimized schedule ------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This pass generates an entirely new schedule tree from the data dependences
10
// and iteration domains. The new schedule tree is computed in two steps:
11
//
12
// 1) The isl scheduling optimizer is run
13
//
14
// The isl scheduling optimizer creates a new schedule tree that maximizes
15
// parallelism and tileability and minimizes data-dependence distances. The
16
// algorithm used is a modified version of the ``Pluto'' algorithm:
17
//
18
//   U. Bondhugula, A. Hartono, J. Ramanujam, and P. Sadayappan.
19
//   A Practical Automatic Polyhedral Parallelizer and Locality Optimizer.
20
//   In Proceedings of the 2008 ACM SIGPLAN Conference On Programming Language
21
//   Design and Implementation, PLDI ’08, pages 101–113. ACM, 2008.
22
//
23
// 2) A set of post-scheduling transformations is applied on the schedule tree.
24
//
25
// These optimizations include:
26
//
27
//  - Tiling of the innermost tilable bands
28
//  - Prevectorization - The choice of a possible outer loop that is strip-mined
29
//                       to the innermost level to enable inner-loop
30
//                       vectorization.
31
//  - Some optimizations for spatial locality are also planned.
32
//
33
// For a detailed description of the schedule tree itself please see section 6
34
// of:
35
//
36
// Polyhedral AST generation is more than scanning polyhedra
37
// Tobias Grosser, Sven Verdoolaege, Albert Cohen
38
// ACM Transactions on Programming Languages and Systems (TOPLAS),
39
// 37(4), July 2015
40
// http://www.grosser.es/#pub-polyhedral-AST-generation
41
//
42
// This publication also contains a detailed discussion of the different options
43
// for polyhedral loop unrolling, full/partial tile separation and other uses
44
// of the schedule tree.
45
//
46
//===----------------------------------------------------------------------===//
47
//
48
// This file is based on the original source files which were modified for sdfglib.
49
//
50
//===----------------------------------------------------------------------===//
51
#include "sdfg/transformations/polly_transform.h"
52

53
#include <isl/constraint.h>
54
#include <isl/id.h>
55
#include <isl/map.h>
56
#include <isl/schedule_node.h>
57
#include <isl/space.h>
58
#include <isl/union_map.h>
59
#include <isl/union_set.h>
60
#include <isl/val.h>
61

62
namespace sdfg {
63
namespace transformations {
64

NEW
65
static bool isSimpleInnermostBand(isl_schedule_node* node) {
×
NEW
66
    assert(isl_schedule_node_get_type(node) == isl_schedule_node_band);
×
NEW
67
    assert(isl_schedule_node_n_children(node) == 1);
×
68

NEW
69
    isl_schedule_node* child = isl_schedule_node_get_child(node, 0);
×
NEW
70
    enum isl_schedule_node_type child_type = isl_schedule_node_get_type(child);
×
71

NEW
72
    if (child_type == isl_schedule_node_leaf) {
×
NEW
73
        isl_schedule_node_free(child);
×
NEW
74
        return true;
×
NEW
75
    }
×
76

NEW
77
    if (child_type != isl_schedule_node_sequence) {
×
NEW
78
        isl_schedule_node_free(child);
×
NEW
79
        return false;
×
NEW
80
    }
×
81

NEW
82
    int nc = isl_schedule_node_n_children(child);
×
NEW
83
    for (int c = 0; c < nc; ++c) {
×
NEW
84
        isl_schedule_node* seq_child = isl_schedule_node_get_child(child, c);
×
NEW
85
        if (isl_schedule_node_get_type(seq_child) != isl_schedule_node_filter) {
×
NEW
86
            isl_schedule_node_free(seq_child);
×
NEW
87
            isl_schedule_node_free(child);
×
NEW
88
            return false;
×
NEW
89
        }
×
90

NEW
91
        isl_schedule_node* filter_child = isl_schedule_node_get_child(seq_child, 0);
×
NEW
92
        bool is_leaf = (isl_schedule_node_get_type(filter_child) == isl_schedule_node_leaf);
×
NEW
93
        isl_schedule_node_free(filter_child);
×
NEW
94
        isl_schedule_node_free(seq_child);
×
95

NEW
96
        if (!is_leaf) {
×
NEW
97
            isl_schedule_node_free(child);
×
NEW
98
            return false;
×
NEW
99
        }
×
NEW
100
    }
×
101

NEW
102
    isl_schedule_node_free(child);
×
NEW
103
    return true;
×
NEW
104
}
×
105

NEW
106
static bool isOneTimeParentBandNode(isl_schedule_node* node) {
×
NEW
107
    if (isl_schedule_node_get_type(node) != isl_schedule_node_band) return false;
×
108

NEW
109
    if (isl_schedule_node_n_children(node) != 1) return false;
×
110

NEW
111
    return true;
×
NEW
112
}
×
113

NEW
114
static bool isTileableBandNode(isl_schedule_node* node) {
×
NEW
115
    if (!isOneTimeParentBandNode(node)) return false;
×
116

NEW
117
    if (!isl_schedule_node_band_get_permutable(node)) return false;
×
118

NEW
119
    isl_space* space = isl_schedule_node_band_get_space(node);
×
NEW
120
    int dim = isl_space_dim(space, isl_dim_set);
×
NEW
121
    isl_space_free(space);
×
122

NEW
123
    if (dim <= 1) return false;
×
124

NEW
125
    return isSimpleInnermostBand(node);
×
NEW
126
}
×
127

NEW
128
static isl_schedule_node* tile_node(isl_ctx* ctx, isl_schedule_node* node, const char* identifier, int default_tile_size) {
×
NEW
129
    isl_space* space = isl_schedule_node_band_get_space(node);
×
NEW
130
    int dims = isl_space_dim(space, isl_dim_set);
×
131

NEW
132
    isl_multi_val* sizes = isl_multi_val_zero(space);
×
NEW
133
    std::string identifierString(identifier);
×
NEW
134
    for (int i = 0; i < dims; ++i) {
×
NEW
135
        sizes = isl_multi_val_set_val(sizes, i, isl_val_int_from_si(ctx, default_tile_size));
×
NEW
136
    }
×
137

NEW
138
    std::string tileLoopMarkerStr = identifierString + " - Tiles";
×
NEW
139
    isl_id* tileLoopMarker = isl_id_alloc(ctx, tileLoopMarkerStr.c_str(), nullptr);
×
NEW
140
    node = isl_schedule_node_insert_mark(node, tileLoopMarker);
×
NEW
141
    node = isl_schedule_node_child(node, 0);
×
NEW
142
    node = isl_schedule_node_band_tile(node, sizes);
×
NEW
143
    node = isl_schedule_node_child(node, 0);
×
144

NEW
145
    std::string pointLoopMarkerStr = identifierString + " - Points";
×
NEW
146
    isl_id* pointLoopMarker = isl_id_alloc(ctx, pointLoopMarkerStr.c_str(), nullptr);
×
147

NEW
148
    node = isl_schedule_node_insert_mark(node, pointLoopMarker);
×
NEW
149
    return isl_schedule_node_child(node, 0);
×
NEW
150
}
×
151

NEW
152
static isl_schedule_node* optimize_band(isl_schedule_node* node, void* User) {
×
NEW
153
    if (!isTileableBandNode(node)) {
×
NEW
154
        return node;
×
NEW
155
    }
×
156

NEW
157
    isl_ctx* ctx = isl_schedule_node_get_ctx(node);
×
158
    // First level tiling
NEW
159
    node = tile_node(ctx, node, "1st level tiling", 32);
×
160

161
    // Second level tiling
NEW
162
    node = tile_node(ctx, node, "2nd level tiling", 16);
×
163

NEW
164
    return node;
×
NEW
165
}
×
166

167
PollyTransform::PollyTransform(structured_control_flow::StructuredLoop& loop, bool tile)
168
    : loop_(loop), tile_(tile), scop_(nullptr), dependences_(nullptr) {};
7✔
169

170
std::string PollyTransform::name() const { return "PollyTransform"; };
2✔
171

172
bool PollyTransform::can_be_applied(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
5✔
173
    analysis::ScopBuilder scop_builder(builder.subject(), loop_);
5✔
174
    this->scop_ = scop_builder.build(analysis_manager);
5✔
175
    if (!this->scop_) {
5✔
176
        return false;
×
177
    }
×
178
    this->dependences_ = std::make_unique<analysis::Dependences>(*this->scop_);
5✔
179
    if (!this->dependences_->has_valid_dependences()) {
5✔
180
        this->dependences_ = nullptr;
×
181
        this->scop_ = nullptr;
×
182
        return false;
×
183
    }
×
184

185
    return true;
5✔
186
};
5✔
187

188
void PollyTransform::apply(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
5✔
189
    assert(
5✔
190
        this->scop_ != nullptr && this->dependences_ != nullptr &&
5✔
191
        "PollyTransform::apply called without successful can_be_applied"
5✔
192
    );
5✔
193

194
    int validity_kinds = analysis::Dependences::TYPE_RAW | analysis::Dependences::TYPE_WAR |
5✔
195
                         analysis::Dependences::TYPE_WAW;
5✔
196
    int proximity_kinds = analysis::Dependences::TYPE_RAW | analysis::Dependences::TYPE_WAR |
5✔
197
                          analysis::Dependences::TYPE_WAW;
5✔
198
    isl_union_map* validity = this->dependences_->dependences(validity_kinds);
5✔
199
    isl_union_map* proximity = this->dependences_->dependences(proximity_kinds);
5✔
200

201
    isl_union_set* domain = this->scop_->domains();
5✔
202
    validity = isl_union_map_gist_domain(validity, isl_union_set_copy(domain));
5✔
203
    validity = isl_union_map_gist_range(validity, isl_union_set_copy(domain));
5✔
204
    proximity = isl_union_map_gist_domain(proximity, isl_union_set_copy(domain));
5✔
205
    proximity = isl_union_map_gist_range(proximity, isl_union_set_copy(domain));
5✔
206

207
    // Add spatial proximity
208
    isl_union_map* spatial_proximity = isl_union_map_empty(isl_union_map_get_space(proximity));
5✔
209

210
    for (auto* stmt : this->scop_->statements()) {
5✔
211
        for (auto* access : stmt->accesses()) {
10✔
212
            isl_map* rel = access->relation();
10✔
213
            if (isl_map_dim(rel, isl_dim_out) == 0) {
10✔
214
                continue;
×
215
            }
×
216

217
            // We create a map that maps each element to the next element in the last dimension
218
            isl_space* array_space = isl_space_range(isl_map_get_space(rel));
10✔
219
            isl_map* adj = isl_map_universe(isl_space_map_from_set(isl_space_copy(array_space)));
10✔
220

221
            int n_dim = isl_map_dim(adj, isl_dim_out);
10✔
222
            for (int i = 0; i < n_dim - 1; ++i) {
18✔
223
                adj = isl_map_equate(adj, isl_dim_in, i, isl_dim_out, i);
8✔
224
            }
8✔
225

226
            isl_local_space* ls = isl_local_space_from_space(isl_map_get_space(adj));
10✔
227
            isl_constraint* c = isl_equality_alloc(ls);
10✔
228
            c = isl_constraint_set_coefficient_si(c, isl_dim_out, n_dim - 1, 1);
10✔
229
            c = isl_constraint_set_coefficient_si(c, isl_dim_in, n_dim - 1, -1);
10✔
230
            c = isl_constraint_set_constant_si(c, -1);
10✔
231
            adj = isl_map_add_constraint(adj, c);
10✔
232

233
            // S -> Array
234
            isl_map* rel_map = isl_map_copy(rel);
10✔
235
            // S_next -> Array_next = Array + 1
236
            // We want S -> S_next such that Acc(S_next) = Acc(S) + 1
237
            // S -> Acc(S) -> Acc(S)+1 -> S_next
238
            // Proximity = Rel . Adj . Rel^-1
239

240
            isl_map* map = isl_map_apply_range(rel_map, adj);
10✔
241
            map = isl_map_apply_range(map, isl_map_reverse(isl_map_copy(rel)));
10✔
242

243
            spatial_proximity = isl_union_map_add_map(spatial_proximity, map);
10✔
244

245
            isl_space_free(array_space);
10✔
246
        }
10✔
247
    }
5✔
248

249
    proximity = isl_union_map_union(proximity, spatial_proximity);
5✔
250

251
    int isl_maximize_bands = 1;
5✔
252
    int isl_outer_coincidence = 0;
5✔
253

254
    isl_options_set_schedule_outer_coincidence(scop_->ctx(), isl_outer_coincidence);
5✔
255
    isl_options_set_schedule_maximize_band_depth(scop_->ctx(), isl_maximize_bands);
5✔
256
    isl_options_set_schedule_max_constant_term(scop_->ctx(), 20);
5✔
257
    isl_options_set_schedule_max_coefficient(scop_->ctx(), 20);
5✔
258
    isl_options_set_tile_scale_tile_loops(scop_->ctx(), 0);
5✔
259

260
    isl_schedule_constraints* SC = isl_schedule_constraints_on_domain(isl_union_set_copy(domain));
5✔
261
    SC = isl_schedule_constraints_set_proximity(SC, isl_union_map_copy(proximity));
5✔
262
    SC = isl_schedule_constraints_set_validity(SC, isl_union_map_copy(validity));
5✔
263
    SC = isl_schedule_constraints_set_coincidence(SC, isl_union_map_copy(validity));
5✔
264
    isl_schedule* S = isl_schedule_constraints_compute_schedule(SC);
5✔
265

266
    if (this->tile_) {
5✔
NEW
267
        isl_schedule_node* root = isl_schedule_get_root(S);
×
NEW
268
        root = isl_schedule_node_map_descendant_bottom_up(root, optimize_band, nullptr);
×
NEW
269
        isl_schedule_free(S);
×
270

NEW
271
        S = isl_schedule_node_get_schedule(root);
×
NEW
272
        isl_schedule_node_free(root);
×
NEW
273
    }
×
274

275
    scop_->set_schedule_tree(S);
5✔
276

277
    isl_union_map_free(validity);
5✔
278
    isl_union_map_free(proximity);
5✔
279
    isl_union_set_free(domain);
5✔
280

281
    DEBUG_PRINTLN("PollyTransform:" << std::endl << scop_->ast());
5✔
282

283
    auto& sdfg = builder.subject();
5✔
284
    analysis::ScopToSDFG converter(*scop_, *dependences_, builder);
5✔
285
    converter.build(analysis_manager);
5✔
286

287
    this->applied_ = true;
5✔
288
    this->dependences_ = nullptr;
5✔
289
    this->scop_ = nullptr;
5✔
290
};
5✔
291

292
void PollyTransform::to_json(nlohmann::json& j) const {
1✔
293
    std::string loop_type;
1✔
294
    if (dynamic_cast<structured_control_flow::For*>(&loop_)) {
1✔
295
        loop_type = "for";
×
296
    } else if (dynamic_cast<structured_control_flow::Map*>(&loop_)) {
1✔
297
        loop_type = "map";
1✔
298
    } else {
1✔
299
        throw InvalidSDFGException("Unsupported loop type for serialization of loop: " + loop_.indvar()->get_name());
×
300
    }
×
301

302
    j["transformation_type"] = this->name();
1✔
303
    j["subgraph"] = {{"0", {{"element_id", this->loop_.element_id()}, {"type", loop_type}}}};
1✔
304
    j["parameters"] = {{"tile", this->tile_}};
1✔
305
};
1✔
306

307
PollyTransform PollyTransform::from_json(builder::StructuredSDFGBuilder& builder, const nlohmann::json& desc) {
1✔
308
    auto loop_id = desc["subgraph"]["0"]["element_id"].get<size_t>();
1✔
309
    auto element = builder.find_element_by_id(loop_id);
1✔
310
    if (!element) {
1✔
311
        throw InvalidTransformationDescriptionException("Element with ID " + std::to_string(loop_id) + " not found.");
×
312
    }
×
313
    auto loop = dynamic_cast<structured_control_flow::StructuredLoop*>(element);
1✔
314
    bool tile = desc["parameters"]["tile"].get<bool>();
1✔
315

316
    return PollyTransform(*loop, tile);
1✔
317
};
1✔
318

319
} // namespace transformations
320
} // 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