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

Commit d5ad933

Browse files
author
Sven Verdoolaege
committed
drop checkValidIslSchedule
This function dates back from a time in prehistory when internal isl data structures (schedule trees) were being created from the outside, subverting the internal checks in isl. Part of the removed comments still mentions the possibility of constructing an invalid isl schedule. Since then, the isl schedule tree construction has been changed to use the proper interface. There is therefore no longer any need to check that the constructed isl schedule tree would be valid since isl should perform the appropriate checks. If any of those checks are missing from isl then they should be added there. The removed function is too low-level, incomplete (FIXMEs) and has a high risk of getting out of sync with isl. More generally, it does not make sense for TC to guess whether the result of a conversion to isl schedule trees would be valid if it does not control the conversion. It may make sense to add a function that checks whether it is possible to convert a TC schedule tree to an isl schedule tree instead.
1 parent 3575c7a commit d5ad933

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
@@ -669,7 +669,6 @@ IslCodegenRes codegenISL(const Scop& scop) {
669669
return collectIteratorMaps(n, b, uv, scop, stmtSubscripts);
670670
};
671671

672-
checkValidIslSchedule(scop.scheduleRoot());
673672
auto schedule = detail::toIslSchedule(scop.scheduleRoot());
674673
auto astBuild = isl::ast_build(schedule.get_ctx());
675674
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
@@ -738,7 +738,6 @@ string emitCudaKernel(
738738
return collectIteratorMaps(n, b, &nodeInfoMap);
739739
};
740740

741-
checkValidIslSchedule(mscop.schedule());
742741
auto schedule = detail::toIslSchedule(mscop.schedule());
743742
auto astBuild = isl::ast_build(schedule.get_ctx());
744743
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)