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

Commit c21c93f

Browse files
authored
Merge pull request #462 from facebookresearch/pr/order
MappedScop::detectReductions: order away statements that depend on updates
2 parents 4615c82 + 3d54f2d commit c21c93f

File tree

4 files changed

+83
-21
lines changed

4 files changed

+83
-21
lines changed

tc/core/polyhedral/cuda/mapped_scop.cc

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ void MappedScop::mapToBlocksAndScaleBand(
166166
bandScale(band, tileSizes);
167167
}
168168

169+
namespace {
170+
169171
/*
170172
* Given a node in the schedule tree of a mapped scop,
171173
* insert a mapping filter underneath (if needed) that fixes
@@ -186,6 +188,41 @@ void fixThreadsBelow(
186188
mscop.mapThreadsBackward(bandTree);
187189
}
188190

191+
/*
192+
* Try and order the other statements in "domain" (if any)
193+
* away from the "updates" statements, returning true is the operation succeeds.
194+
* In particular, only do this if it doesn't violate any dependences.
195+
* Anything that depends on an update statement is ordered after
196+
* the update statements. Anything else is ordered before.
197+
*/
198+
bool separatedOut(
199+
Scop& scop,
200+
detail::ScheduleTree* tree,
201+
isl::union_set domain,
202+
isl::union_set updates) {
203+
auto other = domain.subtract(updates);
204+
if (other.is_empty()) {
205+
return true;
206+
}
207+
auto dependences = scop.activeDependences(tree);
208+
auto after =
209+
dependences.intersect_domain(updates).intersect_range(other).range();
210+
auto before = other.subtract(after);
211+
if (!canOrderBefore(scop.scheduleRoot(), tree, before, dependences) ||
212+
!canOrderAfter(scop.scheduleRoot(), tree, after, dependences)) {
213+
return false;
214+
}
215+
if (!before.is_empty()) {
216+
orderBefore(scop.scheduleRoot(), tree, before);
217+
}
218+
if (!after.is_empty()) {
219+
orderAfter(scop.scheduleRoot(), tree, after);
220+
}
221+
return true;
222+
}
223+
224+
} // namespace
225+
189226
bool MappedScop::detectReductions(detail::ScheduleTree* tree) {
190227
bool found = false;
191228
for (auto c : tree->children()) {
@@ -234,16 +271,8 @@ bool MappedScop::detectReductions(detail::ScheduleTree* tree) {
234271
// Order the other statements (if any) before the update statements
235272
// to ensure the band from which the reduction band has been split off
236273
// only contains update statements.
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);
274+
if (!separatedOut(scop(), tree, domain, updates)) {
275+
return false;
247276
}
248277
reductionBandUpdates_.emplace(tree, Reduction(updateIds));
249278
return true;

tc/core/polyhedral/schedule_transforms.cc

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -729,25 +729,49 @@ ScheduleTreeUPtr gistedFilter(isl::union_set filter, ScheduleTreeUPtr child) {
729729
return ScheduleTree::makeFilter(filter, std::move(child));
730730
}
731731

732+
/*
733+
* Given a partition of the (active) domain elements into "first" and "second",
734+
* is it possible to order the "first" elements before the "second"
735+
* without violating any of the (active) "dependences"?
736+
*/
737+
bool canOrder(
738+
isl::union_set first,
739+
isl::union_set second,
740+
isl::union_map dependences) {
741+
if (first.is_empty() || second.is_empty()) {
742+
return true;
743+
}
744+
// Create an ordering schedule function first -> 0; second -> 1.
745+
auto ctx = dependences.get_ctx();
746+
auto space = isl::space(ctx, 0).unnamed_set_from_params(1);
747+
auto zero = isl::multi_val::zero(space);
748+
auto one = zero.set_val(0, isl::val::one(ctx));
749+
auto order = isl::multi_union_pw_aff(first, zero);
750+
order = order.union_add(isl::multi_union_pw_aff(second, one));
751+
752+
// Check that this ordering preserves all dependences.
753+
auto preserved = dependences.lex_lt_at(order).unite(dependences.eq_at(order));
754+
return dependences.is_subset(preserved);
755+
}
756+
732757
} // namespace
733758

734759
bool canOrderBefore(
735760
ScheduleTree* root,
736761
ScheduleTree* tree,
737762
isl::union_set filter,
738763
isl::union_map dependences) {
739-
// Create an ordering schedule function filter -> 0; other -> 1.
740764
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));
765+
return canOrder(filter, other, dependences);
766+
}
747767

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);
768+
bool canOrderAfter(
769+
ScheduleTree* root,
770+
ScheduleTree* tree,
771+
isl::union_set filter,
772+
isl::union_map dependences) {
773+
auto other = activeDomainPoints(root, tree).subtract(filter);
774+
return canOrder(other, filter, dependences);
751775
}
752776

753777
void orderBefore(

tc/core/polyhedral/schedule_transforms.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,14 @@ bool canOrderBefore(
241241
detail::ScheduleTree* tree,
242242
isl::union_set filter,
243243
isl::union_map dependences);
244+
// Is it possible to order the elements in the given filter
245+
// after the other active elements without violating
246+
// any of the given dependences?
247+
bool canOrderAfter(
248+
detail::ScheduleTree* root,
249+
detail::ScheduleTree* tree,
250+
isl::union_set filter,
251+
isl::union_map dependences);
244252

245253
// Insert a sequence to ensure that the active domain elements
246254
// in the given filter are executed before the other active domain elements.

test/test_cuda_mapper.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,8 @@ struct ReductionTest : public PolyhedralMapperTest {
867867
.outerScheduleFusionStrategy(tc::FusionStrategy::Preserve3Coincident)
868868
.outerScheduleAllowSkewing(false)
869869
.outerSchedulePositiveOrthant(true)
870-
.intraTileScheduleFusionStrategy(tc::FusionStrategy::Min)
870+
.intraTileScheduleFusionStrategy(
871+
tc::FusionStrategy::Preserve3Coincident)
871872
.intraTileScheduleAllowSkewing(false)
872873
.intraTileSchedulePositiveOrthant(true)
873874
.fixParametersBeforeScheduling(false)

0 commit comments

Comments
 (0)