1 
2    /**-------------------------------------------------------------------**
3     **                               CLooG                               **
4     **-------------------------------------------------------------------**
5     **                          constraintset.c                          **
6     **-------------------------------------------------------------------**
7     **                    First version: april 17th 2005                 **
8     **-------------------------------------------------------------------**/
9 
10 
11 /******************************************************************************
12  *               CLooG : the Chunky Loop Generator (experimental)             *
13  ******************************************************************************
14  *                                                                            *
15  * Copyright (C) 2005 Cedric Bastoul                                          *
16  *                                                                            *
17  * This library is free software; you can redistribute it and/or              *
18  * modify it under the terms of the GNU Lesser General Public                 *
19  * License as published by the Free Software Foundation; either               *
20  * version 2.1 of the License, or (at your option) any later version.         *
21  *                                                                            *
22  * This library is distributed in the hope that it will be useful,            *
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          *
25  * Lesser General Public License for more details.                            *
26  *                                                                            *
27  * You should have received a copy of the GNU Lesser General Public           *
28  * License along with this library; if not, write to the Free Software        *
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor,                         *
30  * Boston, MA  02110-1301  USA                                                *
31  *                                                                            *
32  * CLooG, the Chunky Loop Generator                                           *
33  * Written by Cedric Bastoul, Cedric.Bastoul@inria.fr                         *
34  *                                                                            *
35  ******************************************************************************/
36 /* CAUTION: the english used for comments is probably the worst you ever read,
37  *          please feel free to correct and improve it !
38  */
39 
40 
41 # include <stdlib.h>
42 # include <stdio.h>
43 # include <ctype.h>
44 #include <cloog/cloog.h>
45 #include <cloog/matrix/constraintset.h>
46 
47 
48 #define ALLOC(type) (type*)malloc(sizeof(type))
49 #define ALLOCN(type,n) (type*)malloc((n)*sizeof(type))
50 
51 
52 CloogConstraint *cloog_constraint_first(CloogConstraintSet *constraints);
53 CloogConstraint *cloog_constraint_next(CloogConstraint *constraint);
54 
55 
cloog_constraint_set_from_cloog_matrix(CloogMatrix * M)56 CloogConstraintSet *cloog_constraint_set_from_cloog_matrix(CloogMatrix *M)
57 {
58 	return (CloogConstraintSet *)M;
59 }
60 
61 
cloog_constraint_set_free(CloogConstraintSet * constraints)62 void cloog_constraint_set_free(CloogConstraintSet *constraints)
63 {
64 	cloog_matrix_free(&constraints->M);
65 }
66 
cloog_constraint_set_contains_level(CloogConstraintSet * constraints,int level,int nb_parameters)67 int cloog_constraint_set_contains_level(CloogConstraintSet *constraints,
68 			int level, int nb_parameters)
69 {
70 	return constraints->M.NbColumns - 2 - nb_parameters >= level;
71 }
72 
73 /* Check if the variable at position level is defined by an
74  * equality.  If so, return the row number.  Otherwise, return -1.
75  *
76  * If there is an equality, we can print it directly -no ambiguity-.
77  * PolyLib can give more than one equality, we use just the first one
78  * (this is a PolyLib problem, but all equalities are equivalent).
79  */
cloog_constraint_set_defining_equality(CloogConstraintSet * constraints,int level)80 CloogConstraint *cloog_constraint_set_defining_equality(CloogConstraintSet *constraints, int level)
81 {
82 	CloogConstraint *constraint = ALLOC(CloogConstraint);
83 	int i;
84 
85 	constraint->set = constraints;
86 	for (i = 0; i < constraints->M.NbRows; i++)
87 		if (cloog_int_is_zero(constraints->M.p[i][0]) &&
88 		    !cloog_int_is_zero(constraints->M.p[i][level])) {
89 			constraint->line = &constraints->M.p[i];
90 			return constraint;
91 		    }
92 	free(constraint);
93 	return cloog_constraint_invalid();
94 }
95 
96 /* Check if the variable (e) at position level is defined by a
97  * pair of inequalities
98  *		 <a, i> + -m e +  <b, p> + k1 >= 0
99  *		<-a, i> +  m e + <-b, p> + k2 >= 0
100  * with 0 <= k1 + k2 < m
101  * If so return the row number of the upper bound and set *lower
102  * to the row number of the lower bound.  If not, return -1.
103  *
104  * If the variable at position level occurs in any other constraint,
105  * then we currently return -1.  The modulo guard that we would generate
106  * would still be correct, but we would also need to generate
107  * guards corresponding to the other constraints, and this has not
108  * been implemented yet.
109  */
cloog_constraint_set_defining_inequalities(CloogConstraintSet * constraints,int level,CloogConstraint ** lower,int nb_par)110 CloogConstraint *cloog_constraint_set_defining_inequalities(CloogConstraintSet *constraints,
111 	int level, CloogConstraint **lower, int nb_par)
112 {
113 	int i, j, k;
114 	cloog_int_t m;
115 	CloogMatrix *matrix = &constraints->M;
116 	unsigned len = matrix->NbColumns - 2;
117 	unsigned nb_iter = len - nb_par;
118 	CloogConstraint *constraint;
119 
120 	for (i = 0; i < matrix->NbRows; i++) {
121 		if (cloog_int_is_zero(matrix->p[i][level]))
122 			continue;
123 		if (cloog_int_is_zero(matrix->p[i][0]))
124 			return cloog_constraint_invalid();
125 		if (cloog_int_is_one(matrix->p[i][level]))
126 			return cloog_constraint_invalid();
127 		if (cloog_int_is_neg_one(matrix->p[i][level]))
128 			return cloog_constraint_invalid();
129 		if (cloog_seq_first_non_zero(matrix->p[i]+level+1,
130 				    (1+nb_iter)-(level+1)) != -1)
131 			return cloog_constraint_invalid();
132 		for (j = i+1; j < matrix->NbRows; ++j) {
133 			if (cloog_int_is_zero(matrix->p[j][level]))
134 				continue;
135 			if (cloog_int_is_zero(matrix->p[j][0]))
136 				return cloog_constraint_invalid();
137 			if (cloog_int_is_one(matrix->p[j][level]))
138 				return cloog_constraint_invalid();
139 			if (cloog_int_is_neg_one(matrix->p[j][level]))
140 				return cloog_constraint_invalid();
141 			if (cloog_seq_first_non_zero(matrix->p[j]+level+1,
142 					    (1+nb_iter)-(level+1)) != -1)
143 				return cloog_constraint_invalid();
144 
145 			cloog_int_init(m);
146 			cloog_int_add(m, matrix->p[i][1+len], matrix->p[j][1+len]);
147 			if (cloog_int_is_neg(m) ||
148 			    cloog_int_abs_ge(m, matrix->p[i][level])) {
149 				cloog_int_clear(m);
150 				return cloog_constraint_invalid();
151 			}
152 			cloog_int_clear(m);
153 
154 			if (!cloog_seq_is_neg(matrix->p[i]+1, matrix->p[j]+1,
155 						len))
156 				return cloog_constraint_invalid();
157 			for (k = j+1; k < matrix->NbRows; ++k)
158 				if (!cloog_int_is_zero(matrix->p[k][level]))
159 					return cloog_constraint_invalid();
160 			*lower = ALLOC(CloogConstraint);
161 			constraint = ALLOC(CloogConstraint);
162 			(*lower)->set = constraints;
163 			constraint->set = constraints;
164 			if (cloog_int_is_pos(matrix->p[i][level])) {
165 				(*lower)->line = &matrix->p[i];
166 				constraint->line = &matrix->p[j];
167 			} else {
168 				(*lower)->line = &matrix->p[j];
169 				constraint->line = &matrix->p[i];
170 			}
171 			return constraint;
172 		}
173 	}
174 	return cloog_constraint_invalid();
175 }
176 
cloog_constraint_set_total_dimension(CloogConstraintSet * constraints)177 int cloog_constraint_set_total_dimension(CloogConstraintSet *constraints)
178 {
179 	return constraints->M.NbColumns - 2;
180 }
181 
cloog_constraint_set_n_iterators(CloogConstraintSet * constraint,int nb_par)182 int cloog_constraint_set_n_iterators(CloogConstraintSet *constraint, int nb_par)
183 {
184 	return cloog_constraint_set_total_dimension(constraint) - nb_par;
185 }
186 
cloog_equal_total_dimension(CloogEqualities * equal)187 int cloog_equal_total_dimension(CloogEqualities *equal)
188 {
189 	return cloog_constraint_set_total_dimension(equal->constraints);
190 }
191 
cloog_constraint_total_dimension(CloogConstraint * constraint)192 int cloog_constraint_total_dimension(CloogConstraint *constraint)
193 {
194 	return cloog_constraint_set_total_dimension(constraint->set);
195 }
196 
197 
198 
199 /******************************************************************************
200  *                        Equalities spreading functions                      *
201  ******************************************************************************/
202 
203 
204 /* Equalities are stored inside a CloogMatrix data structure called "equal".
205  * This matrix has (nb_scattering + nb_iterators + 1) rows (i.e. total
206  * dimensions + 1, the "+ 1" is because a statement can be included inside an
207  * external loop without iteration domain), and (nb_scattering + nb_iterators +
208  * nb_parameters + 2) columns (all unknowns plus the scalar plus the equality
209  * type). The ith row corresponds to the equality "= 0" for the ith dimension
210  * iterator. The first column gives the equality type (0: no equality, then
211  * EQTYPE_* -see pprint.h-). At each recursion of pprint, if an equality for
212  * the current level is found, the corresponding row is updated. Then the
213  * equality if it exists is used to simplify expressions (e.g. if we have
214  * "i+1" while we know that "i=2", we simplify it in "3"). At the end of
215  * the pprint call, the corresponding row is reset to zero.
216  */
217 
cloog_equal_alloc(int n,int nb_levels,int nb_parameters)218 CloogEqualities *cloog_equal_alloc(int n, int nb_levels,
219 			int nb_parameters)
220 {
221     int i;
222     CloogEqualities *equal = ALLOC(CloogEqualities);
223 
224     equal->constraints = cloog_constraint_set_from_cloog_matrix(
225 		cloog_matrix_alloc(n, nb_levels + nb_parameters + 1));
226     equal->types = ALLOCN(int, n);
227     for (i = 0; i < n; ++i)
228 	equal->types[i] = EQTYPE_NONE;
229     return equal;
230 }
231 
cloog_equal_free(CloogEqualities * equal)232 void cloog_equal_free(CloogEqualities *equal)
233 {
234     cloog_matrix_free(&equal->constraints->M);
235     free(equal->types);
236     free(equal);
237 }
238 
cloog_equal_count(CloogEqualities * equal)239 int cloog_equal_count(CloogEqualities *equal)
240 {
241     return equal->constraints->M.NbRows;
242 }
243 
cloog_equal_constraints(CloogEqualities * equal)244 CloogConstraintSet *cloog_equal_constraints(CloogEqualities *equal)
245 {
246     return equal->constraints;
247 }
248 
249 
250 /**
251  * cloog_constraint_equal_type function :
252  * This function returns the type of the equality in the constraint (line) of
253  * (constraints) for the element (level). An equality is 'constant' iff all
254  * other factors are null except the constant one. It is a 'pure item' iff
255  * it is equal or opposite to a single variable or parameter.
256  * Otherwise it is an 'affine expression'.
257  * For instance:
258  *   i = -13 is constant, i = j, j = -M are pure items,
259  *   j = 2*M, i = j+1, 2*j = M are affine expressions.
260  *
261  * - constraints is the matrix of constraints,
262  * - level is the column number in equal of the element which is 'equal to',
263  **
264  * - July     3rd 2002: first version, called pprint_equal_isconstant.
265  * - July     6th 2002: adaptation for the 3 types.
266  * - June    15th 2005: (debug) expr = domain->Constraint[line] was evaluated
267  *                      before checking if line != ONE_TIME_LOOP. Since
268  *                      ONE_TIME_LOOP is -1, an invalid read was possible.
269  * - October 19th 2005: Removal of the once-time-loop specific processing.
270  */
cloog_constraint_equal_type(CloogConstraint * constraint,int level)271 static int cloog_constraint_equal_type(CloogConstraint *constraint, int level)
272 {
273   int i, one=0 ;
274   cloog_int_t *expr;
275 
276   expr = *constraint->line;
277 
278   if (!cloog_int_is_one(expr[level]) && !cloog_int_is_neg_one(expr[level]))
279     return EQTYPE_EXAFFINE;
280 
281   /* There is only one non null factor, and it must be +1 or -1 for
282    * iterators or parameters.
283    */
284   for (i = 1;i <= constraint->set->M.NbColumns-2; i++)
285   if (!cloog_int_is_zero(expr[i]) && (i != level)) {
286     if ((!cloog_int_is_one(expr[i]) && !cloog_int_is_neg_one(expr[i])) || (one != 0))
287     return EQTYPE_EXAFFINE ;
288     else
289     one = 1 ;
290   }
291   /* if the constant factor is non null, it must be alone. */
292   if (one != 0) {
293     if (!cloog_int_is_zero(expr[constraint->set->M.NbColumns-1]))
294     return EQTYPE_EXAFFINE ;
295   }
296   else
297   return EQTYPE_CONSTANT ;
298 
299   return EQTYPE_PUREITEM ;
300 }
301 
302 
cloog_equal_type(CloogEqualities * equal,int level)303 int cloog_equal_type(CloogEqualities *equal, int level)
304 {
305 	return equal->types[level-1];
306 }
307 
308 
309 /**
310  * cloog_equal_update function:
311  * this function updates a matrix of equalities where each row corresponds to
312  * the equality "=0" of an affine expression such that the entry at column
313  * "row" (="level") is not zero. This matrix is upper-triangular, except the
314  * row number "level-1" which has to be updated for the matrix to be triangular.
315  * This function achieves the processing.
316  * - equal is the matrix to be updated,
317  * - level gives the row that has to be updated (it is actually row "level-1"),
318  * - nb_par is the number of parameters of the program.
319  **
320  * - September 20th 2005: first version.
321  */
cloog_equal_update(CloogEqualities * equal,int level,int nb_par)322 static void cloog_equal_update(CloogEqualities *equal, int level, int nb_par)
323 { int i, j ;
324   cloog_int_t gcd, factor_level, factor_outer, temp_level, temp_outer;
325 
326   cloog_int_init(gcd);
327   cloog_int_init(temp_level);
328   cloog_int_init(temp_outer);
329   cloog_int_init(factor_level);
330   cloog_int_init(factor_outer);
331 
332   /* For each previous level, */
333   for (i=level-2;i>=0;i--)
334   { /* if the corresponding iterator is inside the current equality and is equal
335      * to something,
336      */
337     if (!cloog_int_is_zero(equal->constraints->M.p[level-1][i+1]) && equal->types[i])
338     { /* Compute the Greatest Common Divisor. */
339       cloog_int_gcd(gcd, equal->constraints->M.p[level-1][i+1],
340 			 equal->constraints->M.p[i][i+1]);
341 
342       /* Compute the factors to apply to each row vector element. */
343       cloog_int_divexact(factor_level, equal->constraints->M.p[i][i+1], gcd);
344       cloog_int_divexact(factor_outer, equal->constraints->M.p[level-1][i+1], gcd);
345 
346       /* Now update the row 'level'. */
347       /* - the iterators, up to level, */
348       for (j = 1; j <= level; j++) {
349         cloog_int_mul(temp_level, factor_level,
350 			equal->constraints->M.p[level-1][j]);
351         cloog_int_mul(temp_outer, factor_outer, equal->constraints->M.p[i][j]);
352         cloog_int_sub(equal->constraints->M.p[level-1][j], temp_level, temp_outer);
353       }
354       /* - between last useful iterator (level) and the first parameter, the
355        *   matrix is sparse (full of zeroes), we just do nothing there.
356        * - the parameters and the scalar.
357        */
358       for (j = 0; j < nb_par + 1; j++) {
359         cloog_int_mul(temp_level,factor_level,
360                        equal->constraints->M.p[level-1]
361 					[equal->constraints->M.NbColumns-j-1]);
362         cloog_int_mul(temp_outer,factor_outer,
363                        equal->constraints->M.p[i][equal->constraints->M.NbColumns-j-1]);
364         cloog_int_sub(equal->constraints->M.p[level-1]
365 					 [equal->constraints->M.NbColumns-j-1],
366 	               temp_level,temp_outer) ;
367       }
368     }
369   }
370 
371   /* Normalize (divide by GCD of all elements) the updated equality. */
372   cloog_seq_normalize(&(equal->constraints->M.p[level-1][1]),
373 			equal->constraints->M.NbColumns-1);
374 
375   cloog_int_clear(gcd);
376   cloog_int_clear(temp_level);
377   cloog_int_clear(temp_outer);
378   cloog_int_clear(factor_level);
379   cloog_int_clear(factor_outer);
380 }
381 
382 
383 /**
384  * cloog_equal_add function:
385  * This function updates the row (level-1) of the equality matrix (equal) with
386  * the row that corresponds to the row (line) of the matrix (matrix).
387  * - equal is the matrix of equalities,
388  * - matrix is the matrix of constraints,
389  * - level is the column number in matrix of the element which is 'equal to',
390  * - line is the line number in matrix of the constraint we want to study,
391  * - the infos structure gives the user all options on code printing and more.
392  **
393  * - July     2nd 2002: first version.
394  * - October 19th 2005: Addition of the once-time-loop specific processing.
395  */
cloog_equal_add(CloogEqualities * equal,CloogConstraintSet * constraints,int level,CloogConstraint * line,int nb_par)396 void cloog_equal_add(CloogEqualities *equal, CloogConstraintSet *constraints,
397 			int level, CloogConstraint *line, int nb_par)
398 {
399   int j;
400   CloogConstraint *i = cloog_constraint_invalid();
401   CloogMatrix *matrix = &constraints->M;
402 
403   /* If we are in the case of a loop running once, this means that the equality
404    * comes from an inequality. Here we find this inequality.
405    */
406   if (!cloog_constraint_is_valid(line))
407   { for (i = cloog_constraint_first(constraints);
408 	 cloog_constraint_is_valid(i); i = cloog_constraint_next(i))
409     if ((!cloog_int_is_zero(i->line[0][0]))&& (!cloog_int_is_zero(i->line[0][level])))
410     { line = i ;
411 
412       /* Since in once-time-loops, equalities derive from inequalities, we
413        * may have to offset the values. For instance if we have 2i>=3, the
414        * equality is in fact i=2. This may happen when the level coefficient is
415        * not 1 or -1 and the scalar value is not zero. In any other case (e.g.,
416        * if the inequality is an expression including outer loop counters or
417        * parameters) the once time loop would not have been detected
418        * because of floord and ceild functions.
419        */
420       if (cloog_int_ne_si(i->line[0][level],1) &&
421           cloog_int_ne_si(i->line[0][level],-1) &&
422 	  !cloog_int_is_zero(i->line[0][matrix->NbColumns-1])) {
423 	cloog_int_t denominator;
424 
425 	cloog_int_init(denominator);
426 	cloog_int_abs(denominator, i->line[0][level]);
427 	cloog_int_fdiv_q(i->line[0][matrix->NbColumns-1],
428 			 i->line[0][matrix->NbColumns-1], denominator);
429 	cloog_int_set_si(i->line[0][level], cloog_int_sgn(i->line[0][level]));
430 	cloog_int_clear(denominator);
431       }
432 
433       break ;
434     }
435   }
436   assert(cloog_constraint_is_valid(line));
437 
438   /* We update the line of equal corresponding to level:
439    * - the first element gives the equality type,
440    */
441   equal->types[level-1] = cloog_constraint_equal_type(line, level);
442   /* - the other elements corresponding to the equality itself
443    *   (the iterators up to level, then the parameters and the scalar).
444    */
445   for (j=1;j<=level;j++)
446       cloog_int_set(equal->constraints->M.p[level-1][j], line->line[0][j]);
447   for (j = 0; j < nb_par + 1; j++)
448       cloog_int_set(equal->constraints->M.p[level-1][equal->constraints->M.NbColumns-j-1],
449 		   line->line[0][line->set->M.NbColumns-j-1]);
450 
451   if (cloog_constraint_is_valid(i))
452     cloog_constraint_release(line);
453   cloog_equal_update(equal, level, nb_par);
454 }
455 
456 
457 /**
458  * cloog_equal_del function :
459  * This function reset the equality corresponding to the iterator (level)
460  * in the equality matrix (equal).
461  * - July 2nd 2002: first version.
462  */
cloog_equal_del(CloogEqualities * equal,int level)463 void cloog_equal_del(CloogEqualities *equal, int level)
464 {
465     equal->types[level-1] = EQTYPE_NONE;
466 }
467 
468 
469 
470 /******************************************************************************
471  *                            Processing functions                            *
472  ******************************************************************************/
473 
474 /**
475  * Function cloog_constraint_set_normalize:
476  * This function will modify the constraint system in such a way that when
477  * there is an equality depending on the element at level 'level', there are
478  * no more (in)equalities depending on this element. For instance, try
479  * test/valilache.cloog with options -f 8 -l 9, with and without the call
480  * to this function. At a given moment, for the level L we will have
481  * 32*P=L && L>=1 (P is a lower level), this constraint system cannot be
482  * translated directly into a source code. Thus, we normalize the domain to
483  * remove L from the inequalities. In our example, this leads to
484  * 32*P=L && 32*P>=1, that can be transated to the code
485  * if (P>=1) { L=32*P ; ... }. This function solves the DaeGon Kim bug.
486  * WARNING: Remember that if there is another call to Polylib after a call to
487  * this function, we have to recall this function.
488  *  -June    16th 2005: first version (adaptation from URGent June-7th-2005 by
489  *                      N. Vasilache).
490  * - June    21rd 2005: Adaptation for GMP.
491  * - November 4th 2005: Complete rewriting, simpler and faster. It is no more an
492  *                      adaptation from URGent.
493  */
cloog_constraint_set_normalize(CloogConstraintSet * constraints,int level)494 void cloog_constraint_set_normalize(CloogConstraintSet *constraints, int level)
495 { int ref, i, j ;
496   cloog_int_t factor_i, factor_ref, temp_i, temp_ref, gcd;
497   CloogMatrix *matrix = &constraints->M;
498 
499   if (matrix == NULL)
500   return ;
501 
502   /* Don't "normalize" the constant term. */
503   if (level == matrix->NbColumns-1)
504     return;
505 
506   /* Let us find an equality for the current level that can be propagated. */
507   for (ref=0;ref<matrix->NbRows;ref++)
508   if (cloog_int_is_zero(matrix->p[ref][0]) && !cloog_int_is_zero(matrix->p[ref][level])) {
509     cloog_int_init(gcd);
510     cloog_int_init(temp_i);
511     cloog_int_init(temp_ref);
512     cloog_int_init(factor_i);
513     cloog_int_init(factor_ref);
514 
515     /* Row "ref" is the reference equality, now let us find a row to simplify.*/
516     for (i=ref+1;i<matrix->NbRows;i++)
517     if (!cloog_int_is_zero(matrix->p[i][level])) {
518       /* Now let us set to 0 the "level" coefficient of row "j" using "ref".
519        * First we compute the factors to apply to each row vector element.
520        */
521       cloog_int_gcd(gcd, matrix->p[ref][level], matrix->p[i][level]);
522       cloog_int_divexact(factor_i, matrix->p[ref][level], gcd);
523       cloog_int_divexact(factor_ref, matrix->p[i][level], gcd);
524 
525       /* Maybe we are simplifying an inequality: factor_i must not be <0. */
526       if (cloog_int_is_neg(factor_i)) {
527         cloog_int_abs(factor_i, factor_i);
528         cloog_int_neg(factor_ref, factor_ref);
529       }
530 
531       /* Now update the vector. */
532       for (j=1;j<matrix->NbColumns;j++) {
533         cloog_int_mul(temp_i, factor_i, matrix->p[i][j]);
534         cloog_int_mul(temp_ref, factor_ref, matrix->p[ref][j]);
535         cloog_int_sub(matrix->p[i][j], temp_i, temp_ref);
536       }
537 
538       /* Normalize (divide by GCD of all elements) the updated vector. */
539       cloog_seq_normalize(&(matrix->p[i][1]), matrix->NbColumns-1);
540     }
541 
542     cloog_int_clear(gcd);
543     cloog_int_clear(temp_i);
544     cloog_int_clear(temp_ref);
545     cloog_int_clear(factor_i);
546     cloog_int_clear(factor_ref);
547     break ;
548   }
549 }
550 
551 
552 
553 /**
554  * cloog_constraint_set_copy function:
555  * this functions builds and returns a "hard copy" (not a pointer copy) of a
556  * CloogMatrix data structure.
557  * - October 26th 2005: first version.
558  */
cloog_constraint_set_copy(CloogConstraintSet * constraints)559 CloogConstraintSet *cloog_constraint_set_copy(CloogConstraintSet *constraints)
560 { int i, j ;
561   CloogMatrix *copy;
562   CloogMatrix *matrix = &constraints->M;
563 
564   copy = cloog_matrix_alloc(matrix->NbRows, matrix->NbColumns);
565 
566   for (i=0;i<matrix->NbRows;i++)
567   for (j=0;j<matrix->NbColumns;j++)
568       cloog_int_set(copy->p[i][j], matrix->p[i][j]);
569 
570   return cloog_constraint_set_from_cloog_matrix(copy);
571 }
572 
573 
574 /**
575  * cloog_equal_vector_simplify function:
576  * this function simplify an affine expression with its coefficients in
577  * "vector" of length "length" thanks to an equality matrix "equal" that gives
578  * for some elements of the affine expression an equality with other elements,
579  * preferably constants. For instance, if the vector contains i+j+3 and the
580  * equality matrix gives i=n and j=2, the vector is simplified to n+3 and is
581  * returned in a new vector.
582  * - vector is the array of affine expression coefficients
583  * - equal is the matrix of equalities,
584  * - length is the vector length,
585  * - level is a level we don't want to simplify (-1 if none),
586  * - nb_par is the number of parameters of the program.
587  **
588  * - September 20th 2005: first version.
589  * - November   2nd 2005: (debug) we are simplifying inequalities, thus we are
590  *                        not allowed to multiply the vector by a negative
591  *                        constant.Problem found after a report of Michael
592  *                        Classen.
593  */
cloog_equal_vector_simplify(CloogEqualities * equal,cloog_int_t * vector,int length,int level,int nb_par)594 struct cloog_vec *cloog_equal_vector_simplify(CloogEqualities *equal, cloog_int_t *vector,
595 				    int length, int level, int nb_par)
596 { int i, j ;
597   cloog_int_t gcd, factor_vector, factor_equal, temp_vector, temp_equal;
598 	struct cloog_vec *simplified;
599 
600 	simplified = cloog_vec_alloc(length);
601 	cloog_seq_cpy(simplified->p, vector, length);
602 
603   cloog_int_init(gcd);
604   cloog_int_init(temp_vector);
605   cloog_int_init(temp_equal);
606   cloog_int_init(factor_vector);
607   cloog_int_init(factor_equal);
608 
609   /* For each non-null coefficient in the vector, */
610   for (i=length-nb_par-2;i>0;i--)
611   if (i != level)
612   { /* if the coefficient in not null, and there exists a useful equality */
613     if ((!cloog_int_is_zero(simplified->p[i])) && equal->types[i-1])
614     { /* Compute the Greatest Common Divisor. */
615       cloog_int_gcd(gcd, simplified->p[i], equal->constraints->M.p[i-1][i]);
616 
617       /* Compute the factors to apply to each row vector element. */
618       cloog_int_divexact(factor_vector, equal->constraints->M.p[i-1][i], gcd);
619       cloog_int_divexact(factor_equal, simplified->p[i], gcd);
620 
621       /* We are simplifying an inequality: factor_vector must not be <0. */
622       if (cloog_int_is_neg(factor_vector)) {
623         cloog_int_abs(factor_vector, factor_vector);
624         cloog_int_neg(factor_equal, factor_equal);
625       }
626 
627       /* Now update the vector. */
628       /* - the iterators, up to the current level, */
629       for (j=1;j<=length-nb_par-2;j++) {
630         cloog_int_mul(temp_vector, factor_vector, simplified->p[j]);
631         cloog_int_mul(temp_equal, factor_equal, equal->constraints->M.p[i-1][j]);
632         cloog_int_sub(simplified->p[j], temp_vector, temp_equal);
633       }
634       /* - between last useful iterator (i) and the first parameter, the equal
635        *   matrix is sparse (full of zeroes), we just do nothing there.
636        * - the parameters and the scalar.
637        */
638       for (j = 0; j < nb_par + 1; j++) {
639         cloog_int_mul(temp_vector, factor_vector, simplified->p[length-1-j]);
640         cloog_int_mul(temp_equal,factor_equal,
641 	     equal->constraints->M.p[i-1][equal->constraints->M.NbColumns-j-1]);
642         cloog_int_sub(simplified->p[length-1-j],temp_vector,temp_equal) ;
643       }
644     }
645   }
646 
647   /* Normalize (divide by GCD of all elements) the updated vector. */
648   cloog_seq_normalize(&simplified->p[1], length - 1);
649 
650   cloog_int_clear(gcd);
651   cloog_int_clear(temp_vector);
652   cloog_int_clear(temp_equal);
653   cloog_int_clear(factor_vector);
654   cloog_int_clear(factor_equal);
655 
656   return simplified ;
657 }
658 
659 
660 /**
661  * cloog_constraint_set_simplify function:
662  * this function simplify all constraints inside the matrix "matrix" thanks to
663  * an equality matrix "equal" that gives for some elements of the affine
664  * constraint an equality with other elements, preferably constants.
665  * For instance, if a row of the matrix contains i+j+3>=0 and the equality
666  * matrix gives i=n and j=2, the constraint is simplified to n+3>=0. The
667  * simplified constraints are returned back inside a new simplified matrix.
668  * - matrix is the set of constraints to simplify,
669  * - equal is the matrix of equalities,
670  * - level is a level we don't want to simplify (-1 if none),
671  * - nb_par is the number of parameters of the program.
672  **
673  * - November 4th 2005: first version.
674  */
cloog_constraint_set_simplify(CloogConstraintSet * constraints,CloogEqualities * equal,int level,int nb_par)675 CloogConstraintSet *cloog_constraint_set_simplify(CloogConstraintSet *constraints,
676 	CloogEqualities *equal, int level, int nb_par)
677 { int i, j, k ;
678 	struct cloog_vec *vector;
679   CloogMatrix *simplified;
680   CloogMatrix *matrix = &constraints->M;
681 
682   if (matrix == NULL)
683   return NULL ;
684 
685   /* The simplified matrix is such that each row has been simplified thanks
686    * tho the "equal" matrix. We allocate the memory for the simplified matrix,
687    * then for each row of the original matrix, we compute the simplified
688    * vector and we copy its content into the according simplified row.
689    */
690   simplified = cloog_matrix_alloc(matrix->NbRows, matrix->NbColumns);
691   for (i=0;i<matrix->NbRows;i++)
692   { vector = cloog_equal_vector_simplify(equal, matrix->p[i],
693 					  matrix->NbColumns, level, nb_par);
694     for (j=0;j<matrix->NbColumns;j++)
695     cloog_int_set(simplified->p[i][j], vector->p[j]);
696 
697     cloog_vec_free(vector);
698   }
699 
700   /* After simplification, it may happen that few constraints are the same,
701    * we remove them here by replacing them with 0=0 constraints.
702    */
703   for (i=0;i<simplified->NbRows;i++)
704   for (j=i+1;j<simplified->NbRows;j++)
705   { for (k=0;k<simplified->NbColumns;k++)
706     if (cloog_int_ne(simplified->p[i][k],simplified->p[j][k]))
707     break ;
708 
709     if (k == matrix->NbColumns)
710     { for (k=0;k<matrix->NbColumns;k++)
711         cloog_int_set_si(simplified->p[j][k],0);
712     }
713   }
714 
715   return cloog_constraint_set_from_cloog_matrix(simplified);
716 }
717 
718 
719 /**
720  * Return clast_expr corresponding to the variable "level" (1 based) in
721  * the given constraint.
722  */
cloog_constraint_variable_expr(CloogConstraint * constraint,int level,CloogNames * names)723 struct clast_expr *cloog_constraint_variable_expr(CloogConstraint *constraint,
724 	int level, CloogNames *names)
725 {
726 	int total_dim, nb_iter;
727 	const char *name;
728 
729 	total_dim = cloog_constraint_total_dimension(constraint);
730 	nb_iter = total_dim - names->nb_parameters;
731 
732 	if (level <= nb_iter)
733 		name = cloog_names_name_at_level(names, level);
734 	else
735 		name = names->parameters[level - (nb_iter+1)] ;
736 
737 	return &new_clast_name(name)->expr;
738 }
739 
740 
741 /**
742  * Return true if constraint c involves variable v (zero-based).
743  */
cloog_constraint_involves(CloogConstraint * constraint,int v)744 int cloog_constraint_involves(CloogConstraint *constraint, int v)
745 {
746 	return !cloog_int_is_zero(constraint->line[0][1+v]);
747 }
748 
cloog_constraint_is_lower_bound(CloogConstraint * constraint,int v)749 int cloog_constraint_is_lower_bound(CloogConstraint *constraint, int v)
750 {
751 	return cloog_int_is_pos(constraint->line[0][1+v]);
752 }
753 
cloog_constraint_is_upper_bound(CloogConstraint * constraint,int v)754 int cloog_constraint_is_upper_bound(CloogConstraint *constraint, int v)
755 {
756 	return cloog_int_is_neg(constraint->line[0][1+v]);
757 }
758 
cloog_constraint_is_equality(CloogConstraint * constraint)759 int cloog_constraint_is_equality(CloogConstraint *constraint)
760 {
761 	return cloog_int_is_zero(constraint->line[0][0]);
762 }
763 
cloog_constraint_clear(CloogConstraint * constraint)764 void cloog_constraint_clear(CloogConstraint *constraint)
765 {
766 	int k;
767 
768 	for (k = 1; k <= constraint->set->M.NbColumns - 2; k++)
769 		cloog_int_set_si(constraint->line[0][k], 0);
770 }
771 
cloog_constraint_set_drop_constraint(CloogConstraintSet * constraints,CloogConstraint * constraint)772 CloogConstraintSet *cloog_constraint_set_drop_constraint(
773 	CloogConstraintSet *constraints, CloogConstraint *constraint)
774 {
775 	cloog_constraint_clear(constraint);
776 	return constraints;
777 }
778 
cloog_constraint_coefficient_get(CloogConstraint * constraint,int var,cloog_int_t * val)779 void cloog_constraint_coefficient_get(CloogConstraint *constraint,
780 			int var, cloog_int_t *val)
781 {
782 	cloog_int_set(*val, constraint->line[0][1+var]);
783 }
784 
cloog_constraint_coefficient_set(CloogConstraint * constraint,int var,cloog_int_t val)785 void cloog_constraint_coefficient_set(CloogConstraint *constraint,
786 			int var, cloog_int_t val)
787 {
788 	cloog_int_set(constraint->line[0][1+var], val);
789 }
790 
cloog_constraint_constant_get(CloogConstraint * constraint,cloog_int_t * val)791 void cloog_constraint_constant_get(CloogConstraint *constraint, cloog_int_t *val)
792 {
793 	cloog_int_set(*val, constraint->line[0][constraint->set->M.NbColumns-1]);
794 }
795 
796 /**
797  * Copy the coefficient of constraint c into dst in PolyLib order,
798  * i.e., first the coefficients of the variables, then the coefficients
799  * of the parameters and finally the constant.
800  */
cloog_constraint_copy_coefficients(CloogConstraint * constraint,cloog_int_t * dst)801 void cloog_constraint_copy_coefficients(CloogConstraint *constraint,
802 					cloog_int_t *dst)
803 {
804 	cloog_seq_cpy(dst, constraint->line[0]+1, constraint->set->M.NbColumns-1);
805 }
806 
cloog_constraint_invalid(void)807 CloogConstraint *cloog_constraint_invalid(void)
808 {
809 	return NULL;
810 }
811 
cloog_constraint_is_valid(CloogConstraint * constraint)812 int cloog_constraint_is_valid(CloogConstraint *constraint)
813 {
814 	return constraint != NULL;
815 }
816 
817 
818 /**
819  * Check whether there is any need for the constraint "upper" on
820  * "level" to get reduced.
821  * Yes.
822  */
cloog_constraint_needs_reduction(CloogConstraint * upper,int level)823 int cloog_constraint_needs_reduction(CloogConstraint *upper, int level)
824 {
825 	return 1;
826 }
827 
828 
829 /**
830  * Create a CloogConstraintSet containing enough information to perform
831  * a reduction on the upper equality (in this case lower is an invalid
832  * CloogConstraint) or the pair of inequalities upper and lower
833  * from within insert_modulo_guard.
834  * In the PolyLib backend, we return a CloogConstraintSet containting only
835  * the upper bound.  The reduction will not change the stride so there
836  * will be no need to recompute the bound on the modulo expression.
837  */
cloog_constraint_set_for_reduction(CloogConstraint * upper,CloogConstraint * lower)838 CloogConstraintSet *cloog_constraint_set_for_reduction(CloogConstraint *upper,
839 	 CloogConstraint *lower)
840 {
841 	CloogConstraintSet *set;
842 
843 	set = cloog_constraint_set_from_cloog_matrix(
844 		cloog_matrix_alloc(1, upper->set->M.NbColumns));
845 	cloog_seq_cpy(set->M.p[0], upper->line[0], set->M.NbColumns);
846 	return set;
847 }
848 
849 
850 /* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */
Euclid(cloog_int_t a,cloog_int_t b,cloog_int_t * x,cloog_int_t * y,cloog_int_t * g)851 static void Euclid(cloog_int_t a, cloog_int_t b,
852 			cloog_int_t *x, cloog_int_t *y, cloog_int_t *g)
853 {
854     cloog_int_t c, d, e, f, tmp;
855 
856     cloog_int_init(c);
857     cloog_int_init(d);
858     cloog_int_init(e);
859     cloog_int_init(f);
860     cloog_int_init(tmp);
861     cloog_int_abs(c, a);
862     cloog_int_abs(d, b);
863     cloog_int_set_si(e, 1);
864     cloog_int_set_si(f, 0);
865     while (cloog_int_is_pos(d)) {
866 	cloog_int_tdiv_q(tmp, c, d);
867 	cloog_int_mul(tmp, tmp, f);
868 	cloog_int_sub(e, e, tmp);
869 	cloog_int_tdiv_q(tmp, c, d);
870 	cloog_int_mul(tmp, tmp, d);
871 	cloog_int_sub(c, c, tmp);
872 	cloog_int_swap(c, d);
873 	cloog_int_swap(e, f);
874     }
875     cloog_int_set(*g, c);
876     if (cloog_int_is_zero(a))
877 	cloog_int_set_si(*x, 0);
878     else if (cloog_int_is_pos(a))
879 	cloog_int_set(*x, e);
880     else cloog_int_neg(*x, e);
881     if (cloog_int_is_zero(b))
882 	cloog_int_set_si(*y, 0);
883     else {
884 	cloog_int_mul(tmp, a, *x);
885 	cloog_int_sub(tmp, c, tmp);
886 	cloog_int_divexact(*y, tmp, b);
887     }
888     cloog_int_clear(c);
889     cloog_int_clear(d);
890     cloog_int_clear(e);
891     cloog_int_clear(f);
892     cloog_int_clear(tmp);
893 }
894 
895 /**
896  * Reduce the modulo guard expressed by "contraints" using equalities
897  * found in outer nesting levels (stored in "equal").
898  * The modulo guard may be an equality or a pair of inequalities.
899  * In case of a pair of inequalities, "constraints" only contains the
900  * upper bound and *bound contains the bound on the
901  * corresponding modulo expression.  The bound is left untouched by
902  * this function.
903  */
cloog_constraint_set_reduce(CloogConstraintSet * constraints,int level,CloogEqualities * equal,int nb_par,cloog_int_t * bound)904 CloogConstraintSet *cloog_constraint_set_reduce(CloogConstraintSet *constraints,
905 	int level, CloogEqualities *equal, int nb_par, cloog_int_t *bound)
906 {
907   int i, j, k, len, len2, nb_iter;
908   struct cloog_vec *line_vector2;
909   cloog_int_t *line, *line2, val, x, y, g;
910 
911   len = constraints->M.NbColumns;
912   len2 = cloog_equal_total_dimension(equal) + 2;
913   nb_iter = len - 2 - nb_par;
914 
915   cloog_int_init(val);
916   cloog_int_init(x);
917   cloog_int_init(y);
918   cloog_int_init(g);
919 
920   line_vector2 = cloog_vec_alloc(len2);
921   line2 = line_vector2->p;
922 
923   line = constraints->M.p[0];
924   if (cloog_int_is_pos(line[level]))
925     cloog_seq_neg(line+1, line+1, len-1);
926   cloog_int_neg(line[level], line[level]);
927   assert(cloog_int_is_pos(line[level]));
928 
929   for (i = nb_iter; i >= 1; --i) {
930     if (i == level)
931       continue;
932     cloog_int_fdiv_r(line[i], line[i], line[level]);
933     if (cloog_int_is_zero(line[i]))
934       continue;
935 
936     /* Look for an earlier variable that is also a multiple of line[level]
937      * and check whether we can use the corresponding affine expression
938      * to "reduce" the modulo guard, where reduction means that we eliminate
939      * a variable, possibly at the expense of introducing other variables
940      * with smaller index.
941      */
942     for (j = level-1; j >= 0; --j) {
943       CloogConstraint *equal_constraint;
944       if (cloog_equal_type(equal, j+1) != EQTYPE_EXAFFINE)
945 	continue;
946       equal_constraint = cloog_equal_constraint(equal, j);
947       cloog_constraint_coefficient_get(equal_constraint, j, &val);
948       if (!cloog_int_is_divisible_by(val, line[level])) {
949 	cloog_constraint_release(equal_constraint);
950 	continue;
951       }
952       cloog_constraint_coefficient_get(equal_constraint, i-1, &val);
953       if (cloog_int_is_divisible_by(val, line[level])) {
954 	cloog_constraint_release(equal_constraint);
955 	continue;
956       }
957       for (k = j; k > i; --k) {
958 	cloog_constraint_coefficient_get(equal_constraint, k-1, &val);
959 	if (cloog_int_is_zero(val))
960 	  continue;
961 	if (!cloog_int_is_divisible_by(val, line[level]))
962 	  break;
963       }
964       if (k > i) {
965 	 cloog_constraint_release(equal_constraint);
966 	 continue;
967       }
968       cloog_constraint_coefficient_get(equal_constraint, i-1, &val);
969       Euclid(val, line[level], &x, &y, &g);
970       if (!cloog_int_is_divisible_by(val, line[i])) {
971 	cloog_constraint_release(equal_constraint);
972 	continue;
973       }
974       cloog_int_divexact(val, line[i], g);
975       cloog_int_neg(val, val);
976       cloog_int_mul(val, val, x);
977       cloog_int_set_si(y, 1);
978       /* Add (equal->p[j][i])^{-1} * line[i] times the equality */
979       cloog_constraint_copy_coefficients(equal_constraint, line2+1);
980       cloog_seq_combine(line+1, y, line+1, val, line2+1, i);
981       cloog_seq_combine(line+len-nb_par-1, y, line+len-nb_par-1,
982 					   val, line2+len2-nb_par-1, nb_par+1);
983       cloog_constraint_release(equal_constraint);
984       break;
985     }
986   }
987 
988   cloog_vec_free(line_vector2);
989 
990   cloog_int_clear(val);
991   cloog_int_clear(x);
992   cloog_int_clear(y);
993   cloog_int_clear(g);
994 
995   /* Make sure the line is not inverted again in the calling function. */
996   cloog_int_neg(line[level], line[level]);
997 
998   return constraints;
999 }
1000 
cloog_constraint_first(CloogConstraintSet * constraints)1001 CloogConstraint *cloog_constraint_first(CloogConstraintSet *constraints)
1002 {
1003 	CloogConstraint *c;
1004 	if (constraints->M.NbRows == 0)
1005 		return cloog_constraint_invalid();
1006 	c = ALLOC(CloogConstraint);
1007 	c->set = constraints;
1008 	c->line = &constraints->M.p[0];
1009 	return c;
1010 }
1011 
cloog_constraint_next(CloogConstraint * constraint)1012 CloogConstraint *cloog_constraint_next(CloogConstraint *constraint)
1013 {
1014 	constraint->line++;
1015 	if (constraint->line == constraint->set->M.p + constraint->set->M.NbRows) {
1016 		cloog_constraint_release(constraint);
1017 		return NULL;
1018 	}
1019 	return constraint;
1020 }
1021 
cloog_constraint_copy(CloogConstraint * constraint)1022 CloogConstraint *cloog_constraint_copy(CloogConstraint *constraint)
1023 {
1024 	CloogConstraint *c = ALLOC(CloogConstraint);
1025 	c->set = constraint->set;
1026 	c->line = constraint->line;
1027 	return c;
1028 }
1029 
cloog_constraint_release(CloogConstraint * constraint)1030 void cloog_constraint_release(CloogConstraint *constraint)
1031 {
1032 	free(constraint);
1033 }
1034 
cloog_constraint_set_foreach_constraint(CloogConstraintSet * constraints,int (* fn)(CloogConstraint * constraint,void * user),void * user)1035 int cloog_constraint_set_foreach_constraint(CloogConstraintSet *constraints,
1036 	int (*fn)(CloogConstraint *constraint, void *user), void *user)
1037 {
1038 	CloogConstraint *c;
1039 
1040 	for (c = cloog_constraint_first(constraints);
1041 	     cloog_constraint_is_valid(c); c = cloog_constraint_next(c))
1042 		if (fn(c, user) < 0) {
1043 			cloog_constraint_release(c);
1044 			return -1;
1045 		}
1046 
1047 	return 0;
1048 }
1049 
cloog_equal_constraint(CloogEqualities * equal,int j)1050 CloogConstraint *cloog_equal_constraint(CloogEqualities *equal, int j)
1051 {
1052 	CloogConstraint *c = ALLOC(CloogConstraint);
1053 	c->set = equal->constraints;
1054 	c->line = &equal->constraints->M.p[j];
1055 	return c;
1056 }
1057