isl_box.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  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. #include <isl/val.h>
  13. #include <isl/space.h>
  14. #include <isl_map_private.h>
  15. #include <isl_aff_private.h>
  16. #include <isl/constraint.h>
  17. #include <isl/ilp.h>
  18. #include <isl/fixed_box.h>
  19. /* Representation of a box of fixed size containing the elements
  20. * [offset, offset + size).
  21. * "size" lives in the target space of "offset".
  22. *
  23. * If any of the "offsets" is NaN, then the object represents
  24. * the failure of finding a fixed-size box.
  25. */
  26. struct isl_fixed_box {
  27. isl_multi_aff *offset;
  28. isl_multi_val *size;
  29. };
  30. /* Free "box" and return NULL.
  31. */
  32. __isl_null isl_fixed_box *isl_fixed_box_free(__isl_take isl_fixed_box *box)
  33. {
  34. if (!box)
  35. return NULL;
  36. isl_multi_aff_free(box->offset);
  37. isl_multi_val_free(box->size);
  38. free(box);
  39. return NULL;
  40. }
  41. /* Construct an isl_fixed_box with the given offset and size.
  42. */
  43. static __isl_give isl_fixed_box *isl_fixed_box_alloc(
  44. __isl_take isl_multi_aff *offset, __isl_take isl_multi_val *size)
  45. {
  46. isl_ctx *ctx;
  47. isl_fixed_box *box;
  48. if (!offset || !size)
  49. goto error;
  50. ctx = isl_multi_aff_get_ctx(offset);
  51. box = isl_alloc_type(ctx, struct isl_fixed_box);
  52. if (!box)
  53. goto error;
  54. box->offset = offset;
  55. box->size = size;
  56. return box;
  57. error:
  58. isl_multi_aff_free(offset);
  59. isl_multi_val_free(size);
  60. return NULL;
  61. }
  62. /* Construct an initial isl_fixed_box with zero offsets
  63. * in the given space and zero corresponding sizes.
  64. */
  65. static __isl_give isl_fixed_box *isl_fixed_box_init(
  66. __isl_take isl_space *space)
  67. {
  68. isl_multi_aff *offset;
  69. isl_multi_val *size;
  70. offset = isl_multi_aff_zero(isl_space_copy(space));
  71. space = isl_space_drop_all_params(isl_space_range(space));
  72. size = isl_multi_val_zero(space);
  73. return isl_fixed_box_alloc(offset, size);
  74. }
  75. /* Return a copy of "box".
  76. */
  77. __isl_give isl_fixed_box *isl_fixed_box_copy(__isl_keep isl_fixed_box *box)
  78. {
  79. isl_multi_aff *offset;
  80. isl_multi_val *size;
  81. offset = isl_fixed_box_get_offset(box);
  82. size = isl_fixed_box_get_size(box);
  83. return isl_fixed_box_alloc(offset, size);
  84. }
  85. /* Replace the offset and size in direction "pos" by "offset" and "size"
  86. * (without checking whether "box" is a valid box).
  87. */
  88. static __isl_give isl_fixed_box *isl_fixed_box_set_extent(
  89. __isl_take isl_fixed_box *box, int pos, __isl_keep isl_aff *offset,
  90. __isl_keep isl_val *size)
  91. {
  92. if (!box)
  93. return NULL;
  94. box->offset = isl_multi_aff_set_aff(box->offset, pos,
  95. isl_aff_copy(offset));
  96. box->size = isl_multi_val_set_val(box->size, pos, isl_val_copy(size));
  97. if (!box->offset || !box->size)
  98. return isl_fixed_box_free(box);
  99. return box;
  100. }
  101. /* Replace the offset and size in direction "pos" by "offset" and "size",
  102. * if "box" is a valid box.
  103. */
  104. static __isl_give isl_fixed_box *isl_fixed_box_set_valid_extent(
  105. __isl_take isl_fixed_box *box, int pos, __isl_keep isl_aff *offset,
  106. __isl_keep isl_val *size)
  107. {
  108. isl_bool valid;
  109. valid = isl_fixed_box_is_valid(box);
  110. if (valid < 0 || !valid)
  111. return box;
  112. return isl_fixed_box_set_extent(box, pos, offset, size);
  113. }
  114. /* Replace "box" by an invalid box, by setting all offsets to NaN
  115. * (and all sizes to infinity).
  116. */
  117. static __isl_give isl_fixed_box *isl_fixed_box_invalidate(
  118. __isl_take isl_fixed_box *box)
  119. {
  120. int i;
  121. isl_size n;
  122. isl_space *space;
  123. isl_val *infty;
  124. isl_aff *nan;
  125. if (!box)
  126. return NULL;
  127. n = isl_multi_val_dim(box->size, isl_dim_set);
  128. if (n < 0)
  129. return isl_fixed_box_free(box);
  130. infty = isl_val_infty(isl_fixed_box_get_ctx(box));
  131. space = isl_space_domain(isl_fixed_box_get_space(box));
  132. nan = isl_aff_nan_on_domain(isl_local_space_from_space(space));
  133. for (i = 0; i < n; ++i)
  134. box = isl_fixed_box_set_extent(box, i, nan, infty);
  135. isl_aff_free(nan);
  136. isl_val_free(infty);
  137. if (!box->offset || !box->size)
  138. return isl_fixed_box_free(box);
  139. return box;
  140. }
  141. /* Project the domain of the fixed box onto its parameter space.
  142. * In particular, project out the domain of the offset.
  143. */
  144. static __isl_give isl_fixed_box *isl_fixed_box_project_domain_on_params(
  145. __isl_take isl_fixed_box *box)
  146. {
  147. isl_bool valid;
  148. valid = isl_fixed_box_is_valid(box);
  149. if (valid < 0)
  150. return isl_fixed_box_free(box);
  151. if (!valid)
  152. return box;
  153. box->offset = isl_multi_aff_project_domain_on_params(box->offset);
  154. if (!box->offset)
  155. return isl_fixed_box_free(box);
  156. return box;
  157. }
  158. /* Return the isl_ctx to which "box" belongs.
  159. */
  160. isl_ctx *isl_fixed_box_get_ctx(__isl_keep isl_fixed_box *box)
  161. {
  162. if (!box)
  163. return NULL;
  164. return isl_multi_aff_get_ctx(box->offset);
  165. }
  166. /* Return the space in which "box" lives.
  167. */
  168. __isl_give isl_space *isl_fixed_box_get_space(__isl_keep isl_fixed_box *box)
  169. {
  170. if (!box)
  171. return NULL;
  172. return isl_multi_aff_get_space(box->offset);
  173. }
  174. /* Does "box" contain valid information?
  175. */
  176. isl_bool isl_fixed_box_is_valid(__isl_keep isl_fixed_box *box)
  177. {
  178. if (!box)
  179. return isl_bool_error;
  180. return isl_bool_not(isl_multi_aff_involves_nan(box->offset));
  181. }
  182. /* Return the offsets of the box "box".
  183. */
  184. __isl_give isl_multi_aff *isl_fixed_box_get_offset(
  185. __isl_keep isl_fixed_box *box)
  186. {
  187. if (!box)
  188. return NULL;
  189. return isl_multi_aff_copy(box->offset);
  190. }
  191. /* Return the sizes of the box "box".
  192. */
  193. __isl_give isl_multi_val *isl_fixed_box_get_size(__isl_keep isl_fixed_box *box)
  194. {
  195. if (!box)
  196. return NULL;
  197. return isl_multi_val_copy(box->size);
  198. }
  199. /* Data used in set_dim_extent and compute_size_in_direction.
  200. *
  201. * "bset" is a wrapped copy of the basic map that has the selected
  202. * output dimension as range.
  203. * "pos" is the position of the variable representing the output dimension,
  204. * i.e., the variable for which the size should be computed. This variable
  205. * is also the last variable in "bset".
  206. * "size" is the best size found so far
  207. * (infinity if no offset was found so far).
  208. * "offset" is the offset corresponding to the best size
  209. * (NULL if no offset was found so far).
  210. */
  211. struct isl_size_info {
  212. isl_basic_set *bset;
  213. isl_size pos;
  214. isl_val *size;
  215. isl_aff *offset;
  216. };
  217. /* Is "c" a suitable bound on dimension "pos" for use as a lower bound
  218. * of a fixed-size range.
  219. * In particular, it needs to be a lower bound on "pos".
  220. * In order for the final offset not to be too complicated,
  221. * the constraint itself should also not involve any integer divisions.
  222. */
  223. static isl_bool is_suitable_bound(__isl_keep isl_constraint *c, unsigned pos)
  224. {
  225. isl_size n_div;
  226. isl_bool is_bound, any_divs;
  227. is_bound = isl_constraint_is_lower_bound(c, isl_dim_set, pos);
  228. if (is_bound < 0 || !is_bound)
  229. return is_bound;
  230. n_div = isl_constraint_dim(c, isl_dim_div);
  231. if (n_div < 0)
  232. return isl_bool_error;
  233. any_divs = isl_constraint_involves_dims(c, isl_dim_div, 0, n_div);
  234. return isl_bool_not(any_divs);
  235. }
  236. /* Given a constraint from the basic set describing the bounds on
  237. * an array index, check if it is a lower bound, say m i >= b(x), and,
  238. * if so, check whether the expression "i - ceil(b(x)/m) + 1" has a constant
  239. * upper bound. If so, and if this bound is smaller than any bound
  240. * derived from earlier constraints, set the size to this bound on
  241. * the expression and the lower bound to ceil(b(x)/m).
  242. */
  243. static isl_stat compute_size_in_direction(__isl_take isl_constraint *c,
  244. void *user)
  245. {
  246. struct isl_size_info *info = user;
  247. isl_val *v;
  248. isl_aff *aff;
  249. isl_aff *lb;
  250. isl_bool is_bound, better;
  251. is_bound = is_suitable_bound(c, info->pos);
  252. if (is_bound < 0 || !is_bound) {
  253. isl_constraint_free(c);
  254. return is_bound < 0 ? isl_stat_error : isl_stat_ok;
  255. }
  256. aff = isl_constraint_get_bound(c, isl_dim_set, info->pos);
  257. aff = isl_aff_ceil(aff);
  258. lb = isl_aff_copy(aff);
  259. aff = isl_aff_neg(aff);
  260. aff = isl_aff_add_coefficient_si(aff, isl_dim_in, info->pos, 1);
  261. v = isl_basic_set_max_val(info->bset, aff);
  262. isl_aff_free(aff);
  263. v = isl_val_add_ui(v, 1);
  264. better = isl_val_lt(v, info->size);
  265. if (better >= 0 && better) {
  266. isl_val_free(info->size);
  267. info->size = isl_val_copy(v);
  268. lb = isl_aff_domain_factor_domain(lb);
  269. isl_aff_free(info->offset);
  270. info->offset = isl_aff_copy(lb);
  271. }
  272. isl_val_free(v);
  273. isl_aff_free(lb);
  274. isl_constraint_free(c);
  275. return better < 0 ? isl_stat_error : isl_stat_ok;
  276. }
  277. /* Look for a fixed-size range of values for the output dimension "pos"
  278. * of "map", by looking for a lower-bound expression in the parameters
  279. * and input dimensions such that the range of the output dimension
  280. * is a constant shifted by this expression.
  281. *
  282. * In particular, look through the explicit lower bounds on the output dimension
  283. * for candidate expressions and pick the one that results in the smallest size.
  284. * Initialize the size with infinity and if no better size is found
  285. * then invalidate the box. Otherwise, set the offset and size
  286. * in the given direction by those that correspond to the smallest size.
  287. *
  288. * Note that while evaluating the size corresponding to a lower bound,
  289. * an affine expression is constructed from the lower bound.
  290. * This lower bound may therefore not have any unknown local variables.
  291. * Eliminate any unknown local variables up front.
  292. * No such restriction needs to be imposed on the set over which
  293. * the size is computed.
  294. */
  295. static __isl_give isl_fixed_box *set_dim_extent(__isl_take isl_fixed_box *box,
  296. __isl_keep isl_map *map, int pos)
  297. {
  298. struct isl_size_info info;
  299. isl_bool valid;
  300. isl_ctx *ctx;
  301. isl_basic_set *bset;
  302. if (!box || !map)
  303. return isl_fixed_box_free(box);
  304. ctx = isl_map_get_ctx(map);
  305. map = isl_map_copy(map);
  306. map = isl_map_project_onto(map, isl_dim_out, pos, 1);
  307. info.size = isl_val_infty(ctx);
  308. info.offset = NULL;
  309. info.pos = isl_map_dim(map, isl_dim_in);
  310. info.bset = isl_basic_map_wrap(isl_map_simple_hull(map));
  311. bset = isl_basic_set_copy(info.bset);
  312. bset = isl_basic_set_remove_unknown_divs(bset);
  313. if (info.pos < 0)
  314. bset = isl_basic_set_free(bset);
  315. if (isl_basic_set_foreach_constraint(bset,
  316. &compute_size_in_direction, &info) < 0)
  317. box = isl_fixed_box_free(box);
  318. isl_basic_set_free(bset);
  319. valid = isl_val_is_int(info.size);
  320. if (valid < 0)
  321. box = isl_fixed_box_free(box);
  322. else if (valid)
  323. box = isl_fixed_box_set_valid_extent(box, pos,
  324. info.offset, info.size);
  325. else
  326. box = isl_fixed_box_invalidate(box);
  327. isl_val_free(info.size);
  328. isl_aff_free(info.offset);
  329. isl_basic_set_free(info.bset);
  330. return box;
  331. }
  332. /* Try and construct a fixed-size rectangular box with an offset
  333. * in terms of the domain of "map" that contains the range of "map".
  334. * If no such box can be constructed, then return an invalidated box,
  335. * i.e., one where isl_fixed_box_is_valid returns false.
  336. *
  337. * Iterate over the dimensions in the range
  338. * setting the corresponding offset and extent.
  339. */
  340. __isl_give isl_fixed_box *isl_map_get_range_simple_fixed_box_hull(
  341. __isl_keep isl_map *map)
  342. {
  343. int i;
  344. isl_size n;
  345. isl_space *space;
  346. isl_fixed_box *box;
  347. n = isl_map_dim(map, isl_dim_out);
  348. if (n < 0)
  349. return NULL;
  350. space = isl_map_get_space(map);
  351. box = isl_fixed_box_init(space);
  352. map = isl_map_detect_equalities(isl_map_copy(map));
  353. for (i = 0; i < n; ++i) {
  354. isl_bool valid;
  355. box = set_dim_extent(box, map, i);
  356. valid = isl_fixed_box_is_valid(box);
  357. if (valid < 0 || !valid)
  358. break;
  359. }
  360. isl_map_free(map);
  361. return box;
  362. }
  363. /* Try and construct a fixed-size rectangular box with an offset
  364. * in terms of the parameters of "set" that contains "set".
  365. * If no such box can be constructed, then return an invalidated box,
  366. * i.e., one where isl_fixed_box_is_valid returns false.
  367. *
  368. * Compute the box using isl_map_get_range_simple_fixed_box_hull
  369. * by constructing a map from the set and
  370. * project out the domain again from the result.
  371. */
  372. __isl_give isl_fixed_box *isl_set_get_simple_fixed_box_hull(
  373. __isl_keep isl_set *set)
  374. {
  375. isl_map *map;
  376. isl_fixed_box *box;
  377. map = isl_map_from_range(isl_set_copy(set));
  378. box = isl_map_get_range_simple_fixed_box_hull(map);
  379. isl_map_free(map);
  380. box = isl_fixed_box_project_domain_on_params(box);
  381. return box;
  382. }
  383. /* Check whether the output elements lie on a rectangular lattice,
  384. * possibly depending on the parameters and the input dimensions.
  385. * Return a tile in this lattice.
  386. * If no stride information can be found, then return a tile of size 1
  387. * (and offset 0).
  388. *
  389. * Obtain stride information in each output dimension separately and
  390. * combine the results.
  391. */
  392. __isl_give isl_fixed_box *isl_map_get_range_lattice_tile(
  393. __isl_keep isl_map *map)
  394. {
  395. int i;
  396. isl_size n;
  397. isl_space *space;
  398. isl_fixed_box *box;
  399. n = isl_map_dim(map, isl_dim_out);
  400. if (n < 0)
  401. return NULL;
  402. space = isl_map_get_space(map);
  403. box = isl_fixed_box_init(space);
  404. for (i = 0; i < n; ++i) {
  405. isl_val *stride;
  406. isl_aff *offset;
  407. isl_stride_info *si;
  408. si = isl_map_get_range_stride_info(map, i);
  409. stride = isl_stride_info_get_stride(si);
  410. offset = isl_stride_info_get_offset(si);
  411. isl_stride_info_free(si);
  412. box = isl_fixed_box_set_valid_extent(box, i, offset, stride);
  413. isl_aff_free(offset);
  414. isl_val_free(stride);
  415. }
  416. return box;
  417. }
  418. #undef BASE
  419. #define BASE multi_val
  420. #include "print_yaml_field_templ.c"
  421. #undef BASE
  422. #define BASE multi_aff
  423. #include "print_yaml_field_templ.c"
  424. /* Print the information contained in "box" to "p".
  425. * The information is printed as a YAML document.
  426. */
  427. __isl_give isl_printer *isl_printer_print_fixed_box(
  428. __isl_take isl_printer *p, __isl_keep isl_fixed_box *box)
  429. {
  430. if (!box)
  431. return isl_printer_free(p);
  432. p = isl_printer_yaml_start_mapping(p);
  433. p = print_yaml_field_multi_aff(p, "offset", box->offset);
  434. p = print_yaml_field_multi_val(p, "size", box->size);
  435. p = isl_printer_yaml_end_mapping(p);
  436. return p;
  437. }
  438. #undef BASE
  439. #define BASE fixed_box
  440. #include <print_templ_yaml.c>