1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <ctype.h>
4 #include <cloog/isl/cloog.h>
5 #include <cloog/isl/backend.h>
6 #include <isl/aff.h>
7 #include <isl/set.h>
8 #include <isl/val.h>
9 #include <isl/space.h>
10 
11 #if ISL_USING_GMP
12 #include <isl/val_gmp.h>
13 #endif
14 
15 #define ALLOC(type) (type*)malloc(sizeof(type))
16 #define ALLOCN(type,n) (type*)malloc((n)*sizeof(type))
17 
cloog_int_to_isl_val(isl_ctx * ctx,cloog_int_t c)18 __isl_give isl_val *cloog_int_to_isl_val(isl_ctx* ctx, cloog_int_t c)
19 {
20 	isl_val *v;
21 #if defined(CLOOG_INT_INT)
22 	v = isl_val_int_from_si(ctx, c);
23 #elif defined(CLOOG_INT_LONG)
24 	v = isl_val_int_from_si(ctx, c);
25 #elif defined(CLOOG_INT_LONG_LONG)
26 	v = isl_val_int_from_si(ctx, c);
27 #elif defined(CLOOG_INT_GMP)
28   #if ISL_USING_GMP // ISL using GMP
29     v = isl_val_int_from_gmp(ctx, c);
30   #else // ISL using iMath or iMath-32
31     // The best way to ensure full precision is to go through strings!!!
32     char* str = NULL;
33     str = mpz_get_str(str, 10, c);
34     v = isl_val_read_from_str(ctx, str);
35     free(str);
36   #endif
37 #else
38 #error "No integer type defined"
39 #endif
40 	return v;
41 }
42 
43 /*
44  * CLooG'll be dealing in integers so we expect numerator/1 form
45  * from isl_val. Thus get numerator to assign to cloog_int
46  */
isl_val_to_cloog_int(__isl_keep isl_val * val,cloog_int_t * cint)47 void isl_val_to_cloog_int(__isl_keep isl_val *val, cloog_int_t *cint)
48 {
49 	assert(isl_val_is_int(val));
50 #if defined(CLOOG_INT_INT)
51 	*cint = isl_val_get_num_si(val);
52 #elif defined(CLOOG_INT_LONG)
53 	*cint = isl_val_get_num_si(val);
54 #elif defined(CLOOG_INT_LONG_LONG)
55 	*cint = isl_val_get_num_si(val);
56 #elif defined(CLOOG_INT_GMP)
57   #if ISL_USING_GMP
58     isl_val_get_num_gmp(val, *cint);
59   #else
60     isl_printer *string_printer = isl_printer_to_str(isl_val_get_ctx(val));
61     isl_printer_print_val(string_printer, val);
62     char *str = isl_printer_get_str(string_printer);
63     mpz_set_str(*cint, str, 10);
64     isl_printer_free(string_printer);
65     free(str);
66   #endif
67 #else
68 #error "No integer type defined"
69 #endif
70 }
71 
72 
cloog_constraint_set_from_isl_basic_set(struct isl_basic_set * bset)73 CloogConstraintSet *cloog_constraint_set_from_isl_basic_set(struct isl_basic_set *bset)
74 {
75 	return (CloogConstraintSet *)bset;
76 }
77 
cloog_constraint_from_isl_constraint(struct isl_constraint * constraint)78 CloogConstraint *cloog_constraint_from_isl_constraint(struct isl_constraint *constraint)
79 {
80 	return (CloogConstraint *)constraint;
81 }
82 
cloog_constraint_to_isl(CloogConstraint * constraint)83 isl_constraint *cloog_constraint_to_isl(CloogConstraint *constraint)
84 {
85 	return (isl_constraint *)constraint;
86 }
87 
cloog_constraints_set_to_isl(CloogConstraintSet * constraints)88 isl_basic_set *cloog_constraints_set_to_isl(CloogConstraintSet *constraints)
89 {
90 	return (isl_basic_set *)constraints;
91 }
92 
93 
94 /******************************************************************************
95  *                             Memory leaks hunting                           *
96  ******************************************************************************/
97 
98 
99 
cloog_constraint_set_free(CloogConstraintSet * constraints)100 void cloog_constraint_set_free(CloogConstraintSet *constraints)
101 {
102 	isl_basic_set_free(cloog_constraints_set_to_isl(constraints));
103 }
104 
105 
cloog_constraint_set_contains_level(CloogConstraintSet * constraints,int level,int nb_parameters)106 int cloog_constraint_set_contains_level(CloogConstraintSet *constraints,
107 			int level, int nb_parameters)
108 {
109 	isl_basic_set *bset;
110 	bset = cloog_constraints_set_to_isl(constraints);
111 	return isl_basic_set_dim(bset, isl_dim_set) >= level;
112 }
113 
114 struct cloog_isl_dim {
115 	enum isl_dim_type type;
116 	int		  pos;
117 };
118 
basic_set_cloog_dim_to_isl_dim(__isl_keep isl_basic_set * bset,int pos)119 static struct cloog_isl_dim basic_set_cloog_dim_to_isl_dim(
120 	__isl_keep isl_basic_set *bset, int pos)
121 {
122 	enum isl_dim_type types[] = { isl_dim_set, isl_dim_div, isl_dim_param };
123 	int i;
124 	struct cloog_isl_dim ci_dim;
125 
126 	for (i = 0; i < 3; ++i) {
127 		unsigned dim = isl_basic_set_dim(bset, types[i]);
128 		if (pos < dim) {
129 			ci_dim.type = types[i];
130 			ci_dim.pos = pos;
131 			return ci_dim;
132 		}
133 		pos -= dim;
134 	}
135 	assert(0);
136 }
137 
set_cloog_dim_to_isl_dim(CloogConstraintSet * constraints,int pos)138 static struct cloog_isl_dim set_cloog_dim_to_isl_dim(
139 	CloogConstraintSet *constraints, int pos)
140 {
141 	isl_basic_set *bset;
142 
143 	bset = cloog_constraints_set_to_isl(constraints);
144 	return basic_set_cloog_dim_to_isl_dim(bset, pos);
145 }
146 
147 /* Check if the variable at position level is defined by an
148  * equality.  If so, return the row number.  Otherwise, return -1.
149  */
cloog_constraint_set_defining_equality(CloogConstraintSet * constraints,int level)150 CloogConstraint *cloog_constraint_set_defining_equality(
151 	CloogConstraintSet *constraints, int level)
152 {
153 	struct isl_constraint *c;
154 	struct cloog_isl_dim dim;
155 	isl_basic_set *bset;
156 
157 	bset = cloog_constraints_set_to_isl(constraints);
158 	dim = set_cloog_dim_to_isl_dim(constraints, level - 1);
159 	if (isl_basic_set_has_defining_equality(bset, dim.type, dim.pos, &c))
160 		return cloog_constraint_from_isl_constraint(c);
161 	else
162 		return NULL;
163 }
164 
165 
166 struct cloog_isl_other {
167 	int level;
168 	int found;
169 	isl_constraint *u;
170 	isl_constraint *l;
171 };
172 
173 
174 /* Set other->found to 1 if the given constraint involves other->level
175  * and is different from other->u and other->l.
176  */
check_other_constraint(__isl_take isl_constraint * c,void * user)177 static int check_other_constraint(__isl_take isl_constraint *c, void *user)
178 {
179 	struct cloog_isl_other *other = user;
180 	CloogConstraint *cc;
181 
182 	if (!isl_constraint_is_equal(c, other->l) &&
183 	    !isl_constraint_is_equal(c, other->u)) {
184 		cc = cloog_constraint_from_isl_constraint(c);
185 		if (cloog_constraint_involves(cc, other->level - 1))
186 			other->found = 1;
187 	}
188 
189 	isl_constraint_free(c);
190 
191 	return other->found ? -1 : 0;
192 }
193 
194 
195 /* Check if the variable (e) at position level is defined by a
196  * pair of inequalities
197  *		 <a, i> + -m e +  <b, p> + k1 >= 0
198  *		<-a, i> +  m e + <-b, p> + k2 >= 0
199  * with 0 <= k1 + k2 < m
200  * If so return the row number of the upper bound and set *lower
201  * to the row number of the lower bound.  If not, return -1.
202  *
203  * If the variable at position level occurs in any other constraint,
204  * then we currently return -1.  The modulo guard that we would generate
205  * would still be correct, but we would also need to generate
206  * guards corresponding to the other constraints, and this has not
207  * been implemented yet.
208  */
cloog_constraint_set_defining_inequalities(CloogConstraintSet * constraints,int level,CloogConstraint ** lower,int nb_par)209 CloogConstraint *cloog_constraint_set_defining_inequalities(
210 	CloogConstraintSet *constraints,
211 	int level, CloogConstraint **lower, int nb_par)
212 {
213 	struct isl_constraint *u;
214 	struct isl_constraint *l;
215 	struct cloog_isl_dim dim;
216 	struct isl_basic_set *bset;
217 	struct cloog_isl_other other;
218 
219 	bset = cloog_constraints_set_to_isl(constraints);
220 	dim = set_cloog_dim_to_isl_dim(constraints, level - 1);
221 	if (!isl_basic_set_has_defining_inequalities(bset, dim.type, dim.pos,
222 								&l, &u))
223 		return cloog_constraint_invalid();
224 
225 	other.l = l;
226 	other.u = u;
227 	other.found = 0;
228 	other.level = level;
229 	isl_basic_set_foreach_constraint(bset, &check_other_constraint, &other);
230 	if (other.found) {
231 		isl_constraint_free(l);
232 		isl_constraint_free(u);
233 		*lower = NULL;
234 		return NULL;
235 	}
236 	*lower = cloog_constraint_from_isl_constraint(l);
237 	return cloog_constraint_from_isl_constraint(u);
238 }
239 
cloog_constraint_set_total_dimension(CloogConstraintSet * constraints)240 int cloog_constraint_set_total_dimension(CloogConstraintSet *constraints)
241 {
242 	isl_basic_set *bset;
243 	bset = cloog_constraints_set_to_isl(constraints);
244 	return isl_basic_set_total_dim(bset);
245 }
246 
cloog_constraint_set_n_iterators(CloogConstraintSet * constraints,int n_par)247 int cloog_constraint_set_n_iterators(CloogConstraintSet *constraints, int n_par)
248 {
249 	isl_basic_set *bset;
250 	bset = cloog_constraints_set_to_isl(constraints);
251 	return isl_basic_set_dim(bset, isl_dim_set);
252 }
253 
254 
255 /******************************************************************************
256  *                        Equalities spreading functions                      *
257  ******************************************************************************/
258 
259 
260 /* Equalities are stored inside a Matrix data structure called "equal".
261  * This matrix has (nb_scattering + nb_iterators + 1) rows (i.e. total
262  * dimensions + 1, the "+ 1" is because a statement can be included inside an
263  * external loop without iteration domain), and (nb_scattering + nb_iterators +
264  * nb_parameters + 2) columns (all unknowns plus the scalar plus the equality
265  * type). The ith row corresponds to the equality "= 0" for the ith dimension
266  * iterator. The first column gives the equality type (0: no equality, then
267  * EQTYPE_* -see pprint.h-). At each recursion of pprint, if an equality for
268  * the current level is found, the corresponding row is updated. Then the
269  * equality if it exists is used to simplify expressions (e.g. if we have
270  * "i+1" while we know that "i=2", we simplify it in "3"). At the end of
271  * the pprint call, the corresponding row is reset to zero.
272  */
273 
cloog_equal_alloc(int n,int nb_levels,int nb_parameters)274 CloogEqualities *cloog_equal_alloc(int n, int nb_levels, int nb_parameters)
275 {
276 	int i;
277 	CloogEqualities *equal = ALLOC(CloogEqualities);
278 
279 	equal->total_dim = nb_levels - 1 + nb_parameters;
280 	equal->n = n;
281 	equal->constraints = ALLOCN(isl_constraint *, n);
282 	equal->types = ALLOCN(int, n);
283 	for (i = 0; i < n; ++i) {
284 		equal->constraints[i] = NULL;
285 		equal->types[i] = EQTYPE_NONE;
286 	}
287 	return equal;
288 }
289 
cloog_equal_total_dimension(CloogEqualities * equal)290 int cloog_equal_total_dimension(CloogEqualities *equal)
291 {
292 	return equal->total_dim;
293 }
294 
cloog_equal_free(CloogEqualities * equal)295 void cloog_equal_free(CloogEqualities *equal)
296 {
297 	int i;
298 
299 	for (i = 0; i < equal->n; ++i)
300 		isl_constraint_free(equal->constraints[i]);
301 	free(equal->constraints);
302 	free(equal->types);
303 	free(equal);
304 }
305 
cloog_equal_count(CloogEqualities * equal)306 int cloog_equal_count(CloogEqualities *equal)
307 {
308 	return equal->n;
309 }
310 
311 
312 /**
313  * cloog_constraint_equal_type function :
314  * This function returns the type of the equality in the constraint (line) of
315  * (constraints) for the element (level). An equality is 'constant' iff all
316  * other factors are null except the constant one. It is a 'pure item' iff
317  * it is equal or opposite to a single variable or parameter.
318  * Otherwise it is an 'affine expression'.
319  * For instance:
320  *   i = -13 is constant, i = j, j = -M are pure items,
321  *   j = 2*M, i = j+1, 2*j = M are affine expressions.
322  *
323  * - constraints is the matrix of constraints,
324  * - level is the column number in equal of the element which is 'equal to',
325  */
cloog_constraint_equal_type(CloogConstraint * cc,int level)326 static int cloog_constraint_equal_type(CloogConstraint *cc, int level)
327 {
328 	int i;
329 	isl_val *c;
330 	int type = EQTYPE_NONE;
331 	struct isl_constraint *constraint = cloog_constraint_to_isl(cc);
332 
333 	c = isl_constraint_get_constant_val(constraint);
334 	if (!isl_val_is_zero(c))
335 		type = EQTYPE_CONSTANT;
336 	isl_val_free(c);
337 	c = isl_constraint_get_coefficient_val(constraint, isl_dim_set, level - 1);
338 	if (!isl_val_is_one(c) && !isl_val_is_negone(c))
339 		type = EQTYPE_EXAFFINE;
340 	isl_val_free(c);
341 	for (i = 0; i < isl_constraint_dim(constraint, isl_dim_param); ++i) {
342 		c = isl_constraint_get_coefficient_val(constraint, isl_dim_param, i);
343 		if (isl_val_is_zero(c)){
344 			isl_val_free(c);
345 			continue;
346 		}
347 		if ((!isl_val_is_one(c) && !isl_val_is_negone(c)) ||
348 		    type != EQTYPE_NONE) {
349 			type = EQTYPE_EXAFFINE;
350 			isl_val_free(c);
351 			break;
352 		}
353 		type = EQTYPE_PUREITEM;
354 		isl_val_free(c);
355 	}
356 	for (i = 0; i < isl_constraint_dim(constraint, isl_dim_set); ++i) {
357 		if (i == level - 1)
358 			continue;
359 		c = isl_constraint_get_coefficient_val(constraint, isl_dim_set, i);
360 		if (isl_val_is_zero(c)){
361 			isl_val_free(c);
362 			continue;
363 		}
364 		if ((!isl_val_is_one(c) && !isl_val_is_negone(c)) ||
365 		    type != EQTYPE_NONE) {
366 			type = EQTYPE_EXAFFINE;
367 			isl_val_free(c);
368 			break;
369 		}
370 		type = EQTYPE_PUREITEM;
371 		isl_val_free(c);
372 	}
373 	for (i = 0; i < isl_constraint_dim(constraint, isl_dim_div); ++i) {
374 		c = isl_constraint_get_coefficient_val(constraint, isl_dim_div, i);
375 		if (isl_val_is_zero(c)){
376 			isl_val_free(c);
377 			continue;
378 		}
379 		if ((!isl_val_is_one(c) && !isl_val_is_negone(c)) ||
380 		    type != EQTYPE_NONE) {
381 			type = EQTYPE_EXAFFINE;
382 			isl_val_free(c);
383 			break;
384 		}
385 		type = EQTYPE_PUREITEM;
386 		isl_val_free(c);
387 	}
388 
389 	if (type == EQTYPE_NONE)
390 		type = EQTYPE_CONSTANT;
391 
392 	return type;
393 }
394 
395 
cloog_equal_type(CloogEqualities * equal,int level)396 int cloog_equal_type(CloogEqualities *equal, int level)
397 {
398 	return equal->types[level-1];
399 }
400 
401 
402 /**
403  * cloog_equal_add function:
404  * This function updates the row (level-1) of the equality matrix (equal) with
405  * the row that corresponds to the row (line) of the matrix (matrix).
406  * - equal is the matrix of equalities,
407  * - matrix is the matrix of constraints,
408  * - level is the column number in matrix of the element which is 'equal to',
409  * - line is the line number in matrix of the constraint we want to study,
410  * - the infos structure gives the user all options on code printing and more.
411  **
412  * line is set to an invalid constraint for equalities that CLooG itself has
413  * discovered because the lower and upper bound of a loop happened to be equal.
414  * This situation shouldn't happen in the isl port since isl should
415  * have found the equality itself.
416  */
cloog_equal_add(CloogEqualities * equal,CloogConstraintSet * matrix,int level,CloogConstraint * line,int nb_par)417 void cloog_equal_add(CloogEqualities *equal, CloogConstraintSet *matrix,
418 			int level, CloogConstraint *line, int nb_par)
419 {
420 	isl_constraint *c;
421 	assert(cloog_constraint_is_valid(line));
422 
423 	equal->types[level-1] = cloog_constraint_equal_type(line, level);
424 	c = cloog_constraint_to_isl(line);
425 	equal->constraints[level - 1] = isl_constraint_copy(c);
426 }
427 
428 
429 /**
430  * cloog_equal_del function :
431  * This function reset the equality corresponding to the iterator (level)
432  * in the equality matrix (equal).
433  * - July 2nd 2002: first version.
434  */
cloog_equal_del(CloogEqualities * equal,int level)435 void cloog_equal_del(CloogEqualities *equal, int level)
436 {
437 	equal->types[level-1] = EQTYPE_NONE;
438 	isl_constraint_free(equal->constraints[level - 1]);
439 	equal->constraints[level-1] = NULL;
440 }
441 
442 
443 
444 /******************************************************************************
445  *                            Processing functions                            *
446  ******************************************************************************/
447 
448 /**
449  * Function cloog_constraint_set_normalize:
450  * This function will modify the constraint system in such a way that when
451  * there is an equality depending on the element at level 'level', there are
452  * no more (in)equalities depending on this element.
453  *
454  * The simplified form of isl automatically satisfies this condition.
455  */
cloog_constraint_set_normalize(CloogConstraintSet * matrix,int level)456 void cloog_constraint_set_normalize(CloogConstraintSet *matrix, int level)
457 {
458 }
459 
460 
461 
462 /**
463  * cloog_constraint_set_copy function:
464  * this functions builds and returns a "soft copy" of a CloogConstraintSet data
465  * structure.
466  *
467  * NOTE: this function used to return a "hard copy" (not a pointer copy) but isl
468  * doesn't provide isl_basic_set_dup() anymore and a soft copy works as well.
469  */
cloog_constraint_set_copy(CloogConstraintSet * constraints)470 CloogConstraintSet *cloog_constraint_set_copy(CloogConstraintSet *constraints)
471 {
472 	isl_basic_set *bset;
473 	bset = cloog_constraints_set_to_isl(constraints);
474 	return cloog_constraint_set_from_isl_basic_set(isl_basic_set_copy(bset));
475 }
476 
477 
478 /**
479  * cloog_constraint_set_simplify function:
480  * this function simplify all constraints inside the matrix "matrix" thanks to
481  * an equality matrix "equal" that gives for some elements of the affine
482  * constraint an equality with other elements, preferably constants.
483  * For instance, if a row of the matrix contains i+j+3>=0 and the equality
484  * matrix gives i=n and j=2, the constraint is simplified to n+3>=0. The
485  * simplified constraints are returned back inside a new simplified matrix.
486  * - matrix is the set of constraints to simplify,
487  * - equal is the matrix of equalities,
488  * - level is a level we don't want to simplify (-1 if none),
489  * - nb_par is the number of parameters of the program.
490  **
491  * isl should have performed these simplifications already in isl_set_gist.
492  */
cloog_constraint_set_simplify(CloogConstraintSet * matrix,CloogEqualities * equal,int level,int nb_par)493 CloogConstraintSet *cloog_constraint_set_simplify(CloogConstraintSet *matrix,
494 	CloogEqualities *equal, int level, int nb_par)
495 {
496 	return cloog_constraint_set_copy(matrix);
497 }
498 
499 
constraint_cloog_dim_to_isl_dim(CloogConstraint * constraint,int pos)500 static struct cloog_isl_dim constraint_cloog_dim_to_isl_dim(
501 					CloogConstraint *constraint, int pos)
502 {
503 	enum isl_dim_type types[] = { isl_dim_set, isl_dim_div, isl_dim_param };
504 	int i;
505 	struct cloog_isl_dim ci_dim;
506 
507 	for (i = 0; i < 3; ++i) {
508 		isl_constraint *c = cloog_constraint_to_isl(constraint);
509 		unsigned dim = isl_constraint_dim(c, types[i]);
510 		if (pos < dim) {
511 			ci_dim.type = types[i];
512 			ci_dim.pos = pos;
513 			return ci_dim;
514 		}
515 		pos -= dim;
516 	}
517 
518     ci_dim.pos = -1;
519     return ci_dim;
520 }
521 
div_expr(CloogConstraint * constraint,int pos,CloogNames * names)522 static struct clast_expr *div_expr(CloogConstraint *constraint, int pos,
523 					CloogNames *names)
524 {
525 	int i, nb_elts;
526 	unsigned dim = cloog_constraint_total_dimension(constraint);
527 	isl_val *c;
528 	struct clast_reduction *r;
529 	struct clast_expr *e = NULL;
530 	isl_aff *div;
531 	cloog_int_t cint;
532 
533 	cloog_int_init(cint);
534 	div = isl_constraint_get_div(cloog_constraint_to_isl(constraint), pos);
535 
536 	for (i = 0, nb_elts = 0; i < dim; ++i) {
537 		struct cloog_isl_dim dim;
538 
539 		dim = constraint_cloog_dim_to_isl_dim(constraint, i);
540 		if (dim.pos <= -1)
541 			continue;
542 
543 		if (dim.type == isl_dim_set)
544 			dim.type = isl_dim_in;
545 		c = isl_aff_get_coefficient_val(div, dim.type, dim.pos);
546 		if (!isl_val_is_zero(c))
547 			++nb_elts;
548 
549 		isl_val_free(c);
550 	}
551 	c = isl_aff_get_constant_val(div);
552 	if (!isl_val_is_zero(c))
553 		++nb_elts;
554 	isl_val_free(c);
555 
556 	r = new_clast_reduction(clast_red_sum, nb_elts);
557 	for (i = 0, nb_elts = 0; i < dim; ++i) {
558 		struct clast_expr *v;
559 		struct cloog_isl_dim dim;
560 
561 		dim = constraint_cloog_dim_to_isl_dim(constraint, i);
562 		if (dim.pos <= -1)
563 			continue;
564 
565 		if (dim.type == isl_dim_set)
566 			dim.type = isl_dim_in;
567 		c = isl_aff_get_coefficient_val(div, dim.type, dim.pos);
568 		if (isl_val_is_zero(c)){
569 			isl_val_free(c);
570 			continue;
571 		}
572 
573 		v = cloog_constraint_variable_expr(constraint, 1 + i, names);
574 
575 		/* We are interested only in the numerator */
576 		cloog_int_set_si(cint, isl_val_get_num_si(c));
577 		r->elts[nb_elts++] = &new_clast_term(cint, v)->expr;
578 
579 		isl_val_free(c);
580 	}
581 
582 	c = isl_aff_get_constant_val(div);
583 	if (!isl_val_is_zero(c)) {
584 		/* We are interested only in the numerator */
585 		cloog_int_set_si(cint, isl_val_get_num_si(c));
586 		r->elts[nb_elts++] = &new_clast_term(cint, NULL)->expr;
587 	}
588 	isl_val_free(c);
589 
590 	c = isl_aff_get_denominator_val(div);
591 	isl_val_to_cloog_int(c, &cint);
592 	isl_val_free(c);
593 	e = &new_clast_binary(clast_bin_fdiv, &r->expr, cint)->expr;
594 
595 	cloog_int_clear(cint);
596 
597 	isl_aff_free(div);
598 
599 	return e;
600 }
601 
602 /**
603  * Return clast_expr corresponding to the variable "level" (1 based) in
604  * the given constraint.
605  */
cloog_constraint_variable_expr(CloogConstraint * constraint,int level,CloogNames * names)606 struct clast_expr *cloog_constraint_variable_expr(CloogConstraint *constraint,
607 	int level, CloogNames *names)
608 {
609 	struct cloog_isl_dim dim;
610 	const char *name;
611 
612 	assert(constraint);
613 
614 	dim = constraint_cloog_dim_to_isl_dim(constraint, level - 1);
615 	if (dim.type == isl_dim_div)
616 		return div_expr(constraint, dim.pos, names);
617 
618 	if (dim.type == isl_dim_set)
619 		name = cloog_names_name_at_level(names, level);
620 	else
621 		name = names->parameters[dim.pos];
622 
623 	return &new_clast_name(name)->expr;
624 }
625 
626 
627 /**
628  * Return true if constraint c involves variable v (zero-based).
629  */
cloog_constraint_involves(CloogConstraint * constraint,int v)630 int cloog_constraint_involves(CloogConstraint *constraint, int v)
631 {
632   int res = 0;
633 
634   isl_val* const val = cloog_constraint_coefficient_get_val(constraint, v);
635   if (val)
636   {
637     res = !isl_val_is_zero(val);
638     isl_val_free(val);
639   }
640 
641   return res;
642 }
643 
cloog_constraint_is_lower_bound(CloogConstraint * constraint,int v)644 int cloog_constraint_is_lower_bound(CloogConstraint *constraint, int v)
645 {
646   int res = 0;
647 
648   isl_val* const val = cloog_constraint_coefficient_get_val(constraint, v);
649   if (val)
650   {
651     res = isl_val_is_pos(val);
652     isl_val_free(val);
653   }
654 
655   return res;
656 }
657 
cloog_constraint_is_upper_bound(CloogConstraint * constraint,int v)658 int cloog_constraint_is_upper_bound(CloogConstraint *constraint, int v)
659 {
660   int res = 0;
661 
662   isl_val* const val = cloog_constraint_coefficient_get_val(constraint, v);
663   if (val)
664   {
665     res = isl_val_is_neg(val);
666     isl_val_free(val);
667   }
668 
669   return res;
670 }
671 
cloog_constraint_is_equality(CloogConstraint * constraint)672 int cloog_constraint_is_equality(CloogConstraint *constraint)
673 {
674 	return isl_constraint_is_equality(cloog_constraint_to_isl(constraint));
675 }
676 
677 typedef struct cloog_drop_constraint_data
678 {
679   isl_constraint* constraint;
680   isl_basic_set* basic_set;
681 } cloog_drop_constraint_data;
682 
cloog_basic_set_ignore_constraint(__isl_take isl_constraint * const c,void * const user)683 static inline isl_stat cloog_basic_set_ignore_constraint(
684     __isl_take isl_constraint* const c, void* const user)
685 {
686   cloog_drop_constraint_data* const data = user;
687   isl_constraint* const ignore = data->constraint;
688 
689   isl_aff* a1 = isl_constraint_get_aff(c);
690   isl_aff* a2 = isl_constraint_get_aff(ignore);
691   isl_pw_aff* pw1 = isl_pw_aff_from_aff(a1);
692   isl_pw_aff* pw2 = isl_pw_aff_from_aff(a2);
693 
694   if (!isl_pw_aff_is_equal(pw1, pw2))
695     data->basic_set = isl_basic_set_add_constraint(data->basic_set, c);
696   else
697     isl_constraint_free(c);
698 
699   isl_pw_aff_free(pw1);
700   isl_pw_aff_free(pw2);
701 
702   return isl_stat_ok;
703 }
704 
cloog_constraint_set_drop_constraint(CloogConstraintSet * constraints,CloogConstraint * constraint)705 CloogConstraintSet *cloog_constraint_set_drop_constraint(
706 	CloogConstraintSet *constraints, CloogConstraint *constraint)
707 {
708   isl_basic_set* bset = cloog_constraints_set_to_isl(constraints);
709   isl_constraint* c = cloog_constraint_to_isl(cloog_constraint_copy(constraint));
710 
711   isl_space* space = isl_basic_set_get_space(bset);
712   isl_basic_set* result = isl_basic_set_universe(space);
713   cloog_drop_constraint_data data = { .basic_set = result, .constraint = c, };
714   isl_basic_set_foreach_constraint(
715       bset, cloog_basic_set_ignore_constraint, &data);
716 
717   isl_basic_set_free(bset);
718   isl_constraint_free(c);
719 
720   result = data.basic_set;
721   return cloog_constraint_set_from_isl_basic_set(result);
722 }
723 
cloog_constraint_coefficient_get(CloogConstraint * constraint,int var,cloog_int_t * val)724 void cloog_constraint_coefficient_get(CloogConstraint *constraint,
725 			int var, cloog_int_t *val)
726 {
727 	struct cloog_isl_dim dim;
728 	isl_constraint *c;
729 	isl_val *ival;
730 
731 	if (!constraint)
732 		val = NULL;
733 
734 	dim = constraint_cloog_dim_to_isl_dim(constraint, var);
735 	c = cloog_constraint_to_isl(constraint);
736 	ival = isl_constraint_get_coefficient_val(c, dim.type, dim.pos);
737 
738 	isl_val_to_cloog_int(ival, val);
739 	isl_val_free(ival);
740 }
741 
cloog_constraint_coefficient_get_val(CloogConstraint * constraint,int var)742 isl_val *cloog_constraint_coefficient_get_val(CloogConstraint *constraint,
743 			int var)
744 {
745   if (!constraint)
746     return NULL;
747 
748   struct cloog_isl_dim dim = constraint_cloog_dim_to_isl_dim(constraint, var);
749   isl_constraint* const c = cloog_constraint_to_isl(constraint);
750 
751   isl_val *val = NULL;
752   if (dim.pos > -1)
753     val = isl_constraint_get_coefficient_val(c, dim.type, dim.pos);
754 
755   return val;
756 }
757 
758 
759 
cloog_constraint_coefficient_set(CloogConstraint * constraint,int var,cloog_int_t val)760 void cloog_constraint_coefficient_set(CloogConstraint *constraint,
761 			int var, cloog_int_t val)
762 {
763   struct cloog_isl_dim dim;
764   isl_constraint *c;
765 
766   assert(constraint);
767 
768   dim = constraint_cloog_dim_to_isl_dim(constraint, var);
769   if (dim.pos <= -1)
770     return;
771 
772   c = cloog_constraint_to_isl(constraint);
773   isl_constraint_set_coefficient_val(c, dim.type, dim.pos,
774       cloog_int_to_isl_val(isl_constraint_get_ctx(c), val));
775 }
776 
cloog_constraint_constant_get(CloogConstraint * constraint,cloog_int_t * val)777 void cloog_constraint_constant_get(CloogConstraint *constraint, cloog_int_t *val)
778 {
779 	isl_val *ival;
780 	ival = isl_constraint_get_constant_val(cloog_constraint_to_isl(constraint));
781 	isl_val_to_cloog_int(ival, val);
782 	isl_val_free(ival);
783 }
784 
785 
cloog_constraint_constant_get_val(CloogConstraint * constraint)786 __isl_give isl_val *cloog_constraint_constant_get_val(CloogConstraint *constraint)
787 {
788 	return isl_constraint_get_constant_val(cloog_constraint_to_isl(constraint));
789 }
790 
791 
792 
793 /**
794  * Copy the coefficient of constraint c into dst in PolyLib order,
795  * i.e., first the coefficients of the variables, then the coefficients
796  * of the parameters and finally the constant.
797  */
cloog_constraint_copy_coefficients(CloogConstraint * constraint,cloog_int_t * dst)798 void cloog_constraint_copy_coefficients(CloogConstraint *constraint,
799 					cloog_int_t *dst)
800 {
801 	int i;
802 	unsigned dim;
803 
804 	dim = cloog_constraint_total_dimension(constraint);
805 
806 	for (i = 0; i < dim; ++i)
807 		cloog_constraint_coefficient_get(constraint, i, dst+i);
808 	cloog_constraint_constant_get(constraint, dst+dim);
809 }
810 
cloog_constraint_invalid(void)811 CloogConstraint *cloog_constraint_invalid(void)
812 {
813 	return NULL;
814 }
815 
cloog_constraint_is_valid(CloogConstraint * constraint)816 int cloog_constraint_is_valid(CloogConstraint *constraint)
817 {
818 	return constraint != NULL;
819 }
820 
cloog_constraint_total_dimension(CloogConstraint * constraint)821 int cloog_constraint_total_dimension(CloogConstraint *constraint)
822 {
823 	isl_constraint *c;
824 	c = cloog_constraint_to_isl(constraint);
825 	return isl_constraint_dim(c, isl_dim_all);
826 }
827 
828 
829 /**
830  * Check whether there is any need for the constraint "upper" on
831  * "level" to get reduced.
832  * In case of the isl backend, there should be no need to do so
833  * if the level corresponds to an existentially quantified variable.
834  * Moreover, the way reduction is performed does not work for such
835  * variables since its position might chance during the construction
836  * of a set for reduction.
837  */
cloog_constraint_needs_reduction(CloogConstraint * upper,int level)838 int cloog_constraint_needs_reduction(CloogConstraint *upper, int level)
839 {
840 	isl_basic_set *bset;
841 	isl_constraint *c;
842 	struct cloog_isl_dim dim;
843 
844 	c = cloog_constraint_to_isl(upper);
845 	bset = isl_basic_set_from_constraint(isl_constraint_copy(c));
846 	dim = basic_set_cloog_dim_to_isl_dim(bset, level - 1);
847 	isl_basic_set_free(bset);
848 
849 	return dim.type == isl_dim_set;
850 }
851 
852 
853 /**
854  * Create a CloogConstraintSet containing enough information to perform
855  * a reduction on the upper equality (in this case lower is an invalid
856  * CloogConstraint) or the pair of inequalities upper and lower
857  * from within insert_modulo_guard.
858  * In the isl backend, we return a CloogConstraintSet containing both
859  * bounds, as the stride may change during the reduction and we may
860  * need to recompute the bound on the modulo expression.
861  */
cloog_constraint_set_for_reduction(CloogConstraint * upper,CloogConstraint * lower)862 CloogConstraintSet *cloog_constraint_set_for_reduction(CloogConstraint *upper,
863 	CloogConstraint *lower)
864 {
865 	struct isl_basic_set *bset;
866 	isl_constraint *c;
867 
868 	c = cloog_constraint_to_isl(upper);
869 	bset = isl_basic_set_from_constraint(isl_constraint_copy(c));
870 	if (cloog_constraint_is_valid(lower)) {
871 		c = cloog_constraint_to_isl(lower);
872 		bset = isl_basic_set_add_constraint(bset,
873 						    isl_constraint_copy(c));
874 	}
875 	return cloog_constraint_set_from_isl_basic_set(bset);
876 }
877 
878 
add_constant_term(CloogConstraint * c,void * user)879 static int add_constant_term(CloogConstraint *c, void *user)
880 {
881 	isl_val **bound = (isl_val **)user;
882 	isl_val *v;
883 
884 	v = cloog_constraint_constant_get_val(c);
885 	*bound = isl_val_add(*bound, v);
886 
887 	return 0;
888 }
889 
890 
891 /* Return an isl_basic_set representation of the equality stored
892  * at position i in the given CloogEqualities.
893  */
equality_to_basic_set(CloogEqualities * equal,int i)894 static __isl_give isl_basic_set *equality_to_basic_set(CloogEqualities *equal,
895 	int i)
896 {
897 	isl_constraint *c;
898 	isl_basic_set *bset;
899 	unsigned nparam;
900 	unsigned nvar;
901 
902 	c = isl_constraint_copy(equal->constraints[i]);
903 	bset = isl_basic_set_from_constraint(c);
904 	nparam = isl_basic_set_dim(bset, isl_dim_param);
905 	nvar = isl_basic_set_dim(bset, isl_dim_set);
906 	bset = isl_basic_set_add_dims(bset, isl_dim_set,
907 				      equal->total_dim - (nparam + nvar));
908 	return bset;
909 }
910 
911 /**
912  * Reduce the modulo guard expressed by "constraints" using equalities
913  * found in outer nesting levels (stored in "equal").
914  * The modulo guard may be an equality or a pair of inequalities.
915  * In case of a pair of inequalities, *bound contains the bound on the
916  * corresponding modulo expression.  If any reduction is performed
917  * then this bound is recomputed.
918  *
919  * "level" may not correspond to an existentially quantified variable.
920  *
921  * We first check if there are any equalities we can use.  If not,
922  * there is again nothing to reduce.
923  * For the actual reduction, we use isl_basic_set_gist, but this
924  * function will only perform the reduction we want here if the
925  * the variable that imposes the modulo constraint has been projected
926  * out (i.e., turned into an existentially quantified variable).
927  * After the call to isl_basic_set_gist, we need to move the
928  * existential variable back into the position where the calling
929  * function expects it (assuming there are any constraints left).
930  * We do this by adding an equality between the given dimension and
931  * the existentially quantified variable.
932  *
933  * If there are no existentially quantified variables left, then
934  * we don't need to add this equality.
935  * If, on the other hand, the resulting basic set involves more
936  * than one existentially quantified variable, then the caller
937  * will not be able to handle the result, so we just return the
938  * original input instead.
939  */
cloog_constraint_set_reduce(CloogConstraintSet * constraints,int level,CloogEqualities * equal,int nb_par,cloog_int_t * bound)940 CloogConstraintSet *cloog_constraint_set_reduce(CloogConstraintSet *constraints,
941 	int level, CloogEqualities *equal, int nb_par, cloog_int_t *bound)
942 {
943 	int j;
944 	isl_space *idim;
945 	struct isl_basic_set *eq;
946 	struct isl_basic_map *id;
947 	struct cloog_isl_dim dim;
948 	struct isl_constraint *c;
949 	unsigned constraints_dim;
950 	unsigned n_div;
951 	isl_basic_set *bset, *orig;
952 
953 	bset = cloog_constraints_set_to_isl(constraints);
954 	orig = isl_basic_set_copy(bset);
955 	dim = set_cloog_dim_to_isl_dim(constraints, level - 1);
956 	assert(dim.type == isl_dim_set);
957 
958 	eq = NULL;
959 	for (j = 0; j < level - 1; ++j) {
960 		isl_basic_set *bset_j;
961 		if (equal->types[j] != EQTYPE_EXAFFINE)
962 			continue;
963 		bset_j = equality_to_basic_set(equal, j);
964 		if (!eq)
965 			eq = bset_j;
966 		else
967 			eq = isl_basic_set_intersect(eq, bset_j);
968 	}
969 	if (!eq) {
970 		isl_basic_set_free(orig);
971 		return cloog_constraint_set_from_isl_basic_set(bset);
972 	}
973 
974 	idim = isl_space_map_from_set(isl_basic_set_get_space(bset));
975 	id = isl_basic_map_identity(idim);
976 	id = isl_basic_map_remove_dims(id, isl_dim_out, dim.pos, 1);
977 	bset = isl_basic_set_apply(bset, isl_basic_map_copy(id));
978 	bset = isl_basic_set_apply(bset, isl_basic_map_reverse(id));
979 
980 	constraints_dim = isl_basic_set_dim(bset, isl_dim_set);
981 	eq = isl_basic_set_remove_dims(eq, isl_dim_set, constraints_dim,
982 			isl_basic_set_dim(eq, isl_dim_set) - constraints_dim);
983 	bset = isl_basic_set_gist(bset, eq);
984 	n_div = isl_basic_set_dim(bset, isl_dim_div);
985 	if (n_div > 1) {
986 		isl_basic_set_free(bset);
987 		return cloog_constraint_set_from_isl_basic_set(orig);
988 	}
989 	if (n_div < 1) {
990 		isl_basic_set_free(orig);
991 		return cloog_constraint_set_from_isl_basic_set(bset);
992 	}
993 
994 	c = isl_equality_alloc(isl_basic_set_get_local_space(bset));
995 	c = isl_constraint_set_coefficient_si(c, isl_dim_div, 0, 1);
996 	c = isl_constraint_set_coefficient_si(c, isl_dim_set, dim.pos, -1);
997 	bset = isl_basic_set_add_constraint(bset, c);
998 
999 	cloog_int_set_si(*bound, 0);
1000 	isl_val *v = cloog_int_to_isl_val(isl_basic_set_get_ctx(bset), *bound);
1001 	constraints = cloog_constraint_set_from_isl_basic_set(bset);
1002 	cloog_constraint_set_foreach_constraint(constraints,
1003 	                add_constant_term, &v);
1004 	isl_val_to_cloog_int(v, bound); //return the value to bound
1005 
1006 	isl_val_free(v);
1007 	isl_basic_set_free(orig);
1008 	return cloog_constraint_set_from_isl_basic_set(bset);
1009 }
1010 
cloog_constraint_copy(CloogConstraint * constraint)1011 CloogConstraint *cloog_constraint_copy(CloogConstraint *constraint)
1012 {
1013 	return cloog_constraint_from_isl_constraint(
1014 		isl_constraint_copy(cloog_constraint_to_isl(constraint)));
1015 }
1016 
cloog_constraint_release(CloogConstraint * constraint)1017 void cloog_constraint_release(CloogConstraint *constraint)
1018 {
1019 	isl_constraint_free(cloog_constraint_to_isl(constraint));
1020 }
1021 
1022 struct cloog_isl_foreach {
1023 	int (*fn)(CloogConstraint *constraint, void *user);
1024 	void *user;
1025 };
1026 
cloog_isl_foreach_cb(__isl_take isl_constraint * c,void * user)1027 static int cloog_isl_foreach_cb(__isl_take isl_constraint *c, void *user)
1028 {
1029 	struct cloog_isl_foreach *data = (struct cloog_isl_foreach *)user;
1030 	int ret;
1031 
1032 	if (isl_constraint_is_div_constraint(c)) {
1033 		isl_constraint_free(c);
1034 		return 0;
1035 	}
1036 
1037 	ret = data->fn(cloog_constraint_from_isl_constraint(c), data->user);
1038 
1039 	isl_constraint_free(c);
1040 
1041 	return ret;
1042 }
1043 
cloog_constraint_set_foreach_constraint(CloogConstraintSet * constraints,int (* fn)(CloogConstraint * constraint,void * user),void * user)1044 int cloog_constraint_set_foreach_constraint(CloogConstraintSet *constraints,
1045 	int (*fn)(CloogConstraint *constraint, void *user), void *user)
1046 {
1047 	struct cloog_isl_foreach data = { fn, user };
1048 	isl_basic_set *bset;
1049 
1050 	bset = cloog_constraints_set_to_isl(constraints);
1051 	return isl_basic_set_foreach_constraint(bset,
1052 						cloog_isl_foreach_cb, &data);
1053 }
1054 
cloog_equal_constraint(CloogEqualities * equal,int j)1055 CloogConstraint *cloog_equal_constraint(CloogEqualities *equal, int j)
1056 {
1057 	isl_constraint *c;
1058 
1059 	c = isl_constraint_copy(equal->constraints[j]);
1060 	return cloog_constraint_from_isl_constraint(c);
1061 }
1062 
1063 /* Given a stride constraint on iterator i (specified by level) of the form
1064  *
1065  *	i = f(outer iterators) + stride * f(existentials)
1066  *
1067  * extract f as an isl_aff.
1068  */
extract_stride_offset(__isl_keep isl_constraint * c,int level,CloogStride * stride)1069 static isl_aff *extract_stride_offset(__isl_keep isl_constraint *c,
1070 	int level, CloogStride *stride)
1071 {
1072 	int i;
1073 	isl_space *dim = isl_constraint_get_space(c);
1074 	isl_local_space *ls = isl_local_space_from_space(dim);
1075 	isl_aff *offset = isl_aff_zero_on_domain(ls);
1076 	isl_val *u;
1077 	unsigned nparam, nvar;
1078 
1079 	nparam = isl_constraint_dim(c, isl_dim_param);
1080 	nvar = isl_constraint_dim(c, isl_dim_set);
1081 
1082 	for (i = 0; i < nparam; ++i) {
1083 		u = isl_constraint_get_coefficient_val(c, isl_dim_param, i);
1084 		u = isl_val_mul(u, cloog_int_to_isl_val(isl_constraint_get_ctx(c), stride->factor));
1085 		offset = isl_aff_set_coefficient_val(offset, isl_dim_param, i, u);
1086 	}
1087 	for (i = 0; i < nvar; ++i) {
1088 		if (i == level - 1)
1089 			continue;
1090 		u = isl_constraint_get_coefficient_val(c, isl_dim_set, i);
1091 		u = isl_val_mul(u, cloog_int_to_isl_val(isl_constraint_get_ctx(c), stride->factor));
1092 		offset = isl_aff_set_coefficient_val(offset, isl_dim_in, i, u);
1093 	}
1094 	u = isl_constraint_get_constant_val(c);
1095 	u = isl_val_mul(u, cloog_int_to_isl_val(isl_constraint_get_ctx(c), stride->factor));
1096 	offset = isl_aff_set_constant_val(offset, u);
1097 
1098 	return offset;
1099 }
1100 
1101 /* Update the given lower bound on level such that it satisfies the stride
1102  * constraint.  The computation performed here is essentially the same
1103  * as that performed in constraint_stride_lower_c.
1104  *
1105  * We update the constraint
1106  *
1107  *	a i + f >= 0
1108  *
1109  * to
1110  *
1111  *	i >= s * ceil((-f/a - d)/s) + d
1112  *
1113  * with s the stride and d the offset encoded in the stride constraint.
1114  */
cloog_constraint_stride_lower_bound(CloogConstraint * c,int level,CloogStride * stride)1115 CloogConstraint *cloog_constraint_stride_lower_bound(CloogConstraint *c,
1116 	int level, CloogStride *stride)
1117 {
1118 	isl_constraint *stride_c = cloog_constraint_to_isl(stride->constraint);
1119 	isl_constraint *bound = cloog_constraint_to_isl(c);
1120 	isl_aff *offset;
1121 	isl_aff *lower;
1122 
1123 	lower = isl_constraint_get_bound(bound, isl_dim_set, level - 1);
1124 	isl_constraint_free(bound);
1125 
1126 	offset = extract_stride_offset(stride_c, level, stride);
1127 
1128 	lower = isl_aff_sub(lower, isl_aff_copy(offset));
1129 	lower = isl_aff_scale_down_val(lower, cloog_int_to_isl_val(isl_constraint_get_ctx(stride_c), stride->stride));
1130 	lower = isl_aff_ceil(lower);
1131 	lower = isl_aff_scale_val(lower, cloog_int_to_isl_val(isl_constraint_get_ctx(stride_c), stride->stride));
1132 	lower = isl_aff_add(lower, offset);
1133 	lower = isl_aff_neg(lower);
1134 	lower = isl_aff_add_coefficient_si(lower, isl_dim_in, level - 1, 1);
1135 
1136 	bound = isl_inequality_from_aff(lower);
1137 
1138 	return cloog_constraint_from_isl_constraint(bound);
1139 }
1140