Home | History | Annotate | Line # | Download | only in dist
      1  1.1  mrg /*
      2  1.1  mrg  * Copyright 2012-2013 Ecole Normale Superieure
      3  1.1  mrg  *
      4  1.1  mrg  * Use of this software is governed by the MIT license
      5  1.1  mrg  *
      6  1.1  mrg  * Written by Sven Verdoolaege,
      7  1.1  mrg  * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
      8  1.1  mrg  */
      9  1.1  mrg 
     10  1.1  mrg #include <isl/val.h>
     11  1.1  mrg #include <isl_map_private.h>
     12  1.1  mrg #include <isl_aff_private.h>
     13  1.1  mrg #include <isl/constraint.h>
     14  1.1  mrg #include <isl/set.h>
     15  1.1  mrg 
     16  1.1  mrg /* Stride information about a specific set dimension.
     17  1.1  mrg  * The values of the set dimension are equal to
     18  1.1  mrg  * "offset" plus a multiple of "stride".
     19  1.1  mrg  */
     20  1.1  mrg struct isl_stride_info {
     21  1.1  mrg 	isl_val *stride;
     22  1.1  mrg 	isl_aff *offset;
     23  1.1  mrg };
     24  1.1  mrg 
     25  1.1  mrg /* Return the ctx to which "si" belongs.
     26  1.1  mrg  */
     27  1.1  mrg isl_ctx *isl_stride_info_get_ctx(__isl_keep isl_stride_info *si)
     28  1.1  mrg {
     29  1.1  mrg 	if (!si)
     30  1.1  mrg 		return NULL;
     31  1.1  mrg 
     32  1.1  mrg 	return isl_val_get_ctx(si->stride);
     33  1.1  mrg }
     34  1.1  mrg 
     35  1.1  mrg /* Free "si" and return NULL.
     36  1.1  mrg  */
     37  1.1  mrg __isl_null isl_stride_info *isl_stride_info_free(
     38  1.1  mrg 	__isl_take isl_stride_info *si)
     39  1.1  mrg {
     40  1.1  mrg 	if (!si)
     41  1.1  mrg 		return NULL;
     42  1.1  mrg 	isl_val_free(si->stride);
     43  1.1  mrg 	isl_aff_free(si->offset);
     44  1.1  mrg 	free(si);
     45  1.1  mrg 	return NULL;
     46  1.1  mrg }
     47  1.1  mrg 
     48  1.1  mrg /* Construct an isl_stride_info object with given offset and stride.
     49  1.1  mrg  */
     50  1.1  mrg __isl_give isl_stride_info *isl_stride_info_alloc(
     51  1.1  mrg 	__isl_take isl_val *stride, __isl_take isl_aff *offset)
     52  1.1  mrg {
     53  1.1  mrg 	struct isl_stride_info *si;
     54  1.1  mrg 
     55  1.1  mrg 	if (!stride || !offset)
     56  1.1  mrg 		goto error;
     57  1.1  mrg 	si = isl_alloc_type(isl_val_get_ctx(stride), struct isl_stride_info);
     58  1.1  mrg 	if (!si)
     59  1.1  mrg 		goto error;
     60  1.1  mrg 	si->stride = stride;
     61  1.1  mrg 	si->offset = offset;
     62  1.1  mrg 	return si;
     63  1.1  mrg error:
     64  1.1  mrg 	isl_val_free(stride);
     65  1.1  mrg 	isl_aff_free(offset);
     66  1.1  mrg 	return NULL;
     67  1.1  mrg }
     68  1.1  mrg 
     69  1.1  mrg /* Make a copy of "si" and return it.
     70  1.1  mrg  */
     71  1.1  mrg __isl_give isl_stride_info *isl_stride_info_copy(
     72  1.1  mrg 	__isl_keep isl_stride_info *si)
     73  1.1  mrg {
     74  1.1  mrg 	if (!si)
     75  1.1  mrg 		return NULL;
     76  1.1  mrg 
     77  1.1  mrg 	return isl_stride_info_alloc(isl_val_copy(si->stride),
     78  1.1  mrg 		isl_aff_copy(si->offset));
     79  1.1  mrg }
     80  1.1  mrg 
     81  1.1  mrg /* Return the stride of "si".
     82  1.1  mrg  */
     83  1.1  mrg __isl_give isl_val *isl_stride_info_get_stride(__isl_keep isl_stride_info *si)
     84  1.1  mrg {
     85  1.1  mrg 	if (!si)
     86  1.1  mrg 		return NULL;
     87  1.1  mrg 	return isl_val_copy(si->stride);
     88  1.1  mrg }
     89  1.1  mrg 
     90  1.1  mrg /* Return the offset of "si".
     91  1.1  mrg  */
     92  1.1  mrg __isl_give isl_aff *isl_stride_info_get_offset(__isl_keep isl_stride_info *si)
     93  1.1  mrg {
     94  1.1  mrg 	if (!si)
     95  1.1  mrg 		return NULL;
     96  1.1  mrg 	return isl_aff_copy(si->offset);
     97  1.1  mrg }
     98  1.1  mrg 
     99  1.1  mrg /* Information used inside detect_stride.
    100  1.1  mrg  *
    101  1.1  mrg  * "pos" is the set dimension at which the stride is being determined.
    102  1.1  mrg  * "want_offset" is set if the offset should be computed.
    103  1.1  mrg  * "found" is set if some stride was found already.
    104  1.1  mrg  * "stride" and "offset" contain the (combined) stride and offset
    105  1.1  mrg  * found so far and are NULL when "found" is not set.
    106  1.1  mrg  * If "want_offset" is not set, then "offset" remains NULL.
    107  1.1  mrg  */
    108  1.1  mrg struct isl_detect_stride_data {
    109  1.1  mrg 	int pos;
    110  1.1  mrg 	int want_offset;
    111  1.1  mrg 	int found;
    112  1.1  mrg 	isl_val *stride;
    113  1.1  mrg 	isl_aff *offset;
    114  1.1  mrg };
    115  1.1  mrg 
    116  1.1  mrg /* Set the stride and offset of data->pos to the given
    117  1.1  mrg  * value and expression.
    118  1.1  mrg  *
    119  1.1  mrg  * If we had already found a stride before, then the two strides
    120  1.1  mrg  * are combined into a single stride.
    121  1.1  mrg  *
    122  1.1  mrg  * In particular, if the new stride information is of the form
    123  1.1  mrg  *
    124  1.1  mrg  *	i = f + s (...)
    125  1.1  mrg  *
    126  1.1  mrg  * and the old stride information is of the form
    127  1.1  mrg  *
    128  1.1  mrg  *	i = f2 + s2 (...)
    129  1.1  mrg  *
    130  1.1  mrg  * then we compute the extended gcd of s and s2
    131  1.1  mrg  *
    132  1.1  mrg  *	a s + b s2 = g,
    133  1.1  mrg  *
    134  1.1  mrg  * with g = gcd(s,s2), multiply the first equation with t1 = b s2/g
    135  1.1  mrg  * and the second with t2 = a s1/g.
    136  1.1  mrg  * This results in
    137  1.1  mrg  *
    138  1.1  mrg  *	i = (b s2 + a s1)/g i = t1 f + t2 f2 + (s s2)/g (...)
    139  1.1  mrg  *
    140  1.1  mrg  * so that t1 f + t2 f2 is the combined offset and (s s2)/g = lcm(s,s2)
    141  1.1  mrg  * is the combined stride.
    142  1.1  mrg  */
    143  1.1  mrg static isl_stat set_stride(struct isl_detect_stride_data *data,
    144  1.1  mrg 	__isl_take isl_val *stride, __isl_take isl_aff *offset)
    145  1.1  mrg {
    146  1.1  mrg 	if (!stride || !offset)
    147  1.1  mrg 		goto error;
    148  1.1  mrg 
    149  1.1  mrg 	if (data->found) {
    150  1.1  mrg 		isl_val *stride2, *a, *b, *g;
    151  1.1  mrg 		isl_aff *offset2;
    152  1.1  mrg 
    153  1.1  mrg 		stride2 = data->stride;
    154  1.1  mrg 		g = isl_val_gcdext(isl_val_copy(stride), isl_val_copy(stride2),
    155  1.1  mrg 					&a, &b);
    156  1.1  mrg 		a = isl_val_mul(a, isl_val_copy(stride));
    157  1.1  mrg 		a = isl_val_div(a, isl_val_copy(g));
    158  1.1  mrg 		stride2 = isl_val_div(stride2, g);
    159  1.1  mrg 		b = isl_val_mul(b, isl_val_copy(stride2));
    160  1.1  mrg 		stride = isl_val_mul(stride, stride2);
    161  1.1  mrg 
    162  1.1  mrg 		if (!data->want_offset) {
    163  1.1  mrg 			isl_val_free(a);
    164  1.1  mrg 			isl_val_free(b);
    165  1.1  mrg 		} else {
    166  1.1  mrg 			offset2 = data->offset;
    167  1.1  mrg 			offset2 = isl_aff_scale_val(offset2, a);
    168  1.1  mrg 			offset = isl_aff_scale_val(offset, b);
    169  1.1  mrg 			offset = isl_aff_add(offset, offset2);
    170  1.1  mrg 		}
    171  1.1  mrg 	}
    172  1.1  mrg 
    173  1.1  mrg 	data->found = 1;
    174  1.1  mrg 	data->stride = stride;
    175  1.1  mrg 	if (data->want_offset)
    176  1.1  mrg 		data->offset = offset;
    177  1.1  mrg 	else
    178  1.1  mrg 		isl_aff_free(offset);
    179  1.1  mrg 	if (!data->stride || (data->want_offset && !data->offset))
    180  1.1  mrg 		return isl_stat_error;
    181  1.1  mrg 
    182  1.1  mrg 	return isl_stat_ok;
    183  1.1  mrg error:
    184  1.1  mrg 	isl_val_free(stride);
    185  1.1  mrg 	isl_aff_free(offset);
    186  1.1  mrg 	return isl_stat_error;
    187  1.1  mrg }
    188  1.1  mrg 
    189  1.1  mrg /* Check if constraint "c" imposes any stride on dimension data->pos
    190  1.1  mrg  * and, if so, update the stride information in "data".
    191  1.1  mrg  *
    192  1.1  mrg  * In order to impose a stride on the dimension, "c" needs to be an equality
    193  1.1  mrg  * and it needs to involve the dimension.  Note that "c" may also be
    194  1.1  mrg  * a div constraint and thus an inequality that we cannot use.
    195  1.1  mrg  *
    196  1.1  mrg  * Let c be of the form
    197  1.1  mrg  *
    198  1.1  mrg  *	h(p) + g * v * i + g * stride * f(alpha) = 0
    199  1.1  mrg  *
    200  1.1  mrg  * with h(p) an expression in terms of the parameters and other dimensions
    201  1.1  mrg  * and f(alpha) an expression in terms of the existentially quantified
    202  1.1  mrg  * variables.
    203  1.1  mrg  *
    204  1.1  mrg  * If "stride" is not zero and not one, then it represents a non-trivial stride
    205  1.1  mrg  * on "i".  We compute a and b such that
    206  1.1  mrg  *
    207  1.1  mrg  *	a v + b stride = 1
    208  1.1  mrg  *
    209  1.1  mrg  * We have
    210  1.1  mrg  *
    211  1.1  mrg  *	g v i = -h(p) + g stride f(alpha)
    212  1.1  mrg  *
    213  1.1  mrg  *	a g v i = -a h(p) + g stride f(alpha)
    214  1.1  mrg  *
    215  1.1  mrg  *	a g v i + b g stride i = -a h(p) + g stride * (...)
    216  1.1  mrg  *
    217  1.1  mrg  *	g i = -a h(p) + g stride * (...)
    218  1.1  mrg  *
    219  1.1  mrg  *	i = -a h(p)/g + stride * (...)
    220  1.1  mrg  *
    221  1.1  mrg  * The expression "-a h(p)/g" can therefore be used as offset.
    222  1.1  mrg  */
    223  1.1  mrg static isl_stat detect_stride(__isl_take isl_constraint *c, void *user)
    224  1.1  mrg {
    225  1.1  mrg 	struct isl_detect_stride_data *data = user;
    226  1.1  mrg 	int i;
    227  1.1  mrg 	isl_size n_div;
    228  1.1  mrg 	isl_ctx *ctx;
    229  1.1  mrg 	isl_stat r = isl_stat_ok;
    230  1.1  mrg 	isl_val *v, *stride, *m;
    231  1.1  mrg 	isl_bool is_eq, relevant, has_stride;
    232  1.1  mrg 
    233  1.1  mrg 	is_eq = isl_constraint_is_equality(c);
    234  1.1  mrg 	relevant = isl_constraint_involves_dims(c, isl_dim_set, data->pos, 1);
    235  1.1  mrg 	if (is_eq < 0 || relevant < 0)
    236  1.1  mrg 		goto error;
    237  1.1  mrg 	if (!is_eq || !relevant) {
    238  1.1  mrg 		isl_constraint_free(c);
    239  1.1  mrg 		return isl_stat_ok;
    240  1.1  mrg 	}
    241  1.1  mrg 
    242  1.1  mrg 	n_div = isl_constraint_dim(c, isl_dim_div);
    243  1.1  mrg 	if (n_div < 0)
    244  1.1  mrg 		goto error;
    245  1.1  mrg 	ctx = isl_constraint_get_ctx(c);
    246  1.1  mrg 	stride = isl_val_zero(ctx);
    247  1.1  mrg 	for (i = 0; i < n_div; ++i) {
    248  1.1  mrg 		v = isl_constraint_get_coefficient_val(c, isl_dim_div, i);
    249  1.1  mrg 		stride = isl_val_gcd(stride, v);
    250  1.1  mrg 	}
    251  1.1  mrg 
    252  1.1  mrg 	v = isl_constraint_get_coefficient_val(c, isl_dim_set, data->pos);
    253  1.1  mrg 	m = isl_val_gcd(isl_val_copy(stride), isl_val_copy(v));
    254  1.1  mrg 	stride = isl_val_div(stride, isl_val_copy(m));
    255  1.1  mrg 	v = isl_val_div(v, isl_val_copy(m));
    256  1.1  mrg 
    257  1.1  mrg 	has_stride = isl_val_gt_si(stride, 1);
    258  1.1  mrg 	if (has_stride >= 0 && has_stride) {
    259  1.1  mrg 		isl_aff *aff;
    260  1.1  mrg 		isl_val *gcd, *a, *b;
    261  1.1  mrg 
    262  1.1  mrg 		gcd = isl_val_gcdext(v, isl_val_copy(stride), &a, &b);
    263  1.1  mrg 		isl_val_free(gcd);
    264  1.1  mrg 		isl_val_free(b);
    265  1.1  mrg 
    266  1.1  mrg 		aff = isl_constraint_get_aff(c);
    267  1.1  mrg 		for (i = 0; i < n_div; ++i)
    268  1.1  mrg 			aff = isl_aff_set_coefficient_si(aff,
    269  1.1  mrg 							 isl_dim_div, i, 0);
    270  1.1  mrg 		aff = isl_aff_set_coefficient_si(aff, isl_dim_in, data->pos, 0);
    271  1.1  mrg 		aff = isl_aff_remove_unused_divs(aff);
    272  1.1  mrg 		a = isl_val_neg(a);
    273  1.1  mrg 		aff = isl_aff_scale_val(aff, a);
    274  1.1  mrg 		aff = isl_aff_scale_down_val(aff, m);
    275  1.1  mrg 		r = set_stride(data, stride, aff);
    276  1.1  mrg 	} else {
    277  1.1  mrg 		isl_val_free(stride);
    278  1.1  mrg 		isl_val_free(m);
    279  1.1  mrg 		isl_val_free(v);
    280  1.1  mrg 	}
    281  1.1  mrg 
    282  1.1  mrg 	isl_constraint_free(c);
    283  1.1  mrg 	if (has_stride < 0)
    284  1.1  mrg 		return isl_stat_error;
    285  1.1  mrg 	return r;
    286  1.1  mrg error:
    287  1.1  mrg 	isl_constraint_free(c);
    288  1.1  mrg 	return isl_stat_error;
    289  1.1  mrg }
    290  1.1  mrg 
    291  1.1  mrg /* Check if the constraints in "set" imply any stride on set dimension "pos" and
    292  1.1  mrg  * store the results in data->stride and data->offset.
    293  1.1  mrg  *
    294  1.1  mrg  * In particular, compute the affine hull and then check if
    295  1.1  mrg  * any of the constraints in the hull impose any stride on the dimension.
    296  1.1  mrg  * If no such constraint can be found, then the offset is taken
    297  1.1  mrg  * to be the zero expression and the stride is taken to be one.
    298  1.1  mrg  */
    299  1.1  mrg static void set_detect_stride(__isl_keep isl_set *set, int pos,
    300  1.1  mrg 	struct isl_detect_stride_data *data)
    301  1.1  mrg {
    302  1.1  mrg 	isl_basic_set *hull;
    303  1.1  mrg 
    304  1.1  mrg 	hull = isl_set_affine_hull(isl_set_copy(set));
    305  1.1  mrg 
    306  1.1  mrg 	data->pos = pos;
    307  1.1  mrg 	data->found = 0;
    308  1.1  mrg 	data->stride = NULL;
    309  1.1  mrg 	data->offset = NULL;
    310  1.1  mrg 	if (isl_basic_set_foreach_constraint(hull, &detect_stride, data) < 0)
    311  1.1  mrg 		goto error;
    312  1.1  mrg 
    313  1.1  mrg 	if (!data->found) {
    314  1.1  mrg 		data->stride = isl_val_one(isl_set_get_ctx(set));
    315  1.1  mrg 		if (data->want_offset) {
    316  1.1  mrg 			isl_space *space;
    317  1.1  mrg 			isl_local_space *ls;
    318  1.1  mrg 
    319  1.1  mrg 			space = isl_set_get_space(set);
    320  1.1  mrg 			ls = isl_local_space_from_space(space);
    321  1.1  mrg 			data->offset = isl_aff_zero_on_domain(ls);
    322  1.1  mrg 		}
    323  1.1  mrg 	}
    324  1.1  mrg 	isl_basic_set_free(hull);
    325  1.1  mrg 	return;
    326  1.1  mrg error:
    327  1.1  mrg 	isl_basic_set_free(hull);
    328  1.1  mrg 	data->stride = isl_val_free(data->stride);
    329  1.1  mrg 	data->offset = isl_aff_free(data->offset);
    330  1.1  mrg }
    331  1.1  mrg 
    332  1.1  mrg /* Check if the constraints in "set" imply any stride on set dimension "pos" and
    333  1.1  mrg  * return the results in the form of an offset and a stride.
    334  1.1  mrg  */
    335  1.1  mrg __isl_give isl_stride_info *isl_set_get_stride_info(__isl_keep isl_set *set,
    336  1.1  mrg 	int pos)
    337  1.1  mrg {
    338  1.1  mrg 	struct isl_detect_stride_data data;
    339  1.1  mrg 
    340  1.1  mrg 	data.want_offset = 1;
    341  1.1  mrg 	set_detect_stride(set, pos, &data);
    342  1.1  mrg 
    343  1.1  mrg 	return isl_stride_info_alloc(data.stride, data.offset);
    344  1.1  mrg }
    345  1.1  mrg 
    346  1.1  mrg /* Check if the constraints in "set" imply any stride on set dimension "pos" and
    347  1.1  mrg  * return this stride.
    348  1.1  mrg  */
    349  1.1  mrg __isl_give isl_val *isl_set_get_stride(__isl_keep isl_set *set, int pos)
    350  1.1  mrg {
    351  1.1  mrg 	struct isl_detect_stride_data data;
    352  1.1  mrg 
    353  1.1  mrg 	data.want_offset = 0;
    354  1.1  mrg 	set_detect_stride(set, pos, &data);
    355  1.1  mrg 
    356  1.1  mrg 	return data.stride;
    357  1.1  mrg }
    358  1.1  mrg 
    359  1.1  mrg /* Check if the constraints in "map" imply any stride on output dimension "pos",
    360  1.1  mrg  * independently of any other output dimensions, and
    361  1.1  mrg  * return the results in the form of an offset and a stride.
    362  1.1  mrg  *
    363  1.1  mrg  * Convert the input to a set with only the input dimensions and
    364  1.1  mrg  * the single output dimension such that it be passed to
    365  1.1  mrg  * isl_set_get_stride_info and convert the result back to
    366  1.1  mrg  * an expression defined over the domain of "map".
    367  1.1  mrg  */
    368  1.1  mrg __isl_give isl_stride_info *isl_map_get_range_stride_info(
    369  1.1  mrg 	__isl_keep isl_map *map, int pos)
    370  1.1  mrg {
    371  1.1  mrg 	isl_stride_info *si;
    372  1.1  mrg 	isl_set *set;
    373  1.1  mrg 	isl_size n_in;
    374  1.1  mrg 
    375  1.1  mrg 	n_in = isl_map_dim(map, isl_dim_in);
    376  1.1  mrg 	if (n_in < 0)
    377  1.1  mrg 		return NULL;
    378  1.1  mrg 	map = isl_map_copy(map);
    379  1.1  mrg 	map = isl_map_project_onto(map, isl_dim_out, pos, 1);
    380  1.1  mrg 	set = isl_map_wrap(map);
    381  1.1  mrg 	si = isl_set_get_stride_info(set, n_in);
    382  1.1  mrg 	isl_set_free(set);
    383  1.1  mrg 	if (!si)
    384  1.1  mrg 		return NULL;
    385  1.1  mrg 	si->offset = isl_aff_domain_factor_domain(si->offset);
    386  1.1  mrg 	if (!si->offset)
    387  1.1  mrg 		return isl_stride_info_free(si);
    388  1.1  mrg 	return si;
    389  1.1  mrg }
    390