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