/* Given a relation "map" between instances of two statements A and B, * does it relate every instance of A (according to the domain of "src") * to every instance of B (according to the domain of "dst")? */ static isl_bool covers_src_and_dst(__isl_keep isl_map *map, struct ppcg_grouping_leaf *src, struct ppcg_grouping_leaf *dst) { isl_space *space; isl_set *set1, *set2; isl_bool is_subset; space = isl_space_domain(isl_map_get_space(map)); set1 = isl_union_set_extract_set(src->domain, space); set2 = isl_map_domain(isl_map_copy(map)); is_subset = isl_set_is_subset(set1, set2); isl_set_free(set1); isl_set_free(set2); if (is_subset < 0 || !is_subset) return is_subset; space = isl_space_range(isl_map_get_space(map)); set1 = isl_union_set_extract_set(dst->domain, space); set2 = isl_map_range(isl_map_copy(map)); is_subset = isl_set_is_subset(set1, set2); isl_set_free(set1); isl_set_free(set2); return is_subset; }
/* Insert an if node around graft->node testing the condition encoded * in guard "guard", assuming guard involves any conditions. */ static __isl_give isl_ast_graft *insert_if_node( __isl_take isl_ast_graft *graft, __isl_take isl_set *guard, __isl_keep isl_ast_build *build) { int univ; if (!graft) goto error; univ = isl_set_plain_is_universe(guard); if (univ < 0) goto error; if (univ) { isl_set_free(guard); return graft; } build = isl_ast_build_copy(build); graft->node = ast_node_insert_if(graft->node, guard, build); isl_ast_build_free(build); if (!graft->node) return isl_ast_graft_free(graft); return graft; error: isl_set_free(guard); return isl_ast_graft_free(graft); }
/* Compute the size of a bounding box around the origin and "set", * where "set" is assumed to contain only non-negative elements. * In particular, compute the maximal value of "set" in each direction * and add one. */ __isl_give isl_multi_pw_aff *ppcg_size_from_extent(__isl_take isl_set *set) { int i, n; isl_multi_pw_aff *mpa; n = isl_set_dim(set, isl_dim_set); mpa = isl_multi_pw_aff_zero(isl_set_get_space(set)); for (i = 0; i < n; ++i) { isl_space *space; isl_aff *one; isl_pw_aff *bound; if (!isl_set_dim_has_upper_bound(set, isl_dim_set, i)) { const char *name; name = isl_set_get_tuple_name(set); if (!name) name = ""; fprintf(stderr, "unable to determine extent of '%s' " "in dimension %d\n", name, i); set = isl_set_free(set); } bound = isl_set_dim_max(isl_set_copy(set), i); space = isl_pw_aff_get_domain_space(bound); one = isl_aff_zero_on_domain(isl_local_space_from_space(space)); one = isl_aff_add_constant_si(one, 1); bound = isl_pw_aff_add(bound, isl_pw_aff_from_aff(one)); mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, bound); } isl_set_free(set); return mpa; }
int isl_set_foreach_point(__isl_keep isl_set *set, int (*fn)(__isl_take isl_point *pnt, void *user), void *user) { struct isl_foreach_point fp = { { &foreach_point }, fn, user }; int i; if (!set) return -1; fp.dim = isl_set_get_dim(set); if (!fp.dim) return -1; set = isl_set_copy(set); set = isl_set_cow(set); set = isl_set_make_disjoint(set); set = isl_set_compute_divs(set); if (!set) goto error; for (i = 0; i < set->n; ++i) if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]), &fp.callback) < 0) goto error; isl_set_free(set); isl_dim_free(fp.dim); return 0; error: isl_set_free(set); isl_dim_free(fp.dim); return -1; }
/* Extract a common guard from the grafts in "list" that can be hoisted * out of the current level. If no such guard can be found, then return * a universal set. * * If all the grafts in the list have the same guard and if this guard * is independent of the current level, then it can be hoisted out. * Otherwise, we return the unshifted simple hull of the guards. * * The special case for equal guards is needed in case those guards * are non-convex. Taking the simple hull would remove information * and would not allow for these guards to be hoisted completely. */ static __isl_give isl_set *extract_hoistable_guard( __isl_keep isl_ast_graft_list *list, __isl_keep isl_ast_build *build) { int i, n; int depth; isl_ast_graft *graft_0; int equal; isl_set *guard; if (!list || !build) return NULL; n = isl_ast_graft_list_n_ast_graft(list); if (n == 0) return isl_set_universe(isl_ast_build_get_space(build, 1)); equal = equal_independent_guards(list, build); if (equal < 0) return NULL; graft_0 = isl_ast_graft_list_get_ast_graft(list, 0); if (!graft_0) return NULL; guard = isl_set_copy(graft_0->guard); isl_ast_graft_free(graft_0); if (equal) return guard; depth = isl_ast_build_get_depth(build); if (depth < isl_set_dim(guard, isl_dim_set)) { guard = isl_set_remove_divs_involving_dims(guard, isl_dim_set, depth, 1); guard = isl_set_eliminate(guard, isl_dim_set, depth, 1); guard = isl_set_compute_divs(guard); } for (i = 1; i < n; ++i) { isl_ast_graft *graft; isl_basic_set *hull; int is_universe; is_universe = isl_set_plain_is_universe(guard); if (is_universe < 0) guard = isl_set_free(guard); if (is_universe) break; graft = isl_ast_graft_list_get_ast_graft(list, i); if (!graft) { guard = isl_set_free(guard); break; } guard = isl_set_union(guard, isl_set_copy(graft->guard)); hull = isl_set_unshifted_simple_hull(guard); guard = isl_set_from_basic_set(hull); isl_ast_graft_free(graft); } return guard; }
static int qpolynomial_bound_on_domain_range(__isl_take isl_basic_set *bset, __isl_take isl_qpolynomial *poly, struct range_data *data) { unsigned nparam = isl_basic_set_dim(bset, isl_dim_param); unsigned nvar = isl_basic_set_dim(bset, isl_dim_set); isl_set *set = NULL; if (!bset) goto error; if (nvar == 0) return add_guarded_poly(bset, poly, data); set = isl_set_from_basic_set(bset); set = isl_set_split_dims(set, isl_dim_param, 0, nparam); set = isl_set_split_dims(set, isl_dim_set, 0, nvar); data->poly = poly; data->test_monotonicity = 1; if (isl_set_foreach_basic_set(set, &basic_guarded_poly_bound, data) < 0) goto error; isl_set_free(set); isl_qpolynomial_free(poly); return 0; error: isl_set_free(set); isl_qpolynomial_free(poly); return -1; }
/* Given a list of "n" if nodes, clear those starting at "first" * and return "first" (i.e., the updated size of the array). */ static int clear_if_nodes(struct isl_if_node *if_node, int first, int n) { int i; for (i = first; i < n; ++i) { isl_set_free(if_node[i].guard); isl_set_free(if_node[i].complement); } return first; }
struct isl_basic_map *isl_map_affine_hull(struct isl_map *map) { int i; struct isl_basic_map *model = NULL; struct isl_basic_map *hull = NULL; struct isl_set *set; map = isl_map_detect_equalities(map); map = isl_map_align_divs(map); if (!map) return NULL; if (map->n == 0) { hull = isl_basic_map_empty_like_map(map); isl_map_free(map); return hull; } model = isl_basic_map_copy(map->p[0]); set = isl_map_underlying_set(map); set = isl_set_cow(set); if (!set) goto error; for (i = 0; i < set->n; ++i) { set->p[i] = isl_basic_set_cow(set->p[i]); set->p[i] = isl_basic_set_affine_hull(set->p[i]); set->p[i] = isl_basic_set_gauss(set->p[i], NULL); if (!set->p[i]) goto error; } set = isl_set_remove_empty_parts(set); if (set->n == 0) { hull = isl_basic_map_empty_like(model); isl_basic_map_free(model); } else { struct isl_basic_set *bset; while (set->n > 1) { set->p[0] = affine_hull(set->p[0], set->p[--set->n]); if (!set->p[0]) goto error; } bset = isl_basic_set_copy(set->p[0]); hull = isl_basic_map_overlying_set(bset, model); } isl_set_free(set); hull = isl_basic_map_simplify(hull); return isl_basic_map_finalize(hull); error: isl_basic_map_free(model); isl_set_free(set); return NULL; }
__isl_give isl_set *isl_set_recession_cone(__isl_take isl_set *set) { int i; if (!set) return NULL; if (set->n == 0) return set; set = isl_set_remove_divs(set); set = isl_set_cow(set); if (!set) return NULL; for (i = 0; i < set->n; ++i) { set->p[i] = isl_basic_set_recession_cone(set->p[i]); if (!set->p[i]) goto error; } return set; error: isl_set_free(set); return NULL; }
/* Apply the morphism to the set. */ __isl_give isl_set *isl_morph_set(__isl_take isl_morph *morph, __isl_take isl_set *set) { int i; if (!morph || !set) goto error; isl_assert(set->ctx, isl_space_is_equal(set->dim, morph->dom->dim), goto error); set = isl_set_cow(set); if (!set) goto error; isl_space_free(set->dim); set->dim = isl_space_copy(morph->ran->dim); if (!set->dim) goto error; for (i = 0; i < set->n; ++i) { set->p[i] = isl_morph_basic_set(isl_morph_copy(morph), set->p[i]); if (!set->p[i]) goto error; } isl_morph_free(morph); ISL_F_CLR(set, ISL_SET_NORMALIZED); return set; error: isl_set_free(set); isl_morph_free(morph); return NULL; }
void free_poly_dr (poly_dr_p pdr) { isl_map_free (pdr->accesses); isl_set_free (pdr->subscript_sizes); XDELETE (pdr); }
CloogInput *Cloog::buildCloogInput() { // XXX: We do not copy the context of the scop, but use an unconstrained // context. This 'hack' is necessary as the context may contain bounds // on parameters such as [n] -> {:0 <= n < 2^32}. Those large // integers will cause CLooG to construct a clast that contains // expressions that include these large integers. Such expressions can // possibly not be evaluated correctly with i64 types. The cloog // based code generation backend, however, can not derive types // automatically and just assumes i64 types. Hence, it will break or // generate incorrect code. // This hack does not remove all possibilities of incorrectly generated // code, but it is ensures that for most problems the problems do not // show up. The correct solution, will be to automatically derive the // minimal types for each expression. This could be added to CLooG and it // will be available in the isl based code generation. isl_set *EmptyContext = isl_set_universe(S->getParamSpace()); CloogDomain *Context = cloog_domain_from_isl_set(EmptyContext); CloogUnionDomain *Statements = buildCloogUnionDomain(); isl_set *ScopContext = S->getContext(); for (unsigned i = 0; i < isl_set_dim(ScopContext, isl_dim_param); i++) { isl_id *id = isl_set_get_dim_id(ScopContext, isl_dim_param, i); Statements = cloog_union_domain_set_name(Statements, CLOOG_PARAM, i, isl_id_get_name(id)); isl_id_free(id); } isl_set_free(ScopContext); CloogInput *Input = cloog_input_alloc(Context, Statements); return Input; }
/* Insert an if node around "node" testing the condition encoded * in guard "guard". * * If the user does not want any disjunctions in the if conditions * and if "guard" does involve a disjunction, then we make the different * disjuncts disjoint and insert an if node corresponding to each disjunct * around a copy of "node". The result is then a block node containing * this sequence of guarded copies of "node". */ static __isl_give isl_ast_node *ast_node_insert_if( __isl_take isl_ast_node *node, __isl_take isl_set *guard, __isl_keep isl_ast_build *build) { struct isl_insert_if_data data; isl_ctx *ctx; ctx = isl_ast_build_get_ctx(build); if (isl_options_get_ast_build_allow_or(ctx) || isl_set_n_basic_set(guard) <= 1) { isl_ast_node *if_node; isl_ast_expr *expr; expr = isl_ast_build_expr_from_set_internal(build, guard); if_node = isl_ast_node_alloc_if(expr); return isl_ast_node_if_set_then(if_node, node); } guard = isl_set_make_disjoint(guard); data.list = isl_ast_node_list_alloc(ctx, 0); data.node = node; data.build = build; if (isl_set_foreach_basic_set(guard, &insert_if, &data) < 0) data.list = isl_ast_node_list_free(data.list); isl_set_free(guard); isl_ast_node_free(data.node); return isl_ast_node_alloc_block(data.list); }
/* Used by libpluto interface */ static int extract_stmt(__isl_take isl_set *set, void *user) { int r; Stmt **stmts; int id, i; stmts = (Stmt **) user; int dim = isl_set_dim(set, isl_dim_all); int npar = isl_set_dim(set, isl_dim_param); PlutoMatrix *trans = pluto_matrix_alloc(dim-npar, dim+1); pluto_matrix_set(trans, 0); trans->nrows = 0; /* A statement's domain (isl_set) should be named S_%d */ const char *name = isl_set_get_tuple_name(set); assert(name); assert(strlen(name) >= 3); assert(name[0] == 'S'); assert(name[1] == '_'); assert(isdigit(name[2])); id = atoi(isl_set_get_tuple_name(set)+2); stmts[id] = pluto_stmt_alloc(dim-npar, NULL, trans); Stmt *stmt = stmts[id]; stmt->type = ORIG; stmt->id = id; for (i=0; i<stmt->dim; i++) { char *iter = malloc(5); sprintf(iter, "i%d", i); stmt->iterators[i] = iter; } struct pluto_extra_stmt_info info = {stmts, id}; r = isl_set_foreach_basic_set(set, &extract_basic_set, &info); pluto_constraints_set_names_range(stmt->domain, stmt->iterators, 0, 0, stmt->dim); for (i=0; i<npar; i++) { char *param = malloc(5); sprintf(param, "p%d", i); stmt->domain->names[stmt->dim+i] = param; } pluto_matrix_free(trans); int j; for (j=0; j<stmt->dim; j++) { stmt->is_orig_loop[j] = true; } isl_set_free(set); return r; }
/* Given an array, check whether its positive size guard expression is * trivial. */ static int is_array_positive_size_guard_trivial(struct gpu_array_info *array) { isl_set *guard; int is_trivial; guard = gpu_array_positive_size_guard(array); is_trivial = isl_set_plain_is_universe(guard); isl_set_free(guard); return is_trivial; }
int isl_set_scan(__isl_take isl_set *set, struct isl_scan_callback *callback) { int i; if (!set || !callback) goto error; set = isl_set_cow(set); set = isl_set_make_disjoint(set); set = isl_set_compute_divs(set); if (!set) goto error; for (i = 0; i < set->n; ++i) if (isl_basic_set_scan(isl_basic_set_copy(set->p[i]), callback) < 0) goto error; isl_set_free(set); return 0; error: isl_set_free(set); return -1; }
/* If the isl_pw_aff on which isl_pw_aff_foreach_piece is called * has a constant expression on its only domain, then replace * the isl_val in *user by this constant. * The caller is assumed to have checked that this function will * be called exactly once. */ static isl_stat extract_cst(__isl_take isl_set *set, __isl_take isl_aff *aff, void *user) { isl_val **inc = (isl_val **)user; if (isl_aff_is_cst(aff)) { isl_val_free(*inc); *inc = isl_aff_get_constant_val(aff); } isl_set_free(set); isl_aff_free(aff); return isl_stat_ok; }
/// Translate a isl_set to a ScopLib matrix. /// /// @param PS The set to be translated /// @return A ScopLib Matrix scoplib_matrix_p ScopLib::domainToMatrix(__isl_take isl_set *set) { set = isl_set_compute_divs (set); set = isl_set_align_divs (set); // Initialize the matrix. unsigned NbRows, NbColumns; NbRows = 0; NbColumns = isl_set_n_dim(set) + isl_set_n_param(set) + 2; scoplib_matrix_p matrix = scoplib_matrix_malloc(NbRows, NbColumns); // Copy the content into the matrix. isl_set_foreach_basic_set(set, &domainToMatrix_basic_set, matrix); isl_set_free(set); return matrix; }
/* Check if the constraints in "map" imply any stride on output dimension "pos", * independently of any other output dimensions, and * return the results in the form of an offset and a stride. * * Convert the input to a set with only the input dimensions and * the single output dimension such that it be passed to * isl_set_get_stride_info and convert the result back to * an expression defined over the domain of "map". */ __isl_give isl_stride_info *isl_map_get_range_stride_info( __isl_keep isl_map *map, int pos) { isl_stride_info *si; isl_set *set; map = isl_map_copy(map); map = isl_map_project_onto(map, isl_dim_out, pos, 1); pos = isl_map_dim(map, isl_dim_in); set = isl_map_wrap(map); si = isl_set_get_stride_info(set, pos); isl_set_free(set); if (!si) return NULL; si->offset = isl_aff_domain_factor_domain(si->offset); if (!si->offset) return isl_stride_info_free(si); return si; }
/* Construct a unique identifier for a group in "grouping". * * The name is of the form G_n, with n the first value starting at * grouping->group_id that does not result in an identifier * that is already in use in the domain of the original schedule * constraints. */ static isl_id *construct_group_id(struct ppcg_grouping *grouping, __isl_take isl_space *space) { isl_ctx *ctx; isl_id *id; isl_bool empty; isl_union_set *domain; if (!space) return NULL; ctx = isl_space_get_ctx(space); domain = isl_schedule_constraints_get_domain(grouping->sc); do { char buffer[20]; isl_id *id; isl_set *set; snprintf(buffer, sizeof(buffer), "G_%d", grouping->group_id); grouping->group_id++; id = isl_id_alloc(ctx, buffer, NULL); space = isl_space_set_tuple_id(space, isl_dim_set, id); set = isl_union_set_extract_set(domain, isl_space_copy(space)); empty = isl_set_plain_is_empty(set); isl_set_free(set); } while (empty >= 0 && !empty); if (empty < 0) space = isl_space_free(space); id = isl_space_get_tuple_id(space, isl_dim_set); isl_space_free(space); isl_union_set_free(domain); return id; }
static void pdr_stride_in_loop (mpz_t stride, graphite_dim_t depth, poly_dr_p pdr) { poly_bb_p pbb = PDR_PBB (pdr); isl_map *map; isl_set *set; isl_aff *aff; isl_space *dc; isl_constraint *lma, *c; isl_int islstride; graphite_dim_t time_depth; unsigned offset, nt; unsigned i; /* XXX isl rewrite following comments. */ /* Builds a partial difference equations and inserts them into pointset powerset polyhedron P. Polyhedron is assumed to have the format: T|I|T'|I'|G|S|S'|l1|l2. TIME_DEPTH is the time dimension w.r.t. which we are differentiating. OFFSET represents the number of dimensions between columns t_{time_depth} and t'_{time_depth}. DIM_SCTR is the number of scattering dimensions. It is essentially the dimensionality of the T vector. The following equations are inserted into the polyhedron P: | t_1 = t_1' | ... | t_{time_depth-1} = t'_{time_depth-1} | t_{time_depth} = t'_{time_depth} + 1 | t_{time_depth+1} = t'_{time_depth + 1} | ... | t_{dim_sctr} = t'_{dim_sctr}. */ /* Add the equality: t_{time_depth} = t'_{time_depth} + 1. This is the core part of this alogrithm, since this constraint asks for the memory access stride (difference) between two consecutive points in time dimensions. */ /* Add equalities: | t1 = t1' | ... | t_{time_depth-1} = t'_{time_depth-1} | t_{time_depth+1} = t'_{time_depth+1} | ... | t_{dim_sctr} = t'_{dim_sctr} This means that all the time dimensions are equal except for time_depth, where the constraint is t_{depth} = t'_{depth} + 1 step. More to this: we should be careful not to add equalities to the 'coupled' dimensions, which happens when the one dimension is stripmined dimension, and the other dimension corresponds to the point loop inside stripmined dimension. */ /* pdr->accesses: [P1..nb_param,I1..nb_domain]->[a,S1..nb_subscript] ??? [P] not used for PDRs? pdr->extent: [a,S1..nb_subscript] pbb->domain: [P1..nb_param,I1..nb_domain] pbb->transformed: [P1..nb_param,I1..nb_domain]->[T1..Tnb_sctr] [T] includes local vars (currently unused) First we create [P,I] -> [T,a,S]. */ map = isl_map_flat_range_product (isl_map_copy (pbb->transformed), isl_map_copy (pdr->accesses)); /* Add a dimension for L: [P,I] -> [T,a,S,L].*/ map = isl_map_add_dims (map, isl_dim_out, 1); /* Build a constraint for "lma[S] - L == 0", effectively calculating L in terms of subscripts. */ lma = build_linearized_memory_access (map, pdr); /* And add it to the map, so we now have: [P,I] -> [T,a,S,L] : lma([S]) == L. */ map = isl_map_add_constraint (map, lma); /* Then we create [P,I,P',I'] -> [T,a,S,L,T',a',S',L']. */ map = isl_map_flat_product (map, isl_map_copy (map)); /* Now add the equality T[time_depth] == T'[time_depth]+1. This will force L' to be the linear address at T[time_depth] + 1. */ time_depth = psct_dynamic_dim (pbb, depth); /* Length of [a,S] plus [L] ... */ offset = 1 + isl_map_dim (pdr->accesses, isl_dim_out); /* ... plus [T]. */ offset += isl_map_dim (pbb->transformed, isl_dim_out); c = isl_equality_alloc (isl_local_space_from_space (isl_map_get_space (map))); c = isl_constraint_set_coefficient_si (c, isl_dim_out, time_depth, 1); c = isl_constraint_set_coefficient_si (c, isl_dim_out, offset + time_depth, -1); c = isl_constraint_set_constant_si (c, 1); map = isl_map_add_constraint (map, c); /* Now we equate most of the T/T' elements (making PITaSL nearly the same is (PITaSL)', except for one dimension, namely for 'depth' (an index into [I]), after translating to index into [T]. Take care to not produce an empty map, which indicates we wanted to equate two dimensions that are already coupled via the above time_depth dimension. Happens with strip mining where several scatter dimension are interdependend. */ /* Length of [T]. */ nt = pbb_nb_scattering_transform (pbb) + pbb_nb_local_vars (pbb); for (i = 0; i < nt; i++) if (i != time_depth) { isl_map *temp = isl_map_equate (isl_map_copy (map), isl_dim_out, i, isl_dim_out, offset + i); if (isl_map_is_empty (temp)) isl_map_free (temp); else { isl_map_free (map); map = temp; } } /* Now maximize the expression L' - L. */ set = isl_map_range (map); dc = isl_set_get_space (set); aff = isl_aff_zero_on_domain (isl_local_space_from_space (dc)); aff = isl_aff_set_coefficient_si (aff, isl_dim_in, offset - 1, -1); aff = isl_aff_set_coefficient_si (aff, isl_dim_in, offset + offset - 1, 1); isl_int_init (islstride); isl_set_max (set, aff, &islstride); isl_int_get_gmp (islstride, stride); isl_int_clear (islstride); isl_aff_free (aff); isl_set_free (set); if (dump_file && (dump_flags & TDF_DETAILS)) { char *str; void (*gmp_free) (void *, size_t); fprintf (dump_file, "\nStride in BB_%d, DR_%d, depth %d:", pbb_index (pbb), PDR_ID (pdr), (int) depth); str = mpz_get_str (0, 10, stride); fprintf (dump_file, " %s ", str); mp_get_memory_functions (NULL, NULL, &gmp_free); (*gmp_free) (str, strlen (str) + 1); } }
static void isl_obj_set_free(void *v) { isl_set_free((struct isl_set *)v); }
void destroy_solver (void) { if (solution != 0) isl_point_free (solution); if (solutions != 0) isl_set_free (solutions); isl_local_space_free (ls); isl_ctx_free (context); }