Skip to content
This repository was archived by the owner on Apr 28, 2023. It is now read-only.

Commit ceef5c3

Browse files
Sven Verdoolaegeftynse
authored andcommitted
MappedScop::detectReductions: use dependences to check validity of ordering
The reduction matching moves out any statements other than the reduction updates to be able to do a pure mapping to library calls. The original code took into account that the init statement that corresponds to a reduction update statement can be moved in front of that update statement, but it would punt on any statements other than those explicitly marked as init statements. Use the dependences to check whether moving out the other statements is valid instead. This allows the matching to work in case there are any other statements (that can be moved out) or if the reduction init statements are not explicitly marked.
1 parent 3a2d17e commit ceef5c3

File tree

7 files changed

+61
-53
lines changed

7 files changed

+61
-53
lines changed

tc/core/polyhedral/cuda/mapped_scop.cc

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,8 @@ bool MappedScop::detectReductions(detail::ScheduleTree* tree) {
215215
// a single reduction for now.
216216
// Support for multiple reductions would require a check
217217
// that these reductions do not interfere with each other.
218-
auto initsUpdates = reductionInitsUpdates(band->mupa_.domain(), scop());
219-
auto inits = initsUpdates.first;
220-
auto updates = initsUpdates.second;
218+
auto domain = band->mupa_.domain();
219+
auto updates = reductionUpdates(domain, scop());
221220
if (updates.n_set() != 1) {
222221
return false;
223222
}
@@ -232,12 +231,19 @@ bool MappedScop::detectReductions(detail::ScheduleTree* tree) {
232231
if (!isReductionMember(member, updates, scop())) {
233232
return false;
234233
}
235-
// Order the init statements (if any) before the update statements
234+
// Order the other statements (if any) before the update statements
236235
// to ensure the band from which the reduction band has been split off
237236
// only contains update statements.
238-
// Note that this relies on the outer members being coincident.
239-
if (!inits.is_empty()) {
240-
orderBefore(scop_->scheduleRoot(), tree, inits);
237+
// Only do this if it doesn't violate any dependences.
238+
// TODO (#454): order statements before or after the reduction based on
239+
// dependences.
240+
auto other = domain.subtract(updates);
241+
if (!other.is_empty()) {
242+
auto dependences = scop_->activeDependences(tree);
243+
if (!canOrderBefore(scop_->scheduleRoot(), tree, other, dependences)) {
244+
return false;
245+
}
246+
orderBefore(scop_->scheduleRoot(), tree, other);
241247
}
242248
reductionBandUpdates_.emplace(tree, Reduction(updateIds));
243249
return true;

tc/core/polyhedral/reduction_matcher.cc

Lines changed: 4 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -118,52 +118,19 @@ bool isAlmostIdentityReduction(isl::pw_aff pa, const Scop& scop) {
118118
return false;
119119
}
120120

121-
/*
122-
* Return the identifier that maps to "stmt".
123-
*/
124-
isl::id statementId(const Scop& scop, const Halide::Internal::Stmt& stmt) {
125-
for (auto kvp : scop.halide.statements) {
126-
if (kvp.second.same_as(stmt)) {
127-
return kvp.first;
128-
}
129-
}
130-
CHECK(false) << "no id recorded for statement" << stmt;
131-
return isl::id();
132-
}
133-
134121
} // namespace
135122

136-
std::pair<isl::union_set, isl::union_set> reductionInitsUpdates(
137-
isl::union_set domain,
138-
const Scop& scop) {
139-
auto initUnion = isl::union_set::empty(domain.get_space());
140-
auto update = initUnion;
141-
std::unordered_set<isl::id, isl::IslIdIslHash> init;
142-
std::vector<isl::set> nonUpdate;
143-
// First collect all the update statements,
144-
// the corresponding init statement and all non-update statements.
145-
domain.foreach_set([&init, &update, &nonUpdate, &scop](isl::set set) {
123+
isl::union_set reductionUpdates(isl::union_set domain, const Scop& scop) {
124+
auto update = isl::union_set::empty(domain.get_space());
125+
domain.foreach_set([&update, &scop](isl::set set) {
146126
auto setId = set.get_tuple_id();
147127
Halide::Internal::Stmt initStmt;
148128
std::vector<size_t> reductionDims;
149129
if (isReductionUpdateId(setId, scop, initStmt, reductionDims)) {
150130
update = update.unite(set);
151-
init.emplace(statementId(scop, initStmt));
152-
} else {
153-
nonUpdate.emplace_back(set);
154131
}
155132
});
156-
// Then check if all the non-update statements are init statements
157-
// that correspond to the update statements found.
158-
// If not, return an empty list of update statements.
159-
for (auto set : nonUpdate) {
160-
if (init.count(set.get_tuple_id()) != 1) {
161-
return std::pair<isl::union_set, isl::union_set>(
162-
initUnion, isl::union_set::empty(domain.get_space()));
163-
}
164-
initUnion = initUnion.unite(set);
165-
}
166-
return std::pair<isl::union_set, isl::union_set>(initUnion, update);
133+
return update;
167134
}
168135

169136
bool isReductionMember(

tc/core/polyhedral/schedule_transforms.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,25 @@ ScheduleTreeUPtr gistedFilter(isl::union_set filter, ScheduleTreeUPtr child) {
731731

732732
} // namespace
733733

734+
bool canOrderBefore(
735+
ScheduleTree* root,
736+
ScheduleTree* tree,
737+
isl::union_set filter,
738+
isl::union_map dependences) {
739+
// Create an ordering schedule function filter -> 0; other -> 1.
740+
auto other = activeDomainPoints(root, tree).subtract(filter);
741+
auto ctx = root->ctx_;
742+
auto space = isl::space(ctx, 0).unnamed_set_from_params(1);
743+
auto zero = isl::multi_val::zero(space);
744+
auto one = zero.set_val(0, isl::val::one(ctx));
745+
auto order = isl::multi_union_pw_aff(filter, zero);
746+
order = order.union_add(isl::multi_union_pw_aff(other, one));
747+
748+
// Check that this ordering preserves all dependences.
749+
auto preserved = dependences.lex_lt_at(order).unite(dependences.eq_at(order));
750+
return dependences.is_subset(preserved);
751+
}
752+
734753
void orderBefore(
735754
ScheduleTree* root,
736755
ScheduleTree* tree,

tc/core/polyhedral/schedule_transforms.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,15 @@ void insertExtensionLabelAfter(
233233
detail::ScheduleTree* tree,
234234
isl::id id);
235235

236+
// Is it possible to order the elements in the given filter
237+
// before the other active elements without violating
238+
// any of the given dependences?
239+
bool canOrderBefore(
240+
detail::ScheduleTree* root,
241+
detail::ScheduleTree* tree,
242+
isl::union_set filter,
243+
isl::union_map dependences);
244+
236245
// Insert a sequence to ensure that the active domain elements
237246
// in the given filter are executed before the other active domain elements.
238247
void orderBefore(

tc/core/polyhedral/schedule_tree_matcher.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,9 @@
2525
namespace tc {
2626
namespace polyhedral {
2727

28-
// Return the union of the reduction init statements as well as
29-
// the union of the reduction update statements
30-
// that appear in "domain", assuming "domain" only contains
31-
// reduction init and update statements.
32-
// If "domain" contains any other statements, then return an empty set
33-
// of reduction update statements.
34-
std::pair<isl::union_set, isl::union_set> reductionInitsUpdates(
35-
isl::union_set domain,
36-
const Scop& scop);
28+
// Return the union of the reduction update statements
29+
// that appear in "domain".
30+
isl::union_set reductionUpdates(isl::union_set domain, const Scop& scop);
3731

3832
// Does the band member with the given partial schedule correspond
3933
// to a reduction on all statements with a domain in "domain"?

tc/core/polyhedral/scop.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,16 @@ void Scop::computeAllDependences() {
390390
dependences = flowDeps.unite(falseDeps).coalesce();
391391
}
392392

393+
isl::union_map Scop::activeDependences(detail::ScheduleTree* tree) {
394+
auto prefix = prefixScheduleMupa(scheduleRoot(), tree);
395+
auto domain = activeDomainPoints(scheduleRoot(), tree);
396+
auto active = dependences;
397+
active = active.intersect_domain(domain);
398+
active = active.intersect_range(domain);
399+
active = active.eq_at(prefix);
400+
return active;
401+
}
402+
393403
std::unique_ptr<detail::ScheduleTree> Scop::computeSchedule(
394404
isl::schedule_constraints constraints,
395405
const SchedulerOptionsView& schedulerOptions) {

tc/core/polyhedral/scop.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,9 @@ struct Scop {
471471
// Do the simplest possible dependence analysis.
472472
// Compute all RAW, WAR, and WAW dependences, and save them in dependences.
473473
void computeAllDependences();
474+
// Return the set of dependences that are active
475+
// at the given position.
476+
isl::union_map activeDependences(detail::ScheduleTree* tree);
474477

475478
public:
476479
// Halide stuff

0 commit comments

Comments
 (0)