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

Commit 8cfdd57

Browse files
author
Sven Verdoolaege
committed
use polyhedral reduction description to detect reductions
The exact notion of what constitutes a "reduction" was not spelled out very clearly, but in the use case of mapping the detected reduction to CUB, each thread needs to write to a single tensor element. Take this property as the definition of a "reduction". A necessary and sufficient condition is that the schedule dimensions outside the band members that are considered to form the reduction, determine a unique tensor element that is updated. The condition used in the original detection mechanism (that the reduction band members only involve a specific reduction dimension of the reduction update statement) is neither sufficient nor necessary. It is not sufficient because it doesn't force the schedule dimensions not involving the reduction dimensions to appear outside of those band members. It is not clear if such a case could ever arise in practice in TC, because the coincident band members get placed outermost. However, this situation could change in the future if other criteria such as consecutivity get taken into account. It is not necessary because it is perfectly fine for such a band member to reference multiple reduction dimensions or even to involve non-reduction dimensions, as long as those non-reduction dimensions also appear in outer schedule band members. Since no skewing is currently allowed, this is currently also unlikely to happen. In summary, what the reduction band members look like is largely irrelevant. What is important is that the outer band members make sure that only a single tensor element gets accessed. It just so happens that the reduction band members are very likely to have a particular form in that case. Change the reduction detection mechanism to use the polyhedral reduction representation. Note that if a tensor element is involved in multiple separate reductions (again, unlikely in the current code base), then the detection will not only ensure that a single tensor element is involved, but more specifically, a single reduction on that tensor element. This new mechanism is also much simpler.
1 parent 67fc014 commit 8cfdd57

File tree

4 files changed

+23
-61
lines changed

4 files changed

+23
-61
lines changed

tc/core/polyhedral/cuda/mapped_scop.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,11 @@ bool MappedScop::detectReductions(detail::ScheduleTree* tree) {
268268
updates.foreach_set([&updateIds](isl::set set) {
269269
updateIds.emplace_back(set.get_tuple_id());
270270
});
271-
// The reduction member needs to appear right underneath
272-
// the coincident members.
273-
auto reductionDim = nCoincident;
274-
auto member = band->mupa_.get_union_pw_aff(reductionDim);
275-
if (!isReductionMember(member, updates, scop())) {
271+
// The outer (coincident) members, together with the prefix schedule,
272+
// need to determine a single reduction.
273+
auto prefix = prefixScheduleMupa(schedule(), tree);
274+
prefix = prefix.range_product(band->memberRange(0, nCoincident));
275+
if (!isSingleReductionWithin(updates, prefix, scop())) {
276276
return false;
277277
}
278278
// Order the other statements (if any) before the update statements

tc/core/polyhedral/cuda/mapped_scop.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ class MappedScop {
154154
// Look for innermost reduction bands.
155155
// Store them in reductionBandUpdates_.
156156
// Return true if any were found.
157+
// A band is considered to be a reduction band if it only involves
158+
// instances of a single reduction update statement (modulo other
159+
// statements that can be moved out of the way) and if the outer
160+
// coincident members in the band, together with the prefix schedule,
161+
// determine individual reductions. In particular, each instance
162+
// of this combined outer schedule only writes to a single tensor element.
157163
bool detectReductions(detail::ScheduleTree* band);
158164
// Does separateReduction need to be called on this node?
159165
bool needReductionSeparation(const detail::ScheduleTree* st);

tc/core/polyhedral/reduction_matcher.cc

Lines changed: 7 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -69,52 +69,6 @@ bool isReductionUpdateId(
6969
return false;
7070
}
7171

72-
/*
73-
* Does "aff" only involve the specified input dimension (and not
74-
* any other input dimensions).
75-
*/
76-
bool pwAffInvolvesOnlyInputDim(isl::pw_aff pa, int redDimIdx) {
77-
auto space = pa.get_space();
78-
79-
if (!pa.involves_dims(isl::dim_type::in, redDimIdx, 1)) {
80-
return false;
81-
}
82-
83-
if (pa.involves_dims(isl::dim_type::in, 0, redDimIdx) ||
84-
pa.involves_dims(
85-
isl::dim_type::in,
86-
redDimIdx + 1,
87-
space.dim(isl::dim_type::in) - redDimIdx - 1)) {
88-
return false;
89-
}
90-
91-
return true;
92-
}
93-
94-
// Does pa have the form S(...) -> [(K*r)] where S is either a reduction init
95-
// or update statement and r is a known reduction loop in Scop?
96-
//
97-
// FIXME: now, K can be any value, including nested integer divisions, to
98-
// support detection after tiling; tighten this.
99-
bool isAlmostIdentityReduction(isl::pw_aff pa, const Scop& scop) {
100-
auto space = pa.get_space();
101-
if (!space.has_tuple_id(isl::dim_type::in)) {
102-
return false;
103-
}
104-
auto stmtId = space.get_tuple_id(isl::dim_type::in);
105-
std::vector<size_t> reductionDims;
106-
if (!isReductionUpdateId(stmtId, scop, reductionDims)) {
107-
return false;
108-
}
109-
110-
for (auto redDimIdx : reductionDims) {
111-
if (pwAffInvolvesOnlyInputDim(pa, redDimIdx)) {
112-
return true;
113-
}
114-
}
115-
return false;
116-
}
117-
11872
} // namespace
11973

12074
isl::union_set reductionUpdates(isl::union_set domain, const Scop& scop) {
@@ -129,14 +83,15 @@ isl::union_set reductionUpdates(isl::union_set domain, const Scop& scop) {
12983
return update;
13084
}
13185

132-
bool isReductionMember(
133-
isl::union_pw_aff member,
86+
bool isSingleReductionWithin(
13487
isl::union_set domain,
88+
isl::multi_union_pw_aff prefix,
13589
const Scop& scop) {
136-
return domain.every_set([member, &scop](isl::set set) {
137-
auto pa = member.extract_on_domain(set.get_space());
138-
return isAlmostIdentityReduction(pa, scop);
139-
});
90+
auto reductions = scop.body.reductions;
91+
reductions = reductions.intersect_domain(domain);
92+
auto prefixMap = isl::union_map::from(prefix);
93+
auto prefixToReduction = reductions.apply_domain(prefixMap);
94+
return prefixToReduction.is_single_valued();
14095
}
14196

14297
} // namespace polyhedral

tc/core/polyhedral/schedule_tree_matcher.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ namespace polyhedral {
2929
// that appear in "domain".
3030
isl::union_set reductionUpdates(isl::union_set domain, const Scop& scop);
3131

32-
// Does the band member with the given partial schedule correspond
33-
// to a reduction on all statements with a domain in "domain"?
34-
bool isReductionMember(
35-
isl::union_pw_aff member,
32+
// Does "prefix" partition "domain" into individual reductions?
33+
// In particular, do the elements of "domain" access a single tensor
34+
// element within "prefix"?
35+
bool isSingleReductionWithin(
3636
isl::union_set domain,
37+
isl::multi_union_pw_aff prefix,
3738
const Scop& scop);
3839

3940
} // namespace polyhedral

0 commit comments

Comments
 (0)