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