select "best" lower bound for unrolling
[cloog/uuh.git] / source / isl / domain.c
blob67f0458d847d7a2866d3e4c11badf47f3e3b5422
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <ctype.h>
6 #include <cloog/isl/cloog.h>
7 #include <isl/list.h>
8 #include <isl/constraint.h>
9 #include <isl/ilp.h>
10 #include <isl/aff.h>
12 CloogDomain *cloog_domain_from_isl_set(struct isl_set *set)
14 set = isl_set_detect_equalities(set);
15 set = isl_set_compute_divs(set);
16 return (CloogDomain *)set;
19 __isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain)
21 return (isl_set *)domain;
24 CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map)
26 return (CloogScattering *)map;
29 __isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering)
31 return (isl_map *)scattering;
35 /**
36 * Returns true if each scattering dimension is defined in terms
37 * of the original iterators.
39 int cloog_scattering_fully_specified(CloogScattering *scattering,
40 CloogDomain *domain)
42 isl_map *map = isl_map_from_cloog_scattering(scattering);
43 return isl_map_is_single_valued(map);
47 CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain)
49 isl_basic_set *bset;
50 isl_set *set = isl_set_from_cloog_domain(domain);
51 assert(isl_set_n_basic_set(set) == 1);
52 bset = isl_set_copy_basic_set(set);
53 return cloog_constraint_set_from_isl_basic_set(bset);
57 void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain,
58 int print_number)
60 isl_basic_set *bset;
61 isl_set *set = isl_set_from_cloog_domain(domain);
63 if (print_number)
64 isl_set_print(set, foo, 0, ISL_FORMAT_EXT_POLYLIB);
65 else {
66 assert(isl_set_n_basic_set(set) == 1);
67 bset = isl_set_copy_basic_set(set);
68 isl_basic_set_print(bset, foo,
69 0, NULL, NULL, ISL_FORMAT_POLYLIB);
70 isl_basic_set_free(bset);
75 void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering)
77 isl_map *map = isl_map_from_cloog_scattering(scattering);
78 isl_map_print(map, foo, 0, ISL_FORMAT_EXT_POLYLIB);
82 void cloog_domain_free(CloogDomain * domain)
84 isl_set *set = isl_set_from_cloog_domain(domain);
85 isl_set_free(set);
89 void cloog_scattering_free(CloogScattering *scatt)
91 isl_map *map = isl_map_from_cloog_scattering(scatt);
92 isl_map_free(map);
96 CloogDomain * cloog_domain_copy(CloogDomain * domain)
98 isl_set *set = isl_set_from_cloog_domain(domain);
99 return cloog_domain_from_isl_set(isl_set_copy(set));
104 * cloog_domain_convex function:
105 * Computes the convex hull of domain.
107 CloogDomain *cloog_domain_convex(CloogDomain *domain)
109 isl_set *set = isl_set_from_cloog_domain(domain);
110 set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set)));
111 return cloog_domain_from_isl_set(set);
116 * cloog_domain_simple_convex:
117 * Given a list (union) of polyhedra, this function returns a "simple"
118 * convex hull of this union. In particular, the constraints of the
119 * the returned polyhedron consist of (parametric) lower and upper
120 * bounds on individual variables and constraints that appear in the
121 * original polyhedra.
123 CloogDomain *cloog_domain_simple_convex(CloogDomain *domain)
125 struct isl_basic_set *hull;
126 isl_set *set = isl_set_from_cloog_domain(domain);
128 if (cloog_domain_isconvex(domain))
129 return cloog_domain_copy(domain);
131 hull = isl_set_bounded_simple_hull(isl_set_copy(set));
132 return cloog_domain_from_isl_set(isl_set_from_basic_set(hull));
137 * cloog_domain_simplify function:
138 * Given two polyhedral domains (dom1) and (dom2),
139 * this function finds the largest domain set (or the smallest list
140 * of non-redundant constraints), that when intersected with polyhedral
141 * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain
142 * structure with a polyhedral domain with the "redundant" constraints removed.
143 * NB: the second domain is required not to be a union.
145 CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2)
147 isl_set *set1 = isl_set_from_cloog_domain(dom1);
148 isl_set *set2 = isl_set_from_cloog_domain(dom2);
149 set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2));
150 return cloog_domain_from_isl_set(set1);
155 * cloog_domain_union function:
156 * This function returns a new polyhedral domain which is the union of
157 * two polyhedral domains (dom1) U (dom2).
158 * Frees dom1 and dom2;
160 CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2)
162 isl_set *set1 = isl_set_from_cloog_domain(dom1);
163 isl_set *set2 = isl_set_from_cloog_domain(dom2);
164 set1 = isl_set_union(set1, set2);
165 return cloog_domain_from_isl_set(set1);
171 * cloog_domain_intersection function:
172 * This function returns a new polyhedral domain which is the intersection of
173 * two polyhedral domains (dom1) \cap (dom2).
175 CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2)
177 isl_set *set1 = isl_set_from_cloog_domain(dom1);
178 isl_set *set2 = isl_set_from_cloog_domain(dom2);
179 set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2));
180 return cloog_domain_from_isl_set(set1);
185 * cloog_domain_difference function:
186 * Returns the set difference domain \ minus.
188 CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus)
190 isl_set *set1 = isl_set_from_cloog_domain(domain);
191 isl_set *set2 = isl_set_from_cloog_domain(minus);
192 set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2));
193 return cloog_domain_from_isl_set(set1);
198 * cloog_domain_sort function:
199 * This function topologically sorts (nb_doms) domains. Here (doms) is an
200 * array of pointers to CloogDomains, (nb_doms) is the number of domains,
201 * (level) is the level to consider for partial ordering (nb_par) is the
202 * parameter space dimension, (permut) if not NULL, is an array of (nb_doms)
203 * integers that contains a permutation specification after call in order to
204 * apply the topological sorting.
206 void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level,
207 int *permut)
209 int i, j, k, cmp;
210 struct isl_ctx *ctx;
211 unsigned char **follows;
212 isl_set *set_i, *set_j;
213 isl_basic_set *bset_i, *bset_j;
215 if (!nb_doms)
216 return;
217 set_i = isl_set_from_cloog_domain(doms[0]);
218 ctx = isl_set_get_ctx(set_i);
219 for (i = 0; i < nb_doms; i++) {
220 set_i = isl_set_from_cloog_domain(doms[i]);
221 assert(isl_set_n_basic_set(set_i) == 1);
224 follows = isl_alloc_array(ctx, unsigned char *, nb_doms);
225 assert(follows);
226 for (i = 0; i < nb_doms; ++i) {
227 follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms);
228 assert(follows[i]);
229 for (j = 0; j < nb_doms; ++j)
230 follows[i][j] = 0;
233 for (i = 1; i < nb_doms; ++i) {
234 for (j = 0; j < i; ++j) {
235 if (follows[i][j] || follows[j][i])
236 continue;
237 set_i = isl_set_from_cloog_domain(doms[i]);
238 set_j = isl_set_from_cloog_domain(doms[j]);
239 bset_i = isl_set_copy_basic_set(set_i);
240 bset_j = isl_set_copy_basic_set(set_j);
241 cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1);
242 isl_basic_set_free(bset_i);
243 isl_basic_set_free(bset_j);
244 if (!cmp)
245 continue;
246 if (cmp > 0) {
247 follows[i][j] = 1;
248 for (k = 0; k < i; ++k)
249 follows[i][k] |= follows[j][k];
250 } else {
251 follows[j][i] = 1;
252 for (k = 0; k < i; ++k)
253 follows[k][i] |= follows[k][j];
258 for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) {
259 for (k = 0; k < nb_doms; ++k)
260 if (follows[j][k])
261 break;
262 if (k < nb_doms)
263 continue;
264 for (k = 0; k < nb_doms; ++k)
265 follows[k][j] = 0;
266 follows[j][j] = 1;
267 permut[i] = 1 + j;
268 ++i;
271 for (i = 0; i < nb_doms; ++i)
272 free(follows[i]);
273 free(follows);
278 * Check whether there is or may be any value of dom1 at the given level
279 * that is greater than or equal to a value of dom2 at the same level.
281 * Return
282 * 1 is there is or may be a greater-than pair.
283 * 0 if there is no greater-than pair, but there may be an equal-to pair
284 * -1 if there is definitely no such pair
286 int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level)
288 isl_set *set1 = isl_set_from_cloog_domain(dom1);
289 isl_set *set2 = isl_set_from_cloog_domain(dom2);
290 int follows;
292 follows = isl_set_follows_at(set1, set2, level - 1);
293 assert(follows >= -1);
295 return follows;
300 * cloog_domain_empty function:
301 * Returns an empty domain of the same dimensions as template.
303 CloogDomain *cloog_domain_empty(CloogDomain *template)
305 isl_set *set = isl_set_from_cloog_domain(template);
306 return cloog_domain_from_isl_set(isl_set_empty_like(set));
311 * Return 1 if the specified dimension has both an upper and a lower bound.
313 int cloog_domain_is_bounded(CloogDomain *dom, unsigned level)
315 isl_set *set = isl_set_from_cloog_domain(dom);
316 return isl_set_dim_is_bounded(set, isl_dim_set, level - 1);
320 /******************************************************************************
321 * Structure display function *
322 ******************************************************************************/
326 * cloog_domain_print_structure :
327 * this function is a more human-friendly way to display the CloogDomain data
328 * structure, it only shows the constraint system and includes an indentation
329 * level (level) in order to work with others print_structure functions.
331 void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level,
332 const char *name)
334 int i ;
335 isl_set *set = isl_set_from_cloog_domain(domain);
337 /* Go to the right level. */
338 for (i = 0; i < level; i++)
339 fprintf(file, "|\t");
341 if (!set) {
342 fprintf(file, "+-- Null CloogDomain\n");
343 return;
345 fprintf(file, "+-- %s\n", name);
346 for (i = 0; i < level+1; ++i)
347 fprintf(file, "|\t");
349 isl_set_print(set, file, 0, ISL_FORMAT_ISL);
351 fprintf(file, "\n");
355 /******************************************************************************
356 * Memory deallocation function *
357 ******************************************************************************/
360 void cloog_domain_list_free(CloogDomainList *list)
362 CloogDomainList *next;
364 for ( ; list; list = next) {
365 next = list->next;
366 cloog_domain_free(list->domain);
367 free(list);
373 * cloog_scattering_list_free function:
374 * This function frees the allocated memory for a CloogScatteringList structure.
376 void cloog_scattering_list_free(CloogScatteringList *list)
378 while (list != NULL) {
379 CloogScatteringList *temp = list->next;
380 isl_map *map = isl_map_from_cloog_scattering(list->scatt);
381 isl_map_free(map);
382 free(list);
383 list = temp;
388 /******************************************************************************
389 * Reading function *
390 ******************************************************************************/
394 * cloog_domain_read_context function:
395 * Read parameter domain.
397 CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input)
399 struct isl_ctx *ctx = state->backend->ctx;
400 isl_set *set;
402 set = isl_set_read_from_file(ctx, input);
403 set = isl_set_move_dims(set, isl_dim_param, 0,
404 isl_dim_set, 0, isl_set_dim(set, isl_dim_set));
406 return cloog_domain_from_isl_set(set);
411 * cloog_domain_from_context
412 * Reinterpret context by turning parameters into variables.
414 CloogDomain *cloog_domain_from_context(CloogDomain *context)
416 isl_set *set = isl_set_from_cloog_domain(context);
418 set = isl_set_move_dims(set, isl_dim_set, 0,
419 isl_dim_param, 0, isl_set_dim(set, isl_dim_param));
421 return cloog_domain_from_isl_set(set);
426 * cloog_domain_union_read function:
427 * This function reads a union of polyhedra into a file (input) and
428 * returns a pointer to a CloogDomain containing the read information.
430 CloogDomain *cloog_domain_union_read(CloogState *state,
431 FILE *input, int nb_parameters)
433 struct isl_ctx *ctx = state->backend->ctx;
434 struct isl_set *set;
436 set = isl_set_read_from_file(ctx, input);
437 if (isl_set_dim(set, isl_dim_param) != nb_parameters) {
438 int dim = isl_set_dim(set, isl_dim_set);
439 set = isl_set_move_dims(set, isl_dim_param, 0,
440 isl_dim_set, dim - nb_parameters, nb_parameters);
442 return cloog_domain_from_isl_set(set);
447 * cloog_domain_read_scattering function:
448 * This function reads in a scattering function from the file input.
450 * We try to read the scattering relation as a map, but if it is
451 * specified in the original PolyLib format, then isl_map_read_from_file
452 * will treat the input as a set return a map with zero input dimensions.
453 * In this case, we need to decompose the set into a map from
454 * scattering dimensions to domain dimensions and then invert the
455 * resulting map.
457 CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input)
459 isl_set *set = isl_set_from_cloog_domain(domain);
460 isl_ctx *ctx = isl_set_get_ctx(set);
461 struct isl_map *scat;
462 unsigned nparam;
463 unsigned dim;
464 unsigned n_scat;
466 dim = isl_set_dim(set, isl_dim_set);
467 nparam = isl_set_dim(set, isl_dim_param);
468 scat = isl_map_read_from_file(ctx, input);
469 if (isl_map_dim(scat, isl_dim_param) != nparam) {
470 int n_out = isl_map_dim(scat, isl_dim_out);
471 scat = isl_map_move_dims(scat, isl_dim_param, 0,
472 isl_dim_out, n_out - nparam, nparam);
474 if (isl_map_dim(scat, isl_dim_in) != dim) {
475 n_scat = isl_map_dim(scat, isl_dim_out) - dim;
476 scat = isl_map_move_dims(scat, isl_dim_in, 0,
477 isl_dim_out, n_scat, dim);
479 return cloog_scattering_from_isl_map(scat);
482 /******************************************************************************
483 * CloogMatrix Reading function *
484 ******************************************************************************/
487 * isl_constraint_read_from_matrix:
488 * Convert a single line of a matrix to a isl_constraint.
489 * Returns a pointer to the constraint if successful; NULL otherwise.
491 static struct isl_constraint *isl_constraint_read_from_matrix(
492 struct isl_space *dim, cloog_int_t *row)
494 struct isl_constraint *constraint;
495 int j;
496 int nvariables = isl_space_dim(dim, isl_dim_set);
497 int nparam = isl_space_dim(dim, isl_dim_param);
498 isl_local_space *ls = isl_local_space_from_space(dim);
500 if (cloog_int_is_zero(row[0]))
501 constraint = isl_equality_alloc(ls);
502 else
503 constraint = isl_inequality_alloc(ls);
505 for (j = 0; j < nvariables; ++j)
506 isl_constraint_set_coefficient(constraint, isl_dim_out, j,
507 row[1 + j]);
509 for (j = 0; j < nparam; ++j)
510 isl_constraint_set_coefficient(constraint, isl_dim_param, j,
511 row[1 + nvariables + j]);
513 isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]);
515 return constraint;
519 * isl_basic_set_read_from_matrix:
520 * Convert matrix to basic_set. The matrix contains nparam parameter columns.
521 * Returns a pointer to the basic_set if successful; NULL otherwise.
523 static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx,
524 CloogMatrix* matrix, int nparam)
526 struct isl_space *dim;
527 struct isl_basic_set *bset;
528 int i;
529 unsigned nrows, ncolumns;
531 nrows = matrix->NbRows;
532 ncolumns = matrix->NbColumns;
533 int nvariables = ncolumns - 2 - nparam;
535 dim = isl_space_set_alloc(ctx, nparam, nvariables);
537 bset = isl_basic_set_universe(isl_space_copy(dim));
539 for (i = 0; i < nrows; ++i) {
540 cloog_int_t *row = matrix->p[i];
541 struct isl_constraint *constraint =
542 isl_constraint_read_from_matrix(isl_space_copy(dim), row);
543 bset = isl_basic_set_add_constraint(bset, constraint);
546 isl_space_free(dim);
548 return bset;
552 * cloog_domain_from_cloog_matrix:
553 * Create a CloogDomain containing the constraints described in matrix.
554 * nparam is the number of parameters contained in the domain.
555 * Returns a pointer to the CloogDomain if successful; NULL otherwise.
557 CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state,
558 CloogMatrix *matrix, int nparam)
560 struct isl_ctx *ctx = state->backend->ctx;
561 struct isl_basic_set *bset;
563 bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam);
565 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
569 * cloog_scattering_from_cloog_matrix:
570 * Create a CloogScattering containing the constraints described in matrix.
571 * nparam is the number of parameters contained in the domain.
572 * Returns a pointer to the CloogScattering if successful; NULL otherwise.
574 CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state,
575 CloogMatrix *matrix, int nb_scat, int nb_par)
577 struct isl_ctx *ctx = state->backend->ctx;
578 struct isl_basic_set *bset;
579 struct isl_basic_map *scat;
580 struct isl_space *dims;
581 unsigned dim;
583 bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par);
584 dim = isl_basic_set_n_dim(bset) - nb_scat;
585 dims = isl_space_alloc(ctx, nb_par, nb_scat, dim);
587 scat = isl_basic_map_from_basic_set(bset, dims);
588 scat = isl_basic_map_reverse(scat);
589 return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat));
593 /******************************************************************************
594 * Processing functions *
595 ******************************************************************************/
600 * cloog_domain_isempty function:
602 int cloog_domain_isempty(CloogDomain *domain)
604 isl_set *set = isl_set_from_cloog_domain(domain);
605 return isl_set_is_empty(set);
610 * cloog_domain_universe function:
611 * This function returns the complete dim-dimensional space.
613 CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim)
615 struct isl_space *dims;
616 struct isl_basic_set *bset;
618 dims = isl_space_set_alloc(state->backend->ctx, 0, dim);
619 bset = isl_basic_set_universe(dims);
620 return cloog_domain_from_isl_set(isl_set_from_basic_set(bset));
625 * cloog_domain_project function:
626 * This function returns the projection of
627 * (domain) on the (level) first dimensions (i.e. outer loops).
629 CloogDomain *cloog_domain_project(CloogDomain *domain, int level)
631 isl_set *set = isl_set_from_cloog_domain(domain);
632 set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set,
633 level, isl_set_n_dim(set) - level);
634 set = isl_set_compute_divs(set);
635 if (level > 0)
636 set = isl_set_remove_divs_involving_dims(set,
637 isl_dim_set, level - 1, 1);
638 return cloog_domain_from_isl_set(set);
643 * cloog_domain_extend function:
644 * This function returns the (domain) given as input with (dim)
645 * dimensions and (nb_par) parameters.
646 * This function does not free (domain), and returns a new CloogDomain.
648 CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim)
650 isl_set *set = isl_set_from_cloog_domain(domain);
651 int n = isl_set_dim(set, isl_dim_set);
652 set = isl_set_add_dims(isl_set_copy(set), isl_dim_set, dim - n);
653 return cloog_domain_from_isl_set(set);
658 * cloog_domain_never_integral function:
659 * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0.
660 * There is no need to check for such constraints explicitly for the isl
661 * backend.
663 int cloog_domain_never_integral(CloogDomain * domain)
665 isl_set *set = isl_set_from_cloog_domain(domain);
666 return isl_set_is_empty(set);
671 * Check whether the loop at "level" is executed at most once.
672 * We construct a map that maps all remaining variables to this iterator
673 * and check whether this map is single valued.
675 * Alternatively, we could have mapped the domain through a mapping
676 * [p] -> { [..., i] -> [..., i'] : i' > i }
677 * and then taken the intersection of the original domain and the transformed
678 * domain. If this intersection is empty, then the corresponding
679 * loop is executed at most once.
681 int cloog_domain_is_otl(CloogDomain *domain, int level)
683 int otl;
684 isl_set *set = isl_set_from_cloog_domain(domain);
685 isl_map *map;
687 map = isl_map_from_domain(isl_set_copy(set));
688 map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1);
689 otl = isl_map_is_single_valued(map);
690 isl_map_free(map);
692 return otl;
697 * cloog_domain_stride function:
698 * This function finds the stride imposed to unknown with the column number
699 * 'strided_level' in order to be integral. For instance, if we have a
700 * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral
701 * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to
702 * the unknown i. The function returns the imposed stride in a parameter field.
703 * - domain is the set of constraint we have to consider,
704 * - strided_level is the column number of the unknown for which a stride have
705 * to be found,
706 * - looking_level is the column number of the unknown that impose a stride to
707 * the first unknown.
708 * - stride is the stride that is returned back as a function parameter.
709 * - offset is the value of the constant c if the condition is of the shape
710 * (i + c)%s = 0, s being the stride.
712 void cloog_domain_stride(CloogDomain *domain, int strided_level,
713 cloog_int_t *stride, cloog_int_t *offset)
715 isl_set *set = isl_set_from_cloog_domain(domain);
716 isl_set_dim_residue_class(set, strided_level - 1, stride, offset);
717 if (!isl_int_is_zero(*offset))
718 isl_int_sub(*offset, *stride, *offset);
719 return;
723 struct cloog_can_stride {
724 int level;
725 int can_stride;
728 static int constraint_can_stride(__isl_take isl_constraint *c, void *user)
730 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
731 int i;
732 isl_int v;
733 unsigned n_div;
735 if (isl_constraint_is_equality(c)) {
736 isl_constraint_free(c);
737 return 0;
740 isl_int_init(v);
741 isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v);
742 if (isl_int_is_pos(v)) {
743 n_div = isl_constraint_dim(c, isl_dim_div);
744 for (i = 0; i < n_div; ++i) {
745 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
746 if (!isl_int_is_zero(v))
747 break;
749 if (i < n_div)
750 ccs->can_stride = 0;
752 isl_int_clear(v);
753 isl_constraint_free(c);
755 return 0;
758 static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user)
760 struct cloog_can_stride *ccs = (struct cloog_can_stride *)user;
761 int r;
763 r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs);
764 isl_basic_set_free(bset);
765 return r;
770 * Return 1 if CLooG is allowed to perform stride detection on level "level"
771 * and 0 otherwise.
772 * Currently, stride detection is only allowed when none of the lower
773 * bound constraints involve any existentially quantified variables.
774 * The reason is that the current isl interface does not make it
775 * easy to construct an integer division that depends on other integer
776 * divisions.
777 * By not allowing existentially quantified variables in the constraints,
778 * we can ignore them in cloog_domain_stride_lower_bound.
780 int cloog_domain_can_stride(CloogDomain *domain, int level)
782 struct cloog_can_stride ccs = { level, 1 };
783 isl_set *set = isl_set_from_cloog_domain(domain);
784 int r;
785 r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs);
786 assert(r == 0);
787 return ccs.can_stride;
791 struct cloog_stride_lower {
792 int level;
793 CloogStride *stride;
794 isl_set *set;
795 isl_basic_set *bounds;
798 /* If the given constraint is a lower bound on csl->level, then add
799 * a lower bound to csl->bounds that makes sure that the remainder
800 * of the smallest value on division by csl->stride is equal to csl->offset.
802 * In particular, the given lower bound is of the form
804 * a i + f >= 0
806 * where f may depend on the parameters and other iterators.
807 * The stride is s and the offset is d.
808 * The lower bound -f/a may not satisfy the above condition. In fact,
809 * it may not even be integral. We want to round this value of i up
810 * to the nearest value that satisfies the condition and add the corresponding
811 * lower bound constraint. This nearest value is obtained by rounding
812 * i - d up to the nearest multiple of s.
813 * That is, we first subtract d
815 * i' = -f/a - d
817 * then we round up to the nearest multiple of s
819 * i'' = s * ceil(i'/s)
821 * and finally, we add d again
823 * i''' = i'' + d
825 * and impose the constraint i >= i'''.
827 * We find
829 * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s))
831 * i >= - s * floor((f + a * d)/(a * s)) + d
833 * or
834 * i + s * floor((f + a * d)/(a * s)) - d >= 0
836 static int constraint_stride_lower(__isl_take isl_constraint *c, void *user)
838 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
839 isl_int v;
840 isl_constraint *bound;
841 isl_aff *b;
843 if (isl_constraint_is_equality(c)) {
844 isl_constraint_free(c);
845 return 0;
848 isl_int_init(v);
849 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
850 if (!isl_int_is_pos(v)) {
851 isl_int_clear(v);
852 isl_constraint_free(c);
854 return 0;
857 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
859 b = isl_aff_neg(b);
860 b = isl_aff_add_constant(b, csl->stride->offset);
861 b = isl_aff_scale_down(b, csl->stride->stride);
862 b = isl_aff_floor(b);
863 b = isl_aff_scale(b, csl->stride->stride);
864 isl_int_neg(v, csl->stride->offset);
865 b = isl_aff_add_constant(b, v);
866 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
868 bound = isl_inequality_from_aff(b);
870 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
872 isl_int_clear(v);
873 isl_constraint_free(c);
875 return 0;
878 /* This functions performs essentially the same operation as
879 * constraint_stride_lower, the only difference being that the offset d
880 * is not a constant, but an affine expression in terms of the parameters
881 * and earlier variables. In particular the affine expression is equal
882 * to the coefficients of stride->constraint multiplied by stride->factor.
883 * As in constraint_stride_lower, we add an extra bound
885 * i + s * floor((f + a * d)/(a * s)) - d >= 0
887 * for each lower bound
889 * a i + f >= 0
891 * where d is not the aforementioned affine expression.
893 static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user)
895 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
896 isl_int v;
897 isl_constraint *bound;
898 isl_constraint *csl_c;
899 isl_aff *d, *b;
901 if (isl_constraint_is_equality(c)) {
902 isl_constraint_free(c);
903 return 0;
906 isl_int_init(v);
907 isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v);
908 if (!isl_int_is_pos(v)) {
909 isl_int_clear(v);
910 isl_constraint_free(c);
912 return 0;
915 csl_c = cloog_constraint_to_isl(csl->stride->constraint);
917 d = isl_constraint_get_aff(csl_c);
918 d = isl_aff_drop_dims(d, isl_dim_div, 0, isl_aff_dim(d, isl_dim_div));
919 d = isl_aff_set_coefficient_si(d, isl_dim_in, csl->level - 1, 0);
920 d = isl_aff_scale(d, csl->stride->factor);
922 b = isl_constraint_get_bound(c, isl_dim_set, csl->level - 1);
924 b = isl_aff_neg(b);
925 b = isl_aff_add(b, isl_aff_copy(d));
926 b = isl_aff_scale_down(b, csl->stride->stride);
927 b = isl_aff_floor(b);
928 b = isl_aff_scale(b, csl->stride->stride);
929 b = isl_aff_sub(b, d);
930 b = isl_aff_add_coefficient_si(b, isl_dim_in, csl->level - 1, 1);
932 bound = isl_inequality_from_aff(b);
934 csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound);
936 isl_int_clear(v);
937 isl_constraint_free(c);
939 return 0;
942 static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user)
944 struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user;
945 int r;
947 csl->bounds = isl_basic_set_universe_like(bset);
948 if (csl->stride->constraint)
949 r = isl_basic_set_foreach_constraint(bset,
950 &constraint_stride_lower_c, csl);
951 else
952 r = isl_basic_set_foreach_constraint(bset,
953 &constraint_stride_lower, csl);
954 bset = isl_basic_set_intersect(bset, csl->bounds);
955 csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset));
957 return r;
961 * Update the lower bounds at level "level" to the given stride information.
962 * That is, make sure that the remainder on division by "stride"
963 * is equal to "offset".
965 CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level,
966 CloogStride *stride)
968 struct cloog_stride_lower csl;
969 isl_set *set = isl_set_from_cloog_domain(domain);
970 int r;
972 csl.stride = stride;
973 csl.level = level;
974 csl.set = isl_set_empty_like(set);
976 r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl);
977 assert(r == 0);
979 cloog_domain_free(domain);
980 return cloog_domain_from_isl_set(csl.set);
984 /* Add stride constraint, if any, to domain.
986 CloogDomain *cloog_domain_add_stride_constraint(CloogDomain *domain,
987 CloogStride *stride)
989 isl_constraint *c;
990 isl_set *set;
992 if (!stride || !stride->constraint)
993 return domain;
995 set = isl_set_from_cloog_domain(domain);
996 c = isl_constraint_copy(cloog_constraint_to_isl(stride->constraint));
998 set = isl_set_add_constraint(set, c);
1000 return cloog_domain_from_isl_set(set);
1005 * cloog_domain_lazy_equal function:
1006 * This function returns 1 if the domains given as input are the same, 0 if it
1007 * is unable to decide.
1009 int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2)
1011 isl_set *set1 = isl_set_from_cloog_domain(d1);
1012 isl_set *set2 = isl_set_from_cloog_domain(d2);
1013 return isl_set_fast_is_equal(set1, set2);
1016 struct cloog_bound_split {
1017 isl_set *set;
1018 int level;
1019 int lower;
1020 int upper;
1023 static int constraint_bound_split(__isl_take isl_constraint *c, void *user)
1025 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1026 isl_int v;
1027 int i;
1028 int handle = 0;
1030 isl_int_init(v);
1031 isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v);
1032 if (!cbs->lower && isl_int_is_pos(v))
1033 cbs->lower = handle = 1;
1034 else if (!cbs->upper && isl_int_is_neg(v))
1035 cbs->upper = handle = 1;
1036 if (handle) {
1037 for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) {
1038 isl_constraint_get_coefficient(c, isl_dim_param, i, &v);
1039 if (isl_int_is_zero(v))
1040 continue;
1041 cbs->set = isl_set_split_dims(cbs->set,
1042 isl_dim_param, i, 1);
1045 isl_int_clear(v);
1046 isl_constraint_free(c);
1048 return (cbs->lower && cbs->upper) ? -1 : 0;
1051 static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user)
1053 struct cloog_bound_split *cbs = (struct cloog_bound_split *)user;
1054 int r;
1056 cbs->lower = 0;
1057 cbs->upper = 0;
1058 r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs);
1059 isl_basic_set_free(bset);
1060 return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0;
1064 * Return a union of sets S_i such that the convex hull of "dom",
1065 * when intersected with one the sets S_i, will have an upper and
1066 * lower bound for the dimension at "level" (provided "dom" itself
1067 * has such bounds for the dimensions).
1069 * We currently take a very simple approach. For each of the basic
1070 * sets in "dom" we pick a lower and an upper bound and split the
1071 * range of any parameter involved in these two bounds in a
1072 * nonnegative and a negative part. This ensures that the symbolic
1073 * constant in these two constraints are themselves bounded and
1074 * so there will be at least one upper and one lower bound
1075 * in the convex hull.
1077 CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level)
1079 struct cloog_bound_split cbs;
1080 isl_set *set = isl_set_from_cloog_domain(dom);
1081 int r;
1082 cbs.level = level;
1083 cbs.set = isl_set_universe_like(set);
1084 r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs);
1085 assert(r == 0);
1086 return cloog_domain_from_isl_set(cbs.set);
1090 /* Check whether the union of scattering functions over all domains
1091 * is obviously injective.
1093 static int injective_scattering(CloogScatteringList *list)
1095 isl_map *map;
1096 isl_union_map *umap;
1097 int injective;
1098 int i = 0;
1099 char name[30];
1101 if (!list)
1102 return 1;
1104 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1105 snprintf(name, sizeof(name), "S%d", i);
1106 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1107 umap = isl_union_map_from_map(map);
1109 for (list = list->next, ++i; list; list = list->next, ++i) {
1110 map = isl_map_copy(isl_map_from_cloog_scattering(list->scatt));
1111 snprintf(name, sizeof(name), "S%d", i);
1112 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1113 umap = isl_union_map_add_map(umap, map);
1116 injective = isl_union_map_plain_is_injective(umap);
1118 isl_union_map_free(umap);
1120 return injective;
1125 * cloog_scattering_lazy_block function:
1126 * This function returns 1 if the two scattering functions s1 and s2 given
1127 * as input are the same (except possibly for the final dimension, where we
1128 * allow a difference of 1), assuming that the domains on which this
1129 * scatterings are applied are the same.
1130 * In fact this function answers the question "can I
1131 * safely consider the two domains as only one with two statements (a block) ?".
1132 * A difference of 1 in the final dimension is only allowed if the
1133 * entire scattering function is injective.
1134 * - s1 and s2 are the two domains to check for blocking,
1135 * - scattering is the linked list of all domains,
1136 * - scattdims is the total number of scattering dimentions.
1138 int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2,
1139 CloogScatteringList *scattering, int scattdims)
1141 int i;
1142 struct isl_space *dim;
1143 struct isl_map *rel;
1144 struct isl_set *delta;
1145 isl_map *map1 = isl_map_from_cloog_scattering(s1);
1146 isl_map *map2 = isl_map_from_cloog_scattering(s2);
1147 int fixed, block;
1148 isl_int cst;
1149 unsigned n_scat;
1151 n_scat = isl_map_dim(map1, isl_dim_out);
1152 if (n_scat != isl_map_dim(map2, isl_dim_out))
1153 return 0;
1155 dim = isl_map_get_space(map1);
1156 dim = isl_space_map_from_set(isl_space_domain(dim));
1157 rel = isl_map_identity(dim);
1158 rel = isl_map_apply_domain(rel, isl_map_copy(map1));
1159 rel = isl_map_apply_range(rel, isl_map_copy(map2));
1160 delta = isl_map_deltas(rel);
1161 isl_int_init(cst);
1162 for (i = 0; i < n_scat; ++i) {
1163 fixed = isl_set_fast_dim_is_fixed(delta, i, &cst);
1164 if (fixed != 1)
1165 break;
1166 if (isl_int_is_zero(cst))
1167 continue;
1168 if (i + 1 < n_scat)
1169 break;
1170 if (!isl_int_is_one(cst))
1171 break;
1172 if (!injective_scattering(scattering))
1173 break;
1175 block = i >= n_scat;
1176 isl_int_clear(cst);
1177 isl_set_free(delta);
1178 return block;
1183 * cloog_domain_lazy_disjoint function:
1184 * This function returns 1 if the domains given as input are disjoint, 0 if it
1185 * is unable to decide.
1187 int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2)
1189 isl_set *set1 = isl_set_from_cloog_domain(d1);
1190 isl_set *set2 = isl_set_from_cloog_domain(d2);
1191 return isl_set_fast_is_disjoint(set1, set2);
1196 * cloog_scattering_list_lazy_same function:
1197 * This function returns 1 if two domains in the list are the same, 0 if it
1198 * is unable to decide.
1200 int cloog_scattering_list_lazy_same(CloogScatteringList *list)
1202 CloogScatteringList *one, *other;
1203 isl_map *one_map, *other_map;
1205 for (one = list; one; one = one->next) {
1206 one_map = isl_map_from_cloog_scattering(one->scatt);
1207 for (other = one->next; other; other = other->next) {
1208 other_map = isl_map_from_cloog_scattering(other->scatt);
1209 if (isl_map_fast_is_equal(one_map, other_map))
1210 return 1;
1213 return 0;
1216 int cloog_domain_dimension(CloogDomain * domain)
1218 isl_set *set = isl_set_from_cloog_domain(domain);
1219 return isl_set_dim(set, isl_dim_set);
1222 int cloog_domain_parameter_dimension(CloogDomain *domain)
1224 isl_set *set = isl_set_from_cloog_domain(domain);
1225 return isl_set_dim(set, isl_dim_param);
1228 int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain)
1230 isl_map *map = isl_map_from_cloog_scattering(scatt);
1231 return isl_map_dim(map, isl_dim_out);
1234 int cloog_domain_isconvex(CloogDomain * domain)
1236 isl_set *set = isl_set_from_cloog_domain(domain);
1237 return isl_set_n_basic_set(set) <= 1;
1242 * cloog_domain_cut_first function:
1243 * This function splits off and returns the first convex set in the
1244 * union "domain". The remainder of the union is returned in rest.
1245 * The original "domain" itself is destroyed and may not be used
1246 * after a call to this function.
1248 CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest)
1250 isl_set *set = isl_set_from_cloog_domain(domain);
1251 struct isl_basic_set *first;
1253 first = isl_set_copy_basic_set(set);
1254 set = isl_set_drop_basic_set(set, first);
1255 *rest = cloog_domain_from_isl_set(set);
1257 return cloog_domain_from_isl_set(isl_set_from_basic_set(first));
1262 * Given a union domain, try to find a simpler representation
1263 * using fewer sets in the union.
1264 * The original "domain" itself is destroyed and may not be used
1265 * after a call to this function.
1267 CloogDomain *cloog_domain_simplify_union(CloogDomain *domain)
1269 isl_set *set = isl_set_from_cloog_domain(domain);
1270 return cloog_domain_from_isl_set(isl_set_coalesce(set));
1275 * cloog_scattering_lazy_isscalar function:
1276 * this function returns 1 if the scattering dimension 'dimension' in the
1277 * scattering 'scatt' is constant.
1278 * If value is not NULL, then it is set to the constant value of dimension.
1280 int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension,
1281 cloog_int_t *value)
1283 isl_map *map = isl_map_from_cloog_scattering(scatt);
1284 return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value);
1289 * cloog_domain_lazy_isconstant function:
1290 * this function returns 1 if the dimension 'dimension' in the
1291 * domain 'domain' is constant.
1292 * If value is not NULL, then it is set to the constant value of dimension.
1294 int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension,
1295 cloog_int_t *value)
1297 isl_set *set = isl_set_from_cloog_domain(domain);
1298 return isl_set_fast_dim_is_fixed(set, dimension, value);
1303 * cloog_scattering_erase_dimension function:
1304 * this function returns a CloogDomain structure builds from 'domain' where
1305 * we removed the dimension 'dimension' and every constraint involving this
1306 * dimension.
1308 CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering,
1309 int dimension)
1311 isl_map *map = isl_map_from_cloog_scattering(scattering);
1312 map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1);
1313 return cloog_scattering_from_isl_map(map);
1317 * cloog_domain_cube:
1318 * Construct and return a dim-dimensional cube, with values ranging
1319 * between min and max in each dimension.
1321 CloogDomain *cloog_domain_cube(CloogState *state,
1322 int dim, cloog_int_t min, cloog_int_t max)
1324 int i;
1325 struct isl_basic_set *cube;
1326 struct isl_basic_set *interval;
1327 struct isl_basic_set_list *list;
1329 if (dim == 0)
1330 return cloog_domain_universe(state, dim);
1332 interval = isl_basic_set_interval(state->backend->ctx, min, max);
1333 list = isl_basic_set_list_alloc(state->backend->ctx, dim);
1334 for (i = 0; i < dim; ++i)
1335 list = isl_basic_set_list_add(list, isl_basic_set_copy(interval));
1336 isl_basic_set_free(interval);
1337 cube = isl_basic_set_list_product(list);
1338 return cloog_domain_from_isl_set(isl_set_from_basic_set(cube));
1343 * cloog_domain_scatter function:
1344 * This function add the scattering (scheduling) informations to a domain.
1346 CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt)
1348 isl_set *set = isl_set_from_cloog_domain(domain);
1349 isl_map *map = isl_map_from_cloog_scattering(scatt);
1351 map = isl_map_reverse(isl_map_copy(map));
1352 map = isl_map_intersect_range(map, set);
1353 set = isl_set_flatten(isl_map_wrap(map));
1354 return cloog_domain_from_isl_set(set);
1357 static int add_domain_from_map(__isl_take isl_map *map, void *user)
1359 isl_space *dim;
1360 const char *name;
1361 CloogDomain *domain;
1362 CloogScattering *scat;
1363 CloogUnionDomain **ud = (CloogUnionDomain **)user;
1365 dim = isl_map_get_space(map);
1366 name = isl_space_get_tuple_name(dim, isl_dim_in);
1367 domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map)));
1368 scat = cloog_scattering_from_isl_map(map);
1369 *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL);
1370 isl_space_free(dim);
1372 return 0;
1376 * Construct a CloogUnionDomain from an isl_union_map representing
1377 * a global scattering function. The input is a mapping from different
1378 * spaces (different tuple names and possibly different dimensions)
1379 * to a common space. The iteration domains are set to the domains
1380 * in each space. The statement names are set to the names of the
1381 * spaces. The parameter names of the result are set to those of
1382 * the input, but the iterator and scattering dimension names are
1383 * left unspecified.
1385 CloogUnionDomain *cloog_union_domain_from_isl_union_map(
1386 __isl_take isl_union_map *umap)
1388 int i;
1389 int nparam;
1390 isl_space *dim;
1391 CloogUnionDomain *ud;
1393 dim = isl_union_map_get_space(umap);
1394 nparam = isl_space_dim(dim, isl_dim_param);
1396 ud = cloog_union_domain_alloc(nparam);
1398 for (i = 0; i < nparam; ++i) {
1399 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1400 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1402 isl_space_free(dim);
1404 if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) {
1405 isl_union_map_free(umap);
1406 cloog_union_domain_free(ud);
1407 assert(0);
1410 isl_union_map_free(umap);
1412 return ud;
1415 static int count_same_name(__isl_keep isl_space *dim,
1416 enum isl_dim_type type, unsigned pos, const char *name)
1418 enum isl_dim_type t;
1419 unsigned p, s;
1420 int count = 0;
1421 int len = strlen(name);
1423 for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) {
1424 s = t == type ? pos : isl_space_dim(dim, t);
1425 for (p = 0; p < s; ++p) {
1426 const char *n = isl_space_get_dim_name(dim, t, p);
1427 if (n && !strncmp(n, name, len))
1428 count++;
1431 return count;
1434 static CloogUnionDomain *add_domain(__isl_take isl_set *set, CloogUnionDomain *ud)
1436 int i, nvar;
1437 isl_ctx *ctx;
1438 isl_space *dim;
1439 char buffer[20];
1440 const char *name;
1441 CloogDomain *domain;
1443 ctx = isl_set_get_ctx(set);
1444 dim = isl_set_get_space(set);
1445 name = isl_space_get_tuple_name(dim, isl_dim_set);
1446 set = isl_set_flatten(set);
1447 set = isl_set_set_tuple_name(set, NULL);
1448 domain = cloog_domain_from_isl_set(set);
1449 ud = cloog_union_domain_add_domain(ud, name, domain, NULL, NULL);
1451 nvar = isl_space_dim(dim, isl_dim_set);
1452 for (i = 0; i < nvar; ++i) {
1453 char *long_name = NULL;
1454 int n;
1456 name = isl_space_get_dim_name(dim, isl_dim_set, i);
1457 if (!name) {
1458 snprintf(buffer, sizeof(buffer), "i%d", i);
1459 name = buffer;
1461 n = count_same_name(dim, isl_dim_set, i, name);
1462 if (n) {
1463 int size = strlen(name) + 10;
1464 long_name = isl_alloc_array(ctx, char, size);
1465 if (!long_name)
1466 cloog_die("memory overflow.\n");
1467 snprintf(long_name, size, "%s_%d", name, n);
1468 name = long_name;
1470 ud = cloog_union_domain_set_name(ud, CLOOG_ITER, i, name);
1471 free(long_name);
1473 isl_space_free(dim);
1475 return ud;
1479 * Construct a CloogUnionDomain from an isl_set.
1480 * The statement names are set to the names of the
1481 * spaces. The parameter and iterator names of the result are set to those of
1482 * the input, but the scattering dimension names are left unspecified.
1484 CloogUnionDomain *cloog_union_domain_from_isl_set(
1485 __isl_take isl_set *set)
1487 int i;
1488 int nparam;
1489 isl_space *dim;
1490 CloogUnionDomain *ud;
1492 dim = isl_set_get_space(set);
1493 nparam = isl_space_dim(dim, isl_dim_param);
1495 ud = cloog_union_domain_alloc(nparam);
1497 for (i = 0; i < nparam; ++i) {
1498 const char *s = isl_space_get_dim_name(dim, isl_dim_param, i);
1499 ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s);
1501 isl_space_free(dim);
1503 ud = add_domain(set, ud);
1505 return ud;
1508 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
1509 static void Euclid(cloog_int_t a, cloog_int_t b,
1510 cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
1512 cloog_int_t c, d, e, f, tmp;
1514 cloog_int_init(c);
1515 cloog_int_init(d);
1516 cloog_int_init(e);
1517 cloog_int_init(f);
1518 cloog_int_init(tmp);
1519 cloog_int_abs(c, a);
1520 cloog_int_abs(d, b);
1521 cloog_int_set_si(e, 1);
1522 cloog_int_set_si(f, 0);
1523 while (cloog_int_is_pos(d)) {
1524 cloog_int_tdiv_q(tmp, c, d);
1525 cloog_int_mul(tmp, tmp, f);
1526 cloog_int_sub(e, e, tmp);
1527 cloog_int_tdiv_q(tmp, c, d);
1528 cloog_int_mul(tmp, tmp, d);
1529 cloog_int_sub(c, c, tmp);
1530 cloog_int_swap(c, d);
1531 cloog_int_swap(e, f);
1533 cloog_int_set(*g, c);
1534 if (cloog_int_is_zero(a))
1535 cloog_int_set_si(*x, 0);
1536 else if (cloog_int_is_pos(a))
1537 cloog_int_set(*x, e);
1538 else cloog_int_neg(*x, e);
1539 if (cloog_int_is_zero(b))
1540 cloog_int_set_si(*y, 0);
1541 else {
1542 cloog_int_mul(tmp, a, *x);
1543 cloog_int_sub(tmp, c, tmp);
1544 cloog_int_divexact(*y, tmp, b);
1546 cloog_int_clear(c);
1547 cloog_int_clear(d);
1548 cloog_int_clear(e);
1549 cloog_int_clear(f);
1550 cloog_int_clear(tmp);
1553 /* Construct a CloogStride from the given constraint for the given level,
1554 * if possible.
1555 * We first compute the gcd of the coefficients of the existentially
1556 * quantified variables and then remove any common factors it has
1557 * with the coefficient at the given level.
1558 * The result is the value of the stride and if it is not one,
1559 * then it is possible to construct a CloogStride.
1560 * The constraint leading to the stride is stored in the CloogStride
1561 * as well a value (factor) such that the product of this value
1562 * and the coefficient at the given level is equal to -1 modulo the stride.
1564 static CloogStride *construct_stride(isl_constraint *c, int level)
1566 int i, n, sign;
1567 isl_int v, m, gcd, stride, factor;
1568 CloogStride *s;
1570 if (!c)
1571 return NULL;
1573 isl_int_init(v);
1574 isl_int_init(m);
1575 isl_int_init(gcd);
1576 isl_int_init(factor);
1577 isl_int_init(stride);
1579 isl_constraint_get_coefficient(c, isl_dim_set, level - 1, &v);
1580 sign = isl_int_sgn(v);
1581 isl_int_abs(m, v);
1583 isl_int_set_si(gcd, 0);
1584 n = isl_constraint_dim(c, isl_dim_div);
1585 for (i = 0; i < n; ++i) {
1586 isl_constraint_get_coefficient(c, isl_dim_div, i, &v);
1587 isl_int_gcd(gcd, gcd, v);
1590 isl_int_gcd(v, m, gcd);
1591 isl_int_divexact(stride, gcd, v);
1593 if (isl_int_is_zero(stride) || isl_int_is_one(stride))
1594 s = NULL;
1595 else {
1596 Euclid(m, stride, &factor, &v, &gcd);
1597 if (sign > 0)
1598 isl_int_neg(factor, factor);
1600 c = isl_constraint_copy(c);
1601 s = cloog_stride_alloc_from_constraint(stride,
1602 cloog_constraint_from_isl_constraint(c), factor);
1605 isl_int_clear(stride);
1606 isl_int_clear(factor);
1607 isl_int_clear(gcd);
1608 isl_int_clear(m);
1609 isl_int_clear(v);
1611 return s;
1614 struct cloog_isl_find_stride_data {
1615 int level;
1616 CloogStride *stride;
1619 /* Check if the given constraint can be used to derive
1620 * a stride on the iterator identified by data->level.
1621 * We first check that there are some existentially quantified variables
1622 * and that the coefficient at data->level is non-zero.
1623 * Then we call construct_stride for further checks and the actual
1624 * construction of the CloogStride.
1626 static int find_stride(__isl_take isl_constraint *c, void *user)
1628 struct cloog_isl_find_stride_data *data;
1629 int n;
1630 isl_int v;
1632 data = (struct cloog_isl_find_stride_data *)user;
1634 if (data->stride) {
1635 isl_constraint_free(c);
1636 return 0;
1639 n = isl_constraint_dim(c, isl_dim_div);
1640 if (n == 0) {
1641 isl_constraint_free(c);
1642 return 0;
1645 isl_int_init(v);
1647 isl_constraint_get_coefficient(c, isl_dim_set, data->level - 1, &v);
1648 if (!isl_int_is_zero(v))
1649 data->stride = construct_stride(c, data->level);
1651 isl_int_clear(v);
1653 isl_constraint_free(c);
1655 return 0;
1658 /* Check if the given list of domains has a common stride on the given level.
1659 * If so, return a pointer to a CloogStride object. If not, return NULL.
1661 * We project out all later variables, take the union and compute
1662 * the affine hull of the union. Then we check the (equality)
1663 * constraints in this affine hull for imposing a stride.
1665 CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level)
1667 struct cloog_isl_find_stride_data data = { level, NULL };
1668 isl_set *set;
1669 isl_basic_set *aff;
1670 int first = level;
1671 int n;
1672 int r;
1674 set = isl_set_from_cloog_domain(list->domain);
1675 n = isl_set_dim(set, isl_dim_set) - first;
1676 set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n);
1678 for (list = list->next; list; list = list->next) {
1679 isl_set *set_i = isl_set_from_cloog_domain(list->domain);
1680 n = isl_set_dim(set_i, isl_dim_set) - first;
1681 set_i = isl_set_project_out(isl_set_copy(set_i),
1682 isl_dim_set, first, n);
1683 set = isl_set_union(set, set_i);
1685 aff = isl_set_affine_hull(set);
1687 r = isl_basic_set_foreach_constraint(aff, &find_stride, &data);
1688 assert(r == 0);
1690 isl_basic_set_free(aff);
1692 return data.stride;
1695 struct cloog_can_unroll {
1696 int can_unroll;
1697 int level;
1698 isl_constraint *c;
1699 isl_set *set;
1700 isl_int *n;
1705 * Check if the given lower bound can be used for unrolling
1706 * and, if so, return the unrolling factor/trip count in *v.
1707 * If the lower bound involves any existentially quantified
1708 * variables, we currently punt.
1709 * Otherwise we compute the maximal value of (i - ceil(l) + 1),
1710 * with l the given lower bound and i the iterator identified by level.
1712 static int is_valid_unrolling_lower_bound(struct cloog_can_unroll *ccu,
1713 __isl_keep isl_constraint *c, isl_int *v)
1715 unsigned n_div;
1716 isl_aff *aff;
1717 enum isl_lp_result res;
1719 n_div = isl_constraint_dim(c, isl_dim_div);
1720 if (isl_constraint_involves_dims(c, isl_dim_div, 0, n_div))
1721 return 0;
1723 aff = isl_constraint_get_bound(c, isl_dim_set, ccu->level - 1);
1724 aff = isl_aff_ceil(aff);
1725 aff = isl_aff_neg(aff);
1726 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, ccu->level - 1, 1);
1727 res = isl_set_max(ccu->set, aff, v);
1728 isl_aff_free(aff);
1730 if (res == isl_lp_unbounded)
1731 return 0;
1733 assert(res == isl_lp_ok);
1735 cloog_int_add_ui(*v, *v, 1);
1737 return 1;
1741 /* Check if we can unroll based on the given constraint.
1742 * Only lower bounds can be used.
1743 * Record it if it turns out to be usable and if we haven't recorded
1744 * any other constraint already.
1746 static int constraint_can_unroll(__isl_take isl_constraint *c, void *user)
1748 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1749 isl_int v;
1750 isl_int count;
1752 isl_int_init(v);
1753 isl_int_init(count);
1754 isl_constraint_get_coefficient(c, isl_dim_set, ccu->level - 1, &v);
1755 if (isl_int_is_pos(v) &&
1756 is_valid_unrolling_lower_bound(ccu, c, &count) &&
1757 (!ccu->c || isl_int_lt(count, *ccu->n))) {
1758 isl_constraint_free(ccu->c);
1759 ccu->c = isl_constraint_copy(c);
1760 isl_int_set(*ccu->n, count);
1762 isl_int_clear(count);
1763 isl_int_clear(v);
1764 isl_constraint_free(c);
1766 return 0;
1770 /* Check if we can unroll the domain at the current level.
1771 * If the domain is a union, we cannot. Otherwise, we check the
1772 * constraints.
1774 static int basic_set_can_unroll(__isl_take isl_basic_set *bset, void *user)
1776 struct cloog_can_unroll *ccu = (struct cloog_can_unroll *)user;
1777 int r = 0;
1779 if (ccu->c || !ccu->can_unroll)
1780 ccu->can_unroll = 0;
1781 else {
1782 bset = isl_basic_set_remove_redundancies(bset);
1783 r = isl_basic_set_foreach_constraint(bset,
1784 &constraint_can_unroll, ccu);
1786 isl_basic_set_free(bset);
1787 return r;
1791 /* Check if we can unroll the given domain at the given level, and
1792 * if so, return the single lower bound in *lb and an upper bound
1793 * on the number of iterations in *n.
1794 * If we cannot unroll, return 0 and set *lb to NULL.
1796 * We can unroll, if we can identify a lower bound on level
1797 * such that the number of iterations is bounded by a constant.
1799 int cloog_domain_can_unroll(CloogDomain *domain, int level, cloog_int_t *n,
1800 CloogConstraint **lb)
1802 isl_set *set = isl_set_from_cloog_domain(domain);
1803 struct cloog_can_unroll ccu = { 1, level, NULL, set, n };
1804 int r;
1806 *lb = NULL;
1807 r = isl_set_foreach_basic_set(set, &basic_set_can_unroll, &ccu);
1808 assert(r == 0);
1809 if (!ccu.c)
1810 ccu.can_unroll = 0;
1811 if (!ccu.can_unroll) {
1812 isl_constraint_free(ccu.c);
1813 return 0;
1816 *lb = cloog_constraint_from_isl_constraint(ccu.c);
1818 return ccu.can_unroll;
1822 /* Fix the iterator i at the given level to l + o,
1823 * where l is prescribed by the constraint lb and o is equal to offset.
1824 * In particular, if lb is the constraint
1826 * a i >= f(j)
1828 * then l = ceil(f(j)/a).
1830 CloogDomain *cloog_domain_fixed_offset(CloogDomain *domain,
1831 int level, CloogConstraint *lb, cloog_int_t offset)
1833 isl_aff *aff;
1834 isl_set *set = isl_set_from_cloog_domain(domain);
1835 isl_constraint *c;
1836 isl_constraint *eq;
1838 c = cloog_constraint_to_isl(lb);
1839 aff = isl_constraint_get_bound(c, isl_dim_set, level - 1);
1840 aff = isl_aff_ceil(aff);
1841 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, level - 1, -1);
1842 aff = isl_aff_add_constant(aff, offset);
1843 eq = isl_equality_from_aff(aff);
1844 set = isl_set_add_constraint(set, eq);
1846 return cloog_domain_from_isl_set(set);