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

Commit 1dff4ff

Browse files
authored
Merge pull request #427 from facebookresearch/pr/valid_schedule
drop checkValidIslSchedule
2 parents a9057d9 + d5ad933 commit 1dff4ff

File tree

5 files changed

+0
-263
lines changed

5 files changed

+0
-263
lines changed

tc/core/polyhedral/codegen_llvm.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,6 @@ IslCodegenRes codegenISL(const Scop& scop) {
667667
return collectIteratorMaps(n, b, uv, scop, stmtSubscripts);
668668
};
669669

670-
checkValidIslSchedule(scop.scheduleRoot());
671670
auto schedule = detail::toIslSchedule(scop.scheduleRoot());
672671
auto astBuild = isl::ast_build(schedule.get_ctx());
673672
astBuild = astBuild.set_at_each_domain(collect);

tc/core/polyhedral/cuda/codegen.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,7 +785,6 @@ string emitCudaKernel(
785785
return collectIteratorMaps(n, b, &nodeInfoMap);
786786
};
787787

788-
checkValidIslSchedule(mscop.schedule());
789788
auto schedule = detail::toIslSchedule(mscop.schedule());
790789
auto astBuild = isl::ast_build(schedule.get_ctx());
791790
astBuild = astBuild.set_at_each_domain(collect);

tc/core/polyhedral/schedule_isl_conversion.cc

Lines changed: 0 additions & 230 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ isl::schedule_node extendChild(
243243
* then recursively add nodes corresponding to the descendants of "root".
244244
*/
245245
isl::schedule toIslSchedule(const ScheduleTree* root) {
246-
checkValidIslSchedule(root);
247246
auto domain = root->elemAs<ScheduleTreeElemDomain>();
248247
CHECK(domain) << "Root node should be domain node" << *root;
249248
auto node = isl::schedule_node::from_domain(domain->domain_);
@@ -289,235 +288,6 @@ bool validateSchedule(isl::schedule sc) {
289288
return validateSchedule(fromIslSchedule(sc).get());
290289
}
291290

292-
namespace {
293-
294-
// Get the parametric space in which the relation contained by the given tree
295-
// are defined.
296-
isl::space definitionParamSpace(const ScheduleTree* node) {
297-
auto space = isl::space(node->ctx_, 0);
298-
switch (node->type_) {
299-
// mapping_filter is a filter for ISL
300-
// TODO: this switch is too ISL-ish and is not meant for subtyping
301-
// extensions. Replace by if (node->elemAsBase<T>(...))
302-
case detail::ScheduleTreeType::MappingFilter:
303-
case detail::ScheduleTreeType::Filter: {
304-
auto filterNode = node->elemAsBase<ScheduleTreeElemFilter>();
305-
space = filterNode->filter_.get_space().params();
306-
break;
307-
}
308-
case detail::ScheduleTreeType::Band: {
309-
auto bandNode = node->elemAs<ScheduleTreeElemBand>();
310-
space = bandNode->mupa_.get_space().params();
311-
break;
312-
}
313-
case detail::ScheduleTreeType::Extension: {
314-
auto extensionNode = node->elemAs<ScheduleTreeElemExtension>();
315-
space = extensionNode->extension_.get_space().params();
316-
break;
317-
}
318-
case detail::ScheduleTreeType::Domain: {
319-
auto domainElem = node->elemAs<ScheduleTreeElemDomain>();
320-
space = domainElem->domain_.get_space().params();
321-
break;
322-
}
323-
case detail::ScheduleTreeType::Context: {
324-
auto contextElem = node->elemAs<ScheduleTreeElemContext>();
325-
space = contextElem->context_.get_space().params();
326-
break;
327-
}
328-
329-
// Other types of nodes do not have any potentially parametric expression.
330-
case detail::ScheduleTreeType::Any:
331-
case detail::ScheduleTreeType::None:
332-
case detail::ScheduleTreeType::Set:
333-
case detail::ScheduleTreeType::Sequence:
334-
case detail::ScheduleTreeType::ThreadSpecificMarker:
335-
break;
336-
}
337-
return space;
338-
}
339-
340-
bool refersToUndefinedParameters(
341-
const ScheduleTree* relativeRoot,
342-
const ScheduleTree* node) {
343-
using namespace polyhedral::detail;
344-
345-
// Assuming no parameters are introduced above root.
346-
if (node == relativeRoot) {
347-
return false;
348-
}
349-
350-
// Domain and context can introduce new parameters.
351-
if (node->elemAs<ScheduleTreeElemDomain>() ||
352-
node->elemAs<ScheduleTreeElemContext>()) {
353-
return false;
354-
}
355-
356-
// Collect all ancestors that are allowed to introduce new parameters, i.e.
357-
// domain and context nodes. Collect the parameters they introduce in a
358-
// space.
359-
auto paramSpace = isl::null<isl::space>();
360-
for (auto anc : node->ancestors(relativeRoot)) {
361-
auto contextNode = anc->elemAs<ScheduleTreeElemContext>();
362-
auto domainNode = anc->elemAs<ScheduleTreeElemDomain>();
363-
if (!contextNode && !domainNode) {
364-
continue;
365-
}
366-
367-
auto space = contextNode ? contextNode->context_.get_space()
368-
: domainNode->domain_.get_space();
369-
space = space.params();
370-
paramSpace = paramSpace.get() ? paramSpace.align_params(space) : space;
371-
}
372-
373-
CHECK(paramSpace.get()) << "no parent context or domain node found";
374-
if (!paramSpace.get()) {
375-
return true;
376-
}
377-
378-
// The space in which tree's relations are defined should not involve
379-
// parameters that were not present in its domain or context ancestors. If
380-
// the tree has no relations, it cannot refer to undefined parameters.
381-
auto space = definitionParamSpace(node);
382-
if (space.dim(isl::dim_type::param) == 0) {
383-
return false;
384-
}
385-
386-
// If space uses some parameters that are not available in paramSpace,
387-
// they will be introduced into paramSpace, making its dimension larger.
388-
auto definedParams = paramSpace.dim(isl::dim_type::param);
389-
paramSpace = paramSpace.align_params(space);
390-
return paramSpace.dim(isl::dim_type::param) > definedParams;
391-
}
392-
393-
// Note that this uses union_set as "optional" where nullptr value means
394-
// there's no actual value, rather than an error.
395-
isl::union_set nodeDomain(const ScheduleTree* node) {
396-
if (auto domainElem = node->elemAs<ScheduleTreeElemDomain>()) {
397-
return domainElem->domain_;
398-
} else if (auto bandElem = node->elemAs<ScheduleTreeElemBand>()) {
399-
return bandElem->mupa_.domain();
400-
} else if (auto filterElem = node->elemAsBase<ScheduleTreeElemFilter>()) {
401-
return filterElem->filter_;
402-
} else if (auto extensionElem = node->elemAs<ScheduleTreeElemExtension>()) {
403-
// FIXME: these are the points that are _introduced_... they are inactive
404-
// until now...
405-
// does the extension have a domain?
406-
return extensionElem->extension_
407-
.range(); // FIXME: do we need to restrict its domain first?
408-
}
409-
return isl::null<isl::union_set>();
410-
}
411-
} // namespace
412-
413-
void checkValidIslSchedule(const ScheduleTree* root_) {
414-
using namespace polyhedral::detail;
415-
416-
// 1. The root node is always of type domain or extension.
417-
auto domainRoot = root_->elemAs<ScheduleTreeElemDomain>();
418-
auto extensionRoot = root_->elemAs<ScheduleTreeElemDomain>();
419-
CHECK(domainRoot || extensionRoot)
420-
<< "root must be a domain or an extension" << *root_;
421-
422-
for (auto node : ScheduleTree::collect(root_)) {
423-
auto activeInstances = activeDomainPoints(root_, node);
424-
auto nodeDomainPoints = nodeDomain(node);
425-
426-
// 2. Only set or sequence nodes are allowed to have multiple children and
427-
// these children must be filter nodes.
428-
auto nodeIsSet = node->elemAs<ScheduleTreeElemSet>() != nullptr;
429-
auto nodeIsSequence = node->elemAs<ScheduleTreeElemSequence>() != nullptr;
430-
auto nChildren = node->numChildren();
431-
432-
// 4. Nodes should not refer to inactive domain points.
433-
if (nodeDomainPoints.get()) {
434-
if (!nodeDomainPoints.is_subset(activeInstances)) {
435-
LOG_IF(WARNING, tc::FLAGS_schedule_tree_verbose_validation)
436-
<< "node refers to inactive domain points: active "
437-
<< activeInstances << " found: " << nodeDomainPoints << " in\n"
438-
<< *node;
439-
}
440-
}
441-
442-
if (!nodeIsSet && !nodeIsSequence) {
443-
CHECK_LE(nChildren, 1u)
444-
<< "only sequence or set nodes can have multiple children" << *node;
445-
} else {
446-
auto filters = isl::null<isl::union_set>();
447-
for (auto child : node->children()) {
448-
auto filterElem = child->elemAsBase<ScheduleTreeElemFilter>();
449-
auto childIsFilter = filterElem != nullptr;
450-
CHECK(childIsFilter)
451-
<< "only filter nodes allowed as children of sequence or set node"
452-
<< *child;
453-
454-
filters = filters.get() ? filters.unite(filterElem->filter_)
455-
: filterElem->filter_;
456-
}
457-
CHECK(filters.get()) << "set/sequence node must have at least one child"
458-
<< *node;
459-
460-
// 5. The union of filters must cover all active domain points.
461-
CHECK(activeInstances.is_subset(filters))
462-
<< "filters must cover all active domain points; active "
463-
<< activeInstances << " filtered: " << filters << " in\n"
464-
<< *node;
465-
}
466-
467-
// 3. Nodes should not refer to parameters that are not declared in context
468-
// nodes above.
469-
bool usesUndefinedParams = refersToUndefinedParameters(root_, node);
470-
CHECK(!usesUndefinedParams)
471-
<< "non-context node introduces new parameters" << *node;
472-
473-
// 7. Band schedules should be total on all active domain points.
474-
// Only check if an actual domain is specified.
475-
// In particular, 0D bands do not necessarily specify a domain.
476-
if (auto bandElem = node->elemAs<ScheduleTreeElemBand>()) {
477-
auto scheduleDefinitionDomain = bandElem->mupa_.domain();
478-
if (!scheduleDefinitionDomain.is_params()) {
479-
CHECK(activeInstances.is_subset(scheduleDefinitionDomain))
480-
<< "schedule should be total on the active domain points: active"
481-
<< activeInstances
482-
<< " schedule defined over: " << scheduleDefinitionDomain << " in\n"
483-
<< *node;
484-
}
485-
}
486-
487-
// 8. Extension nodes should not introduce any elements that are already
488-
// active domain elements.
489-
// 10. Anchored nodes match the flattened space of the outer bands.
490-
if (auto extensionElem = node->elemAs<ScheduleTreeElemExtension>()) {
491-
auto introducedInstances =
492-
extensionElem->extension_
493-
.range(); // FIXME: restrict domain to the partial schedule??
494-
CHECK(introducedInstances.intersect(activeInstances).is_empty())
495-
<< "extension node should not introduce elements that are already "
496-
"active domain elements: active "
497-
<< activeInstances << " introduced: " << introducedInstances
498-
<< " in\n"
499-
<< *node;
500-
// FIXME: we probably want to check dim_ids for an exact match
501-
auto depth = node->scheduleDepth(root_);
502-
auto extension = extensionElem->extension_;
503-
for (auto const& e : isl::UnionAsVector<isl::union_map>(extension)) {
504-
CHECK_EQ(depth, e.dim(isl::dim_type::in))
505-
<< "the input dimensionality of the extension map should "
506-
"correspond to the schedule depth"
507-
<< *node;
508-
}
509-
}
510-
511-
// 10. Anchored nodes match the flattened space of the outer bands.
512-
if (auto contextElem = node->elemAs<ScheduleTreeElemContext>()) {
513-
auto depth = node->scheduleDepth(root_);
514-
CHECK_EQ(depth, contextElem->context_.dim(isl::dim_type::set))
515-
<< "the dimensionality of the context should correspond "
516-
"to the schedule depth"
517-
<< *node;
518-
}
519-
}
520-
}
521291
} // namespace detail
522292
} // namespace polyhedral
523293
} // namespace tc

tc/core/polyhedral/schedule_isl_conversion.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ isl::schedule toIslSchedule(const ScheduleTree* root_);
3333
std::unique_ptr<ScheduleTree> fromIslSchedule(isl::schedule schedule);
3434
bool validateSchedule(const ScheduleTree* st);
3535
bool validateSchedule(isl::schedule schedule);
36-
void checkValidIslSchedule(const detail::ScheduleTree* root_);
3736
} // namespace detail
3837
} // namespace polyhedral
3938
} // namespace tc

tc/core/polyhedral/schedule_tree.h

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -104,36 +104,6 @@ namespace detail {
104104
//
105105
// ScheduleTree does NOT impose any structure requirements on the tree, e.g.
106106
// those of ISL. A tree with a null child is ill-formed.
107-
//
108-
// Note that we do not enforce the isl schedule tree invariants [1] at the API
109-
// level. Instead, we provide a function checkValidIslSchedule() to verify
110-
// whether a schedule that has a given ScheduleTree as root can be converted to
111-
// an isl::schedule. Note that, for compatibility reasons, the current
112-
// implementation may also create isl::schedules that do not maintain isl
113-
// schedule tree guarantees. The behavior of isl calls on such schedules is
114-
// undefined.
115-
//
116-
// The following isl invariants can be checked
117-
// 1. root is domain/extension
118-
// 2. only sequence/set have multiple children, these children are filters
119-
// 3. nodes do not refer to parameters that were not previously introduced by a
120-
// context or a domain node
121-
// 4. nodes do not refer to inactive domain points, i.e. those that were
122-
// filtered away (warning only)
123-
// 5. union of filters contains all active domain elements
124-
// 6. domain of an expansion contains all active domain elements
125-
// 7. partial schedule of a band node is total for all active domain elements
126-
// 8. extension nodes do not introduce any elements that are already active
127-
// domain elements
128-
// 9. (not enforced)
129-
// 10. that anchored nodes match the flattened space of the outer bands
130-
//
131-
// TODO(ftynse): implement bool checkValidIslSchedule() to check schedule
132-
// structure without failing the run.
133-
//
134-
//
135-
// [1] Verdoolaege, Guelton, Grosser & Cohen (2014). "Schedule trees". In
136-
// IMPACT 2014.
137107
//////////////////////////////////////////////////////////////////////////////
138108

139109
std::ostream& operator<<(std::ostream& os, const ScheduleTree& tree);

0 commit comments

Comments
 (0)