Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright 2010-2011 INRIA Saclay
      3  * Copyright 2012-2013 Ecole Normale Superieure
      4  *
      5  * Use of this software is governed by the MIT license
      6  *
      7  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
      8  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
      9  * 91893 Orsay, France
     10  * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
     11  */
     12 
     13 #include <isl/val.h>
     14 #include <isl/space.h>
     15 #include <isl_map_private.h>
     16 #include <isl_aff_private.h>
     17 #include <isl/constraint.h>
     18 #include <isl/ilp.h>
     19 #include <isl/fixed_box.h>
     20 #include <isl/stream.h>
     21 
     22 /* Representation of a box of fixed size containing the elements
     23  * [offset, offset + size).
     24  * "size" lives in the target space of "offset".
     25  *
     26  * If any of the "offsets" is NaN, then the object represents
     27  * the failure of finding a fixed-size box.
     28  */
     29 struct isl_fixed_box {
     30 	isl_multi_aff *offset;
     31 	isl_multi_val *size;
     32 };
     33 
     34 /* Free "box" and return NULL.
     35  */
     36 __isl_null isl_fixed_box *isl_fixed_box_free(__isl_take isl_fixed_box *box)
     37 {
     38 	if (!box)
     39 		return NULL;
     40 	isl_multi_aff_free(box->offset);
     41 	isl_multi_val_free(box->size);
     42 	free(box);
     43 	return NULL;
     44 }
     45 
     46 /* Construct an isl_fixed_box with the given offset and size.
     47  */
     48 static __isl_give isl_fixed_box *isl_fixed_box_alloc(
     49 	__isl_take isl_multi_aff *offset, __isl_take isl_multi_val *size)
     50 {
     51 	isl_ctx *ctx;
     52 	isl_fixed_box *box;
     53 
     54 	if (!offset || !size)
     55 		goto error;
     56 	ctx = isl_multi_aff_get_ctx(offset);
     57 	box = isl_alloc_type(ctx, struct isl_fixed_box);
     58 	if (!box)
     59 		goto error;
     60 	box->offset = offset;
     61 	box->size = size;
     62 
     63 	return box;
     64 error:
     65 	isl_multi_aff_free(offset);
     66 	isl_multi_val_free(size);
     67 	return NULL;
     68 }
     69 
     70 /* Construct an initial isl_fixed_box with zero offsets
     71  * in the given space and zero corresponding sizes.
     72  */
     73 static __isl_give isl_fixed_box *isl_fixed_box_init(
     74 	__isl_take isl_space *space)
     75 {
     76 	isl_multi_aff *offset;
     77 	isl_multi_val *size;
     78 
     79 	offset = isl_multi_aff_zero(isl_space_copy(space));
     80 	space = isl_space_drop_all_params(isl_space_range(space));
     81 	size = isl_multi_val_zero(space);
     82 	return isl_fixed_box_alloc(offset, size);
     83 }
     84 
     85 /* Return a copy of "box".
     86  */
     87 __isl_give isl_fixed_box *isl_fixed_box_copy(__isl_keep isl_fixed_box *box)
     88 {
     89 	isl_multi_aff *offset;
     90 	isl_multi_val *size;
     91 
     92 	offset = isl_fixed_box_get_offset(box);
     93 	size = isl_fixed_box_get_size(box);
     94 	return isl_fixed_box_alloc(offset, size);
     95 }
     96 
     97 /* Replace the offset and size in direction "pos" by "offset" and "size"
     98  * (without checking whether "box" is a valid box).
     99  */
    100 static __isl_give isl_fixed_box *isl_fixed_box_set_extent(
    101 	__isl_take isl_fixed_box *box, int pos, __isl_keep isl_aff *offset,
    102 	__isl_keep isl_val *size)
    103 {
    104 	if (!box)
    105 		return NULL;
    106 	box->offset = isl_multi_aff_set_aff(box->offset, pos,
    107 							isl_aff_copy(offset));
    108 	box->size = isl_multi_val_set_val(box->size, pos, isl_val_copy(size));
    109 	if (!box->offset || !box->size)
    110 		return isl_fixed_box_free(box);
    111 	return box;
    112 }
    113 
    114 /* Replace the offset and size in direction "pos" by "offset" and "size",
    115  * if "box" is a valid box.
    116  */
    117 static __isl_give isl_fixed_box *isl_fixed_box_set_valid_extent(
    118 	__isl_take isl_fixed_box *box, int pos, __isl_keep isl_aff *offset,
    119 	__isl_keep isl_val *size)
    120 {
    121 	isl_bool valid;
    122 
    123 	valid = isl_fixed_box_is_valid(box);
    124 	if (valid < 0 || !valid)
    125 		return box;
    126 	return isl_fixed_box_set_extent(box, pos, offset, size);
    127 }
    128 
    129 /* Replace "box" by an invalid box, by setting all offsets to NaN
    130  * (and all sizes to infinity).
    131  */
    132 static __isl_give isl_fixed_box *isl_fixed_box_invalidate(
    133 	__isl_take isl_fixed_box *box)
    134 {
    135 	int i;
    136 	isl_size n;
    137 	isl_space *space;
    138 	isl_val *infty;
    139 	isl_aff *nan;
    140 
    141 	if (!box)
    142 		return NULL;
    143 	n = isl_multi_val_dim(box->size, isl_dim_set);
    144 	if (n < 0)
    145 		return isl_fixed_box_free(box);
    146 
    147 	infty = isl_val_infty(isl_fixed_box_get_ctx(box));
    148 	space = isl_space_domain(isl_fixed_box_get_space(box));
    149 	nan = isl_aff_nan_on_domain(isl_local_space_from_space(space));
    150 	for (i = 0; i < n; ++i)
    151 		box = isl_fixed_box_set_extent(box, i, nan, infty);
    152 	isl_aff_free(nan);
    153 	isl_val_free(infty);
    154 
    155 	if (!box->offset || !box->size)
    156 		return isl_fixed_box_free(box);
    157 	return box;
    158 }
    159 
    160 /* Project the domain of the fixed box onto its parameter space.
    161  * In particular, project out the domain of the offset.
    162  */
    163 static __isl_give isl_fixed_box *isl_fixed_box_project_domain_on_params(
    164 	__isl_take isl_fixed_box *box)
    165 {
    166 	isl_bool valid;
    167 
    168 	valid = isl_fixed_box_is_valid(box);
    169 	if (valid < 0)
    170 		return isl_fixed_box_free(box);
    171 	if (!valid)
    172 		return box;
    173 
    174 	box->offset = isl_multi_aff_project_domain_on_params(box->offset);
    175 	if (!box->offset)
    176 		return isl_fixed_box_free(box);
    177 
    178 	return box;
    179 }
    180 
    181 /* Return the isl_ctx to which "box" belongs.
    182  */
    183 isl_ctx *isl_fixed_box_get_ctx(__isl_keep isl_fixed_box *box)
    184 {
    185 	if (!box)
    186 		return NULL;
    187 	return isl_multi_aff_get_ctx(box->offset);
    188 }
    189 
    190 /* Return the space in which "box" lives.
    191  */
    192 __isl_give isl_space *isl_fixed_box_get_space(__isl_keep isl_fixed_box *box)
    193 {
    194 	if (!box)
    195 		return NULL;
    196 	return isl_multi_aff_get_space(box->offset);
    197 }
    198 
    199 /* Does "box" contain valid information?
    200  */
    201 isl_bool isl_fixed_box_is_valid(__isl_keep isl_fixed_box *box)
    202 {
    203 	if (!box)
    204 		return isl_bool_error;
    205 	return isl_bool_not(isl_multi_aff_involves_nan(box->offset));
    206 }
    207 
    208 /* Return the offsets of the box "box".
    209  */
    210 __isl_give isl_multi_aff *isl_fixed_box_get_offset(
    211 	__isl_keep isl_fixed_box *box)
    212 {
    213 	if (!box)
    214 		return NULL;
    215 	return isl_multi_aff_copy(box->offset);
    216 }
    217 
    218 /* Return the sizes of the box "box".
    219  */
    220 __isl_give isl_multi_val *isl_fixed_box_get_size(__isl_keep isl_fixed_box *box)
    221 {
    222 	if (!box)
    223 		return NULL;
    224 	return isl_multi_val_copy(box->size);
    225 }
    226 
    227 /* Data used in set_dim_extent and compute_size_in_direction.
    228  *
    229  * "bset" is a wrapped copy of the basic map that has the selected
    230  * output dimension as range.
    231  * "pos" is the position of the variable representing the output dimension,
    232  * i.e., the variable for which the size should be computed.  This variable
    233  * is also the last variable in "bset".
    234  * "size" is the best size found so far
    235  * (infinity if no offset was found so far).
    236  * "offset" is the offset corresponding to the best size
    237  * (NULL if no offset was found so far).
    238  */
    239 struct isl_size_info {
    240 	isl_basic_set *bset;
    241 	isl_size pos;
    242 	isl_val *size;
    243 	isl_aff *offset;
    244 };
    245 
    246 /* Is "c" a suitable bound on dimension "pos" for use as a lower bound
    247  * of a fixed-size range.
    248  * In particular, it needs to be a lower bound on "pos".
    249  * In order for the final offset not to be too complicated,
    250  * the constraint itself should also not involve any integer divisions.
    251  */
    252 static isl_bool is_suitable_bound(__isl_keep isl_constraint *c, unsigned pos)
    253 {
    254 	isl_size n_div;
    255 	isl_bool is_bound, any_divs;
    256 
    257 	is_bound = isl_constraint_is_lower_bound(c, isl_dim_set, pos);
    258 	if (is_bound < 0 || !is_bound)
    259 		return is_bound;
    260 
    261 	n_div = isl_constraint_dim(c, isl_dim_div);
    262 	if (n_div < 0)
    263 		return isl_bool_error;
    264 	any_divs = isl_constraint_involves_dims(c, isl_dim_div, 0, n_div);
    265 	return isl_bool_not(any_divs);
    266 }
    267 
    268 /* Given a constraint from the basic set describing the bounds on
    269  * an array index, check if it is a lower bound, say m i >= b(x), and,
    270  * if so, check whether the expression "i - ceil(b(x)/m) + 1" has a constant
    271  * upper bound.  If so, and if this bound is smaller than any bound
    272  * derived from earlier constraints, set the size to this bound on
    273  * the expression and the lower bound to ceil(b(x)/m).
    274  */
    275 static isl_stat compute_size_in_direction(__isl_take isl_constraint *c,
    276 	void *user)
    277 {
    278 	struct isl_size_info *info = user;
    279 	isl_val *v;
    280 	isl_aff *aff;
    281 	isl_aff *lb;
    282 	isl_bool is_bound, better;
    283 
    284 	is_bound = is_suitable_bound(c, info->pos);
    285 	if (is_bound < 0 || !is_bound) {
    286 		isl_constraint_free(c);
    287 		return is_bound < 0 ? isl_stat_error : isl_stat_ok;
    288 	}
    289 
    290 	aff = isl_constraint_get_bound(c, isl_dim_set, info->pos);
    291 	aff = isl_aff_ceil(aff);
    292 
    293 	lb = isl_aff_copy(aff);
    294 
    295 	aff = isl_aff_neg(aff);
    296 	aff = isl_aff_add_coefficient_si(aff, isl_dim_in, info->pos, 1);
    297 
    298 	v = isl_basic_set_max_val(info->bset, aff);
    299 	isl_aff_free(aff);
    300 
    301 	v = isl_val_add_ui(v, 1);
    302 	better = isl_val_lt(v, info->size);
    303 	if (better >= 0 && better) {
    304 		isl_val_free(info->size);
    305 		info->size = isl_val_copy(v);
    306 		lb = isl_aff_domain_factor_domain(lb);
    307 		isl_aff_free(info->offset);
    308 		info->offset = isl_aff_copy(lb);
    309 	}
    310 	isl_val_free(v);
    311 	isl_aff_free(lb);
    312 
    313 	isl_constraint_free(c);
    314 
    315 	return better < 0 ? isl_stat_error : isl_stat_ok;
    316 }
    317 
    318 /* Look for a fixed-size range of values for the output dimension "pos"
    319  * of "map", by looking for a lower-bound expression in the parameters
    320  * and input dimensions such that the range of the output dimension
    321  * is a constant shifted by this expression.
    322  *
    323  * In particular, look through the explicit lower bounds on the output dimension
    324  * for candidate expressions and pick the one that results in the smallest size.
    325  * Initialize the size with infinity and if no better size is found
    326  * then invalidate the box.  Otherwise, set the offset and size
    327  * in the given direction by those that correspond to the smallest size.
    328  *
    329  * Note that while evaluating the size corresponding to a lower bound,
    330  * an affine expression is constructed from the lower bound.
    331  * This lower bound may therefore not have any unknown local variables.
    332  * Eliminate any unknown local variables up front.
    333  * No such restriction needs to be imposed on the set over which
    334  * the size is computed.
    335  */
    336 static __isl_give isl_fixed_box *set_dim_extent(__isl_take isl_fixed_box *box,
    337 	__isl_keep isl_map *map, int pos)
    338 {
    339 	struct isl_size_info info;
    340 	isl_bool valid;
    341 	isl_ctx *ctx;
    342 	isl_basic_set *bset;
    343 
    344 	if (!box || !map)
    345 		return isl_fixed_box_free(box);
    346 
    347 	ctx = isl_map_get_ctx(map);
    348 	map = isl_map_copy(map);
    349 	map = isl_map_project_onto(map, isl_dim_out, pos, 1);
    350 	info.size = isl_val_infty(ctx);
    351 	info.offset = NULL;
    352 	info.pos = isl_map_dim(map, isl_dim_in);
    353 	info.bset = isl_basic_map_wrap(isl_map_simple_hull(map));
    354 	bset = isl_basic_set_copy(info.bset);
    355 	bset = isl_basic_set_remove_unknown_divs(bset);
    356 	if (info.pos < 0)
    357 		bset = isl_basic_set_free(bset);
    358 	if (isl_basic_set_foreach_constraint(bset,
    359 					&compute_size_in_direction, &info) < 0)
    360 		box = isl_fixed_box_free(box);
    361 	isl_basic_set_free(bset);
    362 	valid = isl_val_is_int(info.size);
    363 	if (valid < 0)
    364 		box = isl_fixed_box_free(box);
    365 	else if (valid)
    366 		box = isl_fixed_box_set_valid_extent(box, pos,
    367 						     info.offset, info.size);
    368 	else
    369 		box = isl_fixed_box_invalidate(box);
    370 	isl_val_free(info.size);
    371 	isl_aff_free(info.offset);
    372 	isl_basic_set_free(info.bset);
    373 
    374 	return box;
    375 }
    376 
    377 /* Try and construct a fixed-size rectangular box with an offset
    378  * in terms of the domain of "map" that contains the range of "map".
    379  * If no such box can be constructed, then return an invalidated box,
    380  * i.e., one where isl_fixed_box_is_valid returns false.
    381  *
    382  * Iterate over the dimensions in the range
    383  * setting the corresponding offset and extent.
    384  */
    385 __isl_give isl_fixed_box *isl_map_get_range_simple_fixed_box_hull(
    386 	__isl_keep isl_map *map)
    387 {
    388 	int i;
    389 	isl_size n;
    390 	isl_space *space;
    391 	isl_fixed_box *box;
    392 
    393 	n = isl_map_dim(map, isl_dim_out);
    394 	if (n < 0)
    395 		return NULL;
    396 	space = isl_map_get_space(map);
    397 	box = isl_fixed_box_init(space);
    398 
    399 	map = isl_map_detect_equalities(isl_map_copy(map));
    400 	for (i = 0; i < n; ++i) {
    401 		isl_bool valid;
    402 
    403 		box = set_dim_extent(box, map, i);
    404 		valid = isl_fixed_box_is_valid(box);
    405 		if (valid < 0 || !valid)
    406 			break;
    407 	}
    408 	isl_map_free(map);
    409 
    410 	return box;
    411 }
    412 
    413 /* Compute a fixed box from "set" using "map_box" by treating it as a map
    414  * with a zero-dimensional domain and
    415  * project out the domain again from the result.
    416  */
    417 static __isl_give isl_fixed_box *fixed_box_as_map(__isl_keep isl_set *set,
    418 	__isl_give isl_fixed_box *(*map_box)(__isl_keep isl_map *map))
    419 {
    420 	isl_map *map;
    421 	isl_fixed_box *box;
    422 
    423 	map = isl_map_from_range(isl_set_copy(set));
    424 	box = map_box(map);
    425 	isl_map_free(map);
    426 	box = isl_fixed_box_project_domain_on_params(box);
    427 
    428 	return box;
    429 }
    430 
    431 /* Try and construct a fixed-size rectangular box with an offset
    432  * in terms of the parameters of "set" that contains "set".
    433  * If no such box can be constructed, then return an invalidated box,
    434  * i.e., one where isl_fixed_box_is_valid returns false.
    435  *
    436  * Compute the box using isl_map_get_range_simple_fixed_box_hull
    437  * by constructing a map from the set and
    438  * project out the domain again from the result.
    439  */
    440 __isl_give isl_fixed_box *isl_set_get_simple_fixed_box_hull(
    441 	__isl_keep isl_set *set)
    442 {
    443 	return fixed_box_as_map(set, &isl_map_get_range_simple_fixed_box_hull);
    444 }
    445 
    446 /* Check whether the output elements lie on a rectangular lattice,
    447  * possibly depending on the parameters and the input dimensions.
    448  * Return a tile in this lattice.
    449  * If no stride information can be found, then return a tile of size 1
    450  * (and offset 0).
    451  *
    452  * Obtain stride information in each output dimension separately and
    453  * combine the results.
    454  */
    455 __isl_give isl_fixed_box *isl_map_get_range_lattice_tile(
    456 	__isl_keep isl_map *map)
    457 {
    458 	int i;
    459 	isl_size n;
    460 	isl_space *space;
    461 	isl_fixed_box *box;
    462 
    463 	n = isl_map_dim(map, isl_dim_out);
    464 	if (n < 0)
    465 		return NULL;
    466 	space = isl_map_get_space(map);
    467 	box = isl_fixed_box_init(space);
    468 
    469 	for (i = 0; i < n; ++i) {
    470 		isl_val *stride;
    471 		isl_aff *offset;
    472 		isl_stride_info *si;
    473 
    474 		si = isl_map_get_range_stride_info(map, i);
    475 		stride = isl_stride_info_get_stride(si);
    476 		offset = isl_stride_info_get_offset(si);
    477 		isl_stride_info_free(si);
    478 
    479 		box = isl_fixed_box_set_valid_extent(box, i, offset, stride);
    480 
    481 		isl_aff_free(offset);
    482 		isl_val_free(stride);
    483 	}
    484 
    485 	return box;
    486 }
    487 
    488 /* Check whether the elements lie on a rectangular lattice,
    489  * possibly depending on the parameters.
    490  * Return a tile in this lattice.
    491  * If no stride information can be found, then return a tile of size 1
    492  * (and offset 0).
    493  *
    494  * Consider the set as a map with a zero-dimensional domain and
    495  * obtain a lattice tile of that map.
    496  */
    497 __isl_give isl_fixed_box *isl_set_get_lattice_tile(__isl_keep isl_set *set)
    498 {
    499 	return fixed_box_as_map(set, &isl_map_get_range_lattice_tile);
    500 }
    501 
    502 /* An enumeration of the keys that may appear in a YAML mapping
    503  * of an isl_fixed_box object.
    504  */
    505 enum isl_fb_key {
    506 	isl_fb_key_error = -1,
    507 	isl_fb_key_offset,
    508 	isl_fb_key_size,
    509 	isl_fb_key_end,
    510 };
    511 
    512 /* Textual representations of the YAML keys for an isl_fixed_box object.
    513  */
    514 static char *key_str[] = {
    515 	[isl_fb_key_offset] = "offset",
    516 	[isl_fb_key_size] = "size",
    517 };
    518 
    519 #undef BASE
    520 #define BASE multi_val
    521 #include "print_yaml_field_templ.c"
    522 
    523 #undef BASE
    524 #define BASE multi_aff
    525 #include "print_yaml_field_templ.c"
    526 
    527 /* Print the information contained in "box" to "p".
    528  * The information is printed as a YAML document.
    529  */
    530 __isl_give isl_printer *isl_printer_print_fixed_box(
    531 	__isl_take isl_printer *p, __isl_keep isl_fixed_box *box)
    532 {
    533 	if (!box)
    534 		return isl_printer_free(p);
    535 
    536 	p = isl_printer_yaml_start_mapping(p);
    537 	p = print_yaml_field_multi_aff(p, key_str[isl_fb_key_offset],
    538 					box->offset);
    539 	p = print_yaml_field_multi_val(p, key_str[isl_fb_key_size], box->size);
    540 	p = isl_printer_yaml_end_mapping(p);
    541 
    542 	return p;
    543 }
    544 
    545 #undef BASE
    546 #define BASE fixed_box
    547 #include <print_templ_yaml.c>
    548 
    549 #undef KEY
    550 #define KEY enum isl_fb_key
    551 #undef KEY_ERROR
    552 #define KEY_ERROR isl_fb_key_error
    553 #undef KEY_END
    554 #define KEY_END isl_fb_key_end
    555 #undef KEY_STR
    556 #define KEY_STR key_str
    557 #undef KEY_EXTRACT
    558 #define KEY_EXTRACT extract_key
    559 #undef KEY_GET
    560 #define KEY_GET get_key
    561 #include "extract_key.c"
    562 
    563 #undef BASE
    564 #define BASE multi_val
    565 #include "read_in_string_templ.c"
    566 
    567 #undef BASE
    568 #define BASE multi_aff
    569 #include "read_in_string_templ.c"
    570 
    571 /* Read an isl_fixed_box object from "s".
    572  *
    573  * The input needs to contain both an offset and a size.
    574  * If either is specified multiple times, then the last specification
    575  * overrides all previous ones.  This is simpler than checking
    576  * that each is only specified once.
    577  */
    578 static __isl_give isl_fixed_box *isl_stream_read_fixed_box(isl_stream *s)
    579 {
    580 	isl_bool more;
    581 	isl_multi_aff *offset = NULL;
    582 	isl_multi_val *size = NULL;
    583 
    584 	if (isl_stream_yaml_read_start_mapping(s) < 0)
    585 		return NULL;
    586 
    587 	while ((more = isl_stream_yaml_next(s)) == isl_bool_true) {
    588 		enum isl_fb_key key;
    589 
    590 		key = get_key(s);
    591 		if (isl_stream_yaml_next(s) < 0)
    592 			goto error;
    593 		switch (key) {
    594 		case isl_fb_key_end:
    595 		case isl_fb_key_error:
    596 			goto error;
    597 		case isl_fb_key_offset:
    598 			isl_multi_aff_free(offset);
    599 			offset = read_multi_aff(s);
    600 			if (!offset)
    601 				goto error;
    602 			break;
    603 		case isl_fb_key_size:
    604 			isl_multi_val_free(size);
    605 			size = read_multi_val(s);
    606 			if (!size)
    607 				goto error;
    608 			break;
    609 		}
    610 	}
    611 	if (more < 0)
    612 		goto error;
    613 
    614 	if (isl_stream_yaml_read_end_mapping(s) < 0)
    615 		goto error;
    616 
    617 	if (!offset) {
    618 		isl_stream_error(s, NULL, "no offset specified");
    619 		goto error;
    620 	}
    621 
    622 	if (!size) {
    623 		isl_stream_error(s, NULL, "no size specified");
    624 		goto error;
    625 	}
    626 
    627 	return isl_fixed_box_alloc(offset, size);
    628 error:
    629 	isl_multi_aff_free(offset);
    630 	isl_multi_val_free(size);
    631 	return NULL;
    632 }
    633 
    634 #undef TYPE_BASE
    635 #define TYPE_BASE	fixed_box
    636 #include "isl_read_from_str_templ.c"
    637