/* Merge pairs of consecutive leaves in "leaves" taking into account * the intersection of validity and proximity schedule constraints "dep". * * If a leaf has been merged with the next leaf, then the combination * is checked again for merging with the next leaf. * That is, if the leaves are A, B and C, then B may not have been * merged with C, but after merging A and B, it could still be useful * to merge the combination AB with C. * * Two leaves A and B are merged if there are instances of at least * one pair of statements, one statement in A and one B, such that * the validity and proximity schedule constraints between them * make them suitable for merging according to check_merge. * * Return the final number of leaves in the sequence, or -1 on error. */ static int merge_leaves(int n, struct ppcg_grouping_leaf leaves[n], __isl_keep isl_union_map *dep) { int i; struct ppcg_merge_leaves_data data; for (i = n - 1; i >= 0; --i) { isl_union_map *dep_i; isl_stat ok; if (i + 1 >= n) continue; dep_i = isl_union_map_copy(dep); dep_i = isl_union_map_intersect_domain(dep_i, isl_union_set_copy(leaves[i].domain)); dep_i = isl_union_map_intersect_range(dep_i, isl_union_set_copy(leaves[i + 1].domain)); data.merge = 0; data.src = &leaves[i]; data.dst = &leaves[i + 1]; ok = isl_union_map_foreach_map(dep_i, &check_merge, &data); isl_union_map_free(dep_i); if (ok < 0 && !data.merge) return -1; if (!data.merge) continue; if (merge_pair(n, leaves, i) < 0) return -1; --n; ++i; } return n; }
/* Construct a contraction from "prefix" and "domain" for a new group * in "grouping". * * The values of the prefix schedule "prefix" are used as instances * of the new group. The identifier of the group is constructed * in such a way that it does not conflict with those of earlier * groups nor with statements in the domain of the original * schedule constraints. * The isl_multi_union_pw_aff "prefix" then simply needs to be * converted to an isl_union_pw_multi_aff. However, this is not * possible if "prefix" is zero-dimensional, so in this case, * a contraction is constructed from "domain" instead. */ static isl_union_pw_multi_aff *group_contraction_from_prefix_and_domain( struct ppcg_grouping *grouping, __isl_keep isl_multi_union_pw_aff *prefix, __isl_keep isl_union_set *domain) { isl_id *id; isl_space *space; int dim; space = isl_multi_union_pw_aff_get_space(prefix); if (!space) return NULL; dim = isl_space_dim(space, isl_dim_set); id = construct_group_id(grouping, space); if (dim == 0) { isl_multi_val *mv; space = isl_multi_union_pw_aff_get_space(prefix); space = isl_space_set_tuple_id(space, isl_dim_set, id); mv = isl_multi_val_zero(space); domain = isl_union_set_copy(domain); return isl_union_pw_multi_aff_multi_val_on_domain(domain, mv); } prefix = isl_multi_union_pw_aff_copy(prefix); prefix = isl_multi_union_pw_aff_set_tuple_id(prefix, isl_dim_out, id); return isl_union_pw_multi_aff_from_multi_union_pw_aff(prefix); }
/* Return an array of "n" elements with information extracted from * the "n" children of "node" starting at "first", all of which * are known to be filtered leaves. */ struct ppcg_grouping_leaf *extract_leaves(__isl_keep isl_schedule_node *node, int first, int n) { int i; isl_ctx *ctx; struct ppcg_grouping_leaf *leaves; if (!node) return NULL; ctx = isl_schedule_node_get_ctx(node); leaves = isl_calloc_array(ctx, struct ppcg_grouping_leaf, n); if (!leaves) return NULL; for (i = 0; i < n; ++i) { isl_schedule_node *child; isl_union_set *domain; child = isl_schedule_node_get_child(node, first + i); child = isl_schedule_node_child(child, 0); domain = isl_schedule_node_get_domain(child); leaves[i].domain = isl_union_set_copy(domain); leaves[i].list = isl_union_set_list_from_union_set(domain); leaves[i].prefix = get_prefix(child); isl_schedule_node_free(child); } return leaves; }
/* Complete "grouping" to cover all statement instances in the domain * of grouping->sc. * * In particular, grouping->domain is set to the full set of statement * instances; group->contraction is extended with an identity * contraction on the additional instances and group->schedule * is extended with an independent schedule on those additional instances. * In the extension of group->contraction, the additional instances * are split into those belong to different statements and those * that belong to some of the same statements. The first group * is replaced by its universe in order to simplify the contraction extension. */ static void complete_grouping(struct ppcg_grouping *grouping) { isl_union_set *domain, *left, *overlap; isl_union_pw_multi_aff *upma; isl_schedule *schedule; domain = isl_schedule_constraints_get_domain(grouping->sc); left = isl_union_set_subtract(isl_union_set_copy(domain), isl_union_set_copy(grouping->domain)); schedule = isl_schedule_from_domain(isl_union_set_copy(left)); schedule = isl_schedule_set(schedule, grouping->schedule); grouping->schedule = schedule; overlap = isl_union_set_universe(grouping->domain); grouping->domain = domain; overlap = isl_union_set_intersect(isl_union_set_copy(left), overlap); left = isl_union_set_subtract(left, isl_union_set_copy(overlap)); left = isl_union_set_universe(left); left = isl_union_set_union(left, overlap); upma = isl_union_set_identity_union_pw_multi_aff(left); upma = isl_union_pw_multi_aff_union_add(upma, grouping->contraction); grouping->contraction = upma; }
/* Construct a schedule with "domain" as domain, that executes * the elements of "list" in order (as a sequence). */ static __isl_give isl_schedule *schedule_from_domain_and_list( __isl_keep isl_union_set *domain, __isl_keep isl_union_set_list *list) { isl_schedule *schedule; isl_schedule_node *node; schedule = isl_schedule_from_domain(isl_union_set_copy(domain)); node = isl_schedule_get_root(schedule); isl_schedule_free(schedule); node = isl_schedule_node_child(node, 0); list = isl_union_set_list_copy(list); node = isl_schedule_node_insert_sequence(node, list); schedule = isl_schedule_node_get_schedule(node); isl_schedule_node_free(node); return schedule; }
/* Extend "grouping" with groups corresponding to merged * leaves in the list of potentially merged leaves "leaves". * * The "list" field of each element in "leaves" contains a list * of the instances sets of the original leaves that have been * merged into this element. If at least two of the original leaves * have been merged into a given element, then add the corresponding * group to "grouping". * In particular, the domain is extended with the statement instances * of the merged leaves, the contraction is extended with a mapping * of these statement instances to instances of a new group and * the schedule is extended with a schedule that executes * the statement instances according to the order of the leaves * in which they appear. * Since the instances of the groups should already be scheduled apart * in the schedule into which this schedule will be plugged in, * the schedules of the individual groups are combined independently * of each other (as a set). */ static isl_stat add_groups(struct ppcg_grouping *grouping, int n, struct ppcg_grouping_leaf leaves[n]) { int i; for (i = 0; i < n; ++i) { int n_leaf; isl_schedule *schedule; isl_union_set *domain; isl_union_pw_multi_aff *upma; n_leaf = isl_union_set_list_n_union_set(leaves[i].list); if (n_leaf < 0) return isl_stat_error; if (n_leaf <= 1) continue; schedule = schedule_from_domain_and_list(leaves[i].domain, leaves[i].list); upma = group_contraction_from_prefix_and_domain(grouping, leaves[i].prefix, leaves[i].domain); domain = isl_union_set_copy(leaves[i].domain); if (grouping->domain) { domain = isl_union_set_union(domain, grouping->domain); upma = isl_union_pw_multi_aff_union_add(upma, grouping->contraction); schedule = isl_schedule_set(schedule, grouping->schedule); } grouping->domain = domain; grouping->contraction = upma; grouping->schedule = schedule; if (!grouping->domain || !grouping->contraction || !grouping->schedule) return isl_stat_error; } return isl_stat_ok; }
/* Create a duplicate of the given isl_schedule_band. */ __isl_give isl_schedule_band *isl_schedule_band_dup( __isl_keep isl_schedule_band *band) { int i; isl_ctx *ctx; isl_schedule_band *dup; if (!band) return NULL; ctx = isl_schedule_band_get_ctx(band); dup = isl_schedule_band_alloc(ctx); if (!dup) return NULL; dup->n = band->n; dup->coincident = isl_alloc_array(ctx, int, band->n); if (band->n && !dup->coincident) return isl_schedule_band_free(dup); for (i = 0; i < band->n; ++i) dup->coincident[i] = band->coincident[i]; dup->permutable = band->permutable; dup->mupa = isl_multi_union_pw_aff_copy(band->mupa); dup->ast_build_options = isl_union_set_copy(band->ast_build_options); if (!dup->mupa || !dup->ast_build_options) return isl_schedule_band_free(dup); if (band->loop_type) { dup->loop_type = isl_alloc_array(ctx, enum isl_ast_loop_type, band->n); if (band->n && !dup->loop_type) return isl_schedule_band_free(dup); for (i = 0; i < band->n; ++i) dup->loop_type[i] = band->loop_type[i]; }
static void *isl_obj_union_set_copy(void *v) { return isl_union_set_copy((isl_union_set *)v); }