grouping.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*
  2. * Copyright 2016 Sven Verdoolaege
  3. *
  4. * Use of this software is governed by the MIT license
  5. *
  6. * Written by Sven Verdoolaege.
  7. */
  8. #include <isl/ctx.h>
  9. #include <isl/id.h>
  10. #include <isl/val.h>
  11. #include <isl/space.h>
  12. #include <isl/aff.h>
  13. #include <isl/set.h>
  14. #include <isl/map.h>
  15. #include <isl/union_set.h>
  16. #include <isl/union_map.h>
  17. #include <isl/schedule.h>
  18. #include <isl/schedule_node.h>
  19. #include "ppcg.h"
  20. /* Internal data structure for use during the detection of statements
  21. * that can be grouped.
  22. *
  23. * "sc" contains the original schedule constraints (not a copy).
  24. * "dep" contains the intersection of the validity and the proximity
  25. * constraints in "sc". It may be NULL if it has not been computed yet.
  26. * "group_id" is the identifier for the next group that is extracted.
  27. *
  28. * "domain" is the set of statement instances that belong to any of the groups.
  29. * "contraction" maps the elements of "domain" to the corresponding group
  30. * instances.
  31. * "schedule" schedules the statements in each group relatively to each other.
  32. * These last three fields are NULL if no groups have been found so far.
  33. */
  34. struct ppcg_grouping {
  35. isl_schedule_constraints *sc;
  36. isl_union_map *dep;
  37. int group_id;
  38. isl_union_set *domain;
  39. isl_union_pw_multi_aff *contraction;
  40. isl_schedule *schedule;
  41. };
  42. /* Clear all memory allocated by "grouping".
  43. */
  44. static void ppcg_grouping_clear(struct ppcg_grouping *grouping)
  45. {
  46. isl_union_map_free(grouping->dep);
  47. isl_union_set_free(grouping->domain);
  48. isl_union_pw_multi_aff_free(grouping->contraction);
  49. isl_schedule_free(grouping->schedule);
  50. }
  51. /* Compute the intersection of the proximity and validity dependences
  52. * in grouping->sc and store the result in grouping->dep, unless
  53. * this intersection has been computed before.
  54. */
  55. static isl_stat ppcg_grouping_compute_dep(struct ppcg_grouping *grouping)
  56. {
  57. isl_union_map *validity, *proximity;
  58. if (grouping->dep)
  59. return isl_stat_ok;
  60. validity = isl_schedule_constraints_get_validity(grouping->sc);
  61. proximity = isl_schedule_constraints_get_proximity(grouping->sc);
  62. grouping->dep = isl_union_map_intersect(validity, proximity);
  63. if (!grouping->dep)
  64. return isl_stat_error;
  65. return isl_stat_ok;
  66. }
  67. /* Information extracted from one or more consecutive leaves
  68. * in the input schedule.
  69. *
  70. * "list" contains the sets of statement instances in the leaves,
  71. * one element in the list for each original leaf.
  72. * "domain" contains the union of the sets in "list".
  73. * "prefix" contains the prefix schedule of these elements.
  74. */
  75. struct ppcg_grouping_leaf {
  76. isl_union_set *domain;
  77. isl_union_set_list *list;
  78. isl_multi_union_pw_aff *prefix;
  79. };
  80. /* Free all memory allocated for "leaves".
  81. */
  82. static void ppcg_grouping_leaf_free(int n, struct ppcg_grouping_leaf leaves[])
  83. {
  84. int i;
  85. if (!leaves)
  86. return;
  87. for (i = 0; i < n; ++i) {
  88. isl_union_set_free(leaves[i].domain);
  89. isl_union_set_list_free(leaves[i].list);
  90. isl_multi_union_pw_aff_free(leaves[i].prefix);
  91. }
  92. free(leaves);
  93. }
  94. /* Short-hand for retrieving the prefix schedule at "node"
  95. * in the form of an isl_multi_union_pw_aff.
  96. */
  97. static __isl_give isl_multi_union_pw_aff *get_prefix(
  98. __isl_keep isl_schedule_node *node)
  99. {
  100. return isl_schedule_node_get_prefix_schedule_multi_union_pw_aff(node);
  101. }
  102. /* Return an array of "n" elements with information extracted from
  103. * the "n" children of "node" starting at "first", all of which
  104. * are known to be filtered leaves.
  105. */
  106. struct ppcg_grouping_leaf *extract_leaves(__isl_keep isl_schedule_node *node,
  107. int first, int n)
  108. {
  109. int i;
  110. isl_ctx *ctx;
  111. struct ppcg_grouping_leaf *leaves;
  112. if (!node)
  113. return NULL;
  114. ctx = isl_schedule_node_get_ctx(node);
  115. leaves = isl_calloc_array(ctx, struct ppcg_grouping_leaf, n);
  116. if (!leaves)
  117. return NULL;
  118. for (i = 0; i < n; ++i) {
  119. isl_schedule_node *child;
  120. isl_union_set *domain;
  121. child = isl_schedule_node_get_child(node, first + i);
  122. child = isl_schedule_node_child(child, 0);
  123. domain = isl_schedule_node_get_domain(child);
  124. leaves[i].domain = isl_union_set_copy(domain);
  125. leaves[i].list = isl_union_set_list_from_union_set(domain);
  126. leaves[i].prefix = get_prefix(child);
  127. isl_schedule_node_free(child);
  128. }
  129. return leaves;
  130. }
  131. /* Internal data structure used by merge_leaves.
  132. *
  133. * "src" and "dst" point to the two consecutive leaves that are
  134. * under investigation for being merged.
  135. * "merge" is initially set to 0 and is set to 1 as soon as
  136. * it turns out that it is useful to merge the two leaves.
  137. */
  138. struct ppcg_merge_leaves_data {
  139. int merge;
  140. struct ppcg_grouping_leaf *src;
  141. struct ppcg_grouping_leaf *dst;
  142. };
  143. /* Given a relation "map" between instances of two statements A and B,
  144. * does it relate every instance of A (according to the domain of "src")
  145. * to every instance of B (according to the domain of "dst")?
  146. */
  147. static isl_bool covers_src_and_dst(__isl_keep isl_map *map,
  148. struct ppcg_grouping_leaf *src, struct ppcg_grouping_leaf *dst)
  149. {
  150. isl_space *space;
  151. isl_set *set1, *set2;
  152. isl_bool is_subset;
  153. space = isl_space_domain(isl_map_get_space(map));
  154. set1 = isl_union_set_extract_set(src->domain, space);
  155. set2 = isl_map_domain(isl_map_copy(map));
  156. is_subset = isl_set_is_subset(set1, set2);
  157. isl_set_free(set1);
  158. isl_set_free(set2);
  159. if (is_subset < 0 || !is_subset)
  160. return is_subset;
  161. space = isl_space_range(isl_map_get_space(map));
  162. set1 = isl_union_set_extract_set(dst->domain, space);
  163. set2 = isl_map_range(isl_map_copy(map));
  164. is_subset = isl_set_is_subset(set1, set2);
  165. isl_set_free(set1);
  166. isl_set_free(set2);
  167. return is_subset;
  168. }
  169. /* Given a relation "map" between instances of two statements A and B,
  170. * are pairs of related instances executed together in the input schedule?
  171. * That is, is each pair of instances assigned the same value
  172. * by the corresponding prefix schedules?
  173. *
  174. * In particular, select the subset of "map" that has pairs of elements
  175. * with the same value for the prefix schedules and then check
  176. * if "map" is still a subset of the result.
  177. */
  178. static isl_bool matches_prefix(__isl_keep isl_map *map,
  179. struct ppcg_grouping_leaf *src, struct ppcg_grouping_leaf *dst)
  180. {
  181. isl_union_map *umap, *equal;
  182. isl_multi_union_pw_aff *src_prefix, *dst_prefix, *prefix;
  183. isl_bool is_subset;
  184. src_prefix = isl_multi_union_pw_aff_copy(src->prefix);
  185. dst_prefix = isl_multi_union_pw_aff_copy(dst->prefix);
  186. prefix = isl_multi_union_pw_aff_union_add(src_prefix, dst_prefix);
  187. umap = isl_union_map_from_map(isl_map_copy(map));
  188. equal = isl_union_map_copy(umap);
  189. equal = isl_union_map_eq_at_multi_union_pw_aff(equal, prefix);
  190. is_subset = isl_union_map_is_subset(umap, equal);
  191. isl_union_map_free(umap);
  192. isl_union_map_free(equal);
  193. return is_subset;
  194. }
  195. /* Given a set of validity and proximity schedule constraints "map"
  196. * between statements in consecutive leaves in a valid schedule,
  197. * should the two leaves be merged into one?
  198. *
  199. * In particular, the two are merged if the constraints form
  200. * a bijection between every instance of the first statement and
  201. * every instance of the second statement. Moreover, each
  202. * pair of such dependent instances needs to be executed consecutively
  203. * in the input schedule. That is, they need to be assigned
  204. * the same value by their prefix schedules.
  205. *
  206. * What this means is that for each instance of the first statement
  207. * there is exactly one instance of the second statement that
  208. * is executed immediately after the instance of the first statement and
  209. * that, moreover, both depends on this statement instance and
  210. * should be brought as close as possible to this statement instance.
  211. * In other words, it is both possible to execute the two instances
  212. * together (according to the input schedule) and desirable to do so
  213. * (according to the validity and proximity schedule constraints).
  214. */
  215. static isl_stat check_merge(__isl_take isl_map *map, void *user)
  216. {
  217. struct ppcg_merge_leaves_data *data = user;
  218. isl_bool ok;
  219. ok = covers_src_and_dst(map, data->src, data->dst);
  220. if (ok >= 0 && ok)
  221. ok = isl_map_is_bijective(map);
  222. if (ok >= 0 && ok)
  223. ok = matches_prefix(map, data->src, data->dst);
  224. isl_map_free(map);
  225. if (ok < 0)
  226. return isl_stat_error;
  227. if (!ok)
  228. return isl_stat_ok;
  229. data->merge = 1;
  230. return isl_stat_error;
  231. }
  232. /* Merge the leaves at position "pos" and "pos + 1" in "leaves".
  233. */
  234. static isl_stat merge_pair(int n, struct ppcg_grouping_leaf leaves[], int pos)
  235. {
  236. int i;
  237. leaves[pos].domain = isl_union_set_union(leaves[pos].domain,
  238. leaves[pos + 1].domain);
  239. leaves[pos].list = isl_union_set_list_concat(leaves[pos].list,
  240. leaves[pos + 1].list);
  241. leaves[pos].prefix = isl_multi_union_pw_aff_union_add(
  242. leaves[pos].prefix, leaves[pos + 1].prefix);
  243. for (i = pos + 1; i + 1 < n; ++i)
  244. leaves[i] = leaves[i + 1];
  245. leaves[n - 1].domain = NULL;
  246. leaves[n - 1].list = NULL;
  247. leaves[n - 1].prefix = NULL;
  248. if (!leaves[pos].domain || !leaves[pos].list || !leaves[pos].prefix)
  249. return isl_stat_error;
  250. return isl_stat_ok;
  251. }
  252. /* Merge pairs of consecutive leaves in "leaves" taking into account
  253. * the intersection of validity and proximity schedule constraints "dep".
  254. *
  255. * If a leaf has been merged with the next leaf, then the combination
  256. * is checked again for merging with the next leaf.
  257. * That is, if the leaves are A, B and C, then B may not have been
  258. * merged with C, but after merging A and B, it could still be useful
  259. * to merge the combination AB with C.
  260. *
  261. * Two leaves A and B are merged if there are instances of at least
  262. * one pair of statements, one statement in A and one B, such that
  263. * the validity and proximity schedule constraints between them
  264. * make them suitable for merging according to check_merge.
  265. *
  266. * Return the final number of leaves in the sequence, or -1 on error.
  267. */
  268. static int merge_leaves(int n, struct ppcg_grouping_leaf leaves[],
  269. __isl_keep isl_union_map *dep)
  270. {
  271. int i;
  272. struct ppcg_merge_leaves_data data;
  273. for (i = n - 1; i >= 0; --i) {
  274. isl_union_map *dep_i;
  275. isl_stat ok;
  276. if (i + 1 >= n)
  277. continue;
  278. dep_i = isl_union_map_copy(dep);
  279. dep_i = isl_union_map_intersect_domain(dep_i,
  280. isl_union_set_copy(leaves[i].domain));
  281. dep_i = isl_union_map_intersect_range(dep_i,
  282. isl_union_set_copy(leaves[i + 1].domain));
  283. data.merge = 0;
  284. data.src = &leaves[i];
  285. data.dst = &leaves[i + 1];
  286. ok = isl_union_map_foreach_map(dep_i, &check_merge, &data);
  287. isl_union_map_free(dep_i);
  288. if (ok < 0 && !data.merge)
  289. return -1;
  290. if (!data.merge)
  291. continue;
  292. if (merge_pair(n, leaves, i) < 0)
  293. return -1;
  294. --n;
  295. ++i;
  296. }
  297. return n;
  298. }
  299. /* Construct a schedule with "domain" as domain, that executes
  300. * the elements of "list" in order (as a sequence).
  301. */
  302. static __isl_give isl_schedule *schedule_from_domain_and_list(
  303. __isl_keep isl_union_set *domain, __isl_keep isl_union_set_list *list)
  304. {
  305. isl_schedule *schedule;
  306. isl_schedule_node *node;
  307. schedule = isl_schedule_from_domain(isl_union_set_copy(domain));
  308. node = isl_schedule_get_root(schedule);
  309. isl_schedule_free(schedule);
  310. node = isl_schedule_node_child(node, 0);
  311. list = isl_union_set_list_copy(list);
  312. node = isl_schedule_node_insert_sequence(node, list);
  313. schedule = isl_schedule_node_get_schedule(node);
  314. isl_schedule_node_free(node);
  315. return schedule;
  316. }
  317. /* Construct a unique identifier for a group in "grouping".
  318. *
  319. * The name is of the form G_n, with n the first value starting at
  320. * grouping->group_id that does not result in an identifier
  321. * that is already in use in the domain of the original schedule
  322. * constraints.
  323. */
  324. static isl_id *construct_group_id(struct ppcg_grouping *grouping,
  325. __isl_take isl_space *space)
  326. {
  327. isl_ctx *ctx;
  328. isl_id *id;
  329. isl_bool empty;
  330. isl_union_set *domain;
  331. if (!space)
  332. return NULL;
  333. ctx = isl_space_get_ctx(space);
  334. domain = isl_schedule_constraints_get_domain(grouping->sc);
  335. do {
  336. char buffer[20];
  337. isl_id *id;
  338. isl_set *set;
  339. snprintf(buffer, sizeof(buffer), "G_%d", grouping->group_id);
  340. grouping->group_id++;
  341. id = isl_id_alloc(ctx, buffer, NULL);
  342. space = isl_space_set_tuple_id(space, isl_dim_set, id);
  343. set = isl_union_set_extract_set(domain, isl_space_copy(space));
  344. empty = isl_set_plain_is_empty(set);
  345. isl_set_free(set);
  346. } while (empty >= 0 && !empty);
  347. if (empty < 0)
  348. space = isl_space_free(space);
  349. id = isl_space_get_tuple_id(space, isl_dim_set);
  350. isl_space_free(space);
  351. isl_union_set_free(domain);
  352. return id;
  353. }
  354. /* Construct a contraction from "prefix" and "domain" for a new group
  355. * in "grouping".
  356. *
  357. * The values of the prefix schedule "prefix" are used as instances
  358. * of the new group. The identifier of the group is constructed
  359. * in such a way that it does not conflict with those of earlier
  360. * groups nor with statements in the domain of the original
  361. * schedule constraints.
  362. * The isl_multi_union_pw_aff "prefix" then simply needs to be
  363. * converted to an isl_union_pw_multi_aff. However, this is not
  364. * possible if "prefix" is zero-dimensional, so in this case,
  365. * a contraction is constructed from "domain" instead.
  366. */
  367. static isl_union_pw_multi_aff *group_contraction_from_prefix_and_domain(
  368. struct ppcg_grouping *grouping,
  369. __isl_keep isl_multi_union_pw_aff *prefix,
  370. __isl_keep isl_union_set *domain)
  371. {
  372. isl_id *id;
  373. isl_space *space;
  374. int dim;
  375. space = isl_multi_union_pw_aff_get_space(prefix);
  376. if (!space)
  377. return NULL;
  378. dim = isl_space_dim(space, isl_dim_set);
  379. id = construct_group_id(grouping, space);
  380. if (dim == 0) {
  381. isl_multi_val *mv;
  382. space = isl_multi_union_pw_aff_get_space(prefix);
  383. space = isl_space_set_tuple_id(space, isl_dim_set, id);
  384. mv = isl_multi_val_zero(space);
  385. domain = isl_union_set_copy(domain);
  386. return isl_union_pw_multi_aff_multi_val_on_domain(domain, mv);
  387. }
  388. prefix = isl_multi_union_pw_aff_copy(prefix);
  389. prefix = isl_multi_union_pw_aff_set_tuple_id(prefix, isl_dim_out, id);
  390. return isl_union_pw_multi_aff_from_multi_union_pw_aff(prefix);
  391. }
  392. /* Extend "grouping" with groups corresponding to merged
  393. * leaves in the list of potentially merged leaves "leaves".
  394. *
  395. * The "list" field of each element in "leaves" contains a list
  396. * of the instances sets of the original leaves that have been
  397. * merged into this element. If at least two of the original leaves
  398. * have been merged into a given element, then add the corresponding
  399. * group to "grouping".
  400. * In particular, the domain is extended with the statement instances
  401. * of the merged leaves, the contraction is extended with a mapping
  402. * of these statement instances to instances of a new group and
  403. * the schedule is extended with a schedule that executes
  404. * the statement instances according to the order of the leaves
  405. * in which they appear.
  406. * Since the instances of the groups should already be scheduled apart
  407. * in the schedule into which this schedule will be plugged in,
  408. * the schedules of the individual groups are combined independently
  409. * of each other (as a set).
  410. */
  411. static isl_stat add_groups(struct ppcg_grouping *grouping,
  412. int n, struct ppcg_grouping_leaf leaves[])
  413. {
  414. int i;
  415. for (i = 0; i < n; ++i) {
  416. int n_leaf;
  417. isl_schedule *schedule;
  418. isl_union_set *domain;
  419. isl_union_pw_multi_aff *upma;
  420. n_leaf = isl_union_set_list_n_union_set(leaves[i].list);
  421. if (n_leaf < 0)
  422. return isl_stat_error;
  423. if (n_leaf <= 1)
  424. continue;
  425. schedule = schedule_from_domain_and_list(leaves[i].domain,
  426. leaves[i].list);
  427. upma = group_contraction_from_prefix_and_domain(grouping,
  428. leaves[i].prefix, leaves[i].domain);
  429. domain = isl_union_set_copy(leaves[i].domain);
  430. if (grouping->domain) {
  431. domain = isl_union_set_union(domain, grouping->domain);
  432. upma = isl_union_pw_multi_aff_union_add(upma,
  433. grouping->contraction);
  434. schedule = isl_schedule_set(schedule,
  435. grouping->schedule);
  436. }
  437. grouping->domain = domain;
  438. grouping->contraction = upma;
  439. grouping->schedule = schedule;
  440. if (!grouping->domain || !grouping->contraction ||
  441. !grouping->schedule)
  442. return isl_stat_error;
  443. }
  444. return isl_stat_ok;
  445. }
  446. /* Look for any pairs of consecutive leaves among the "n" children of "node"
  447. * starting at "first" that should be merged together.
  448. * Store the results in "grouping".
  449. *
  450. * First make sure the intersection of validity and proximity
  451. * schedule constraints is available and extract the required
  452. * information from the "n" leaves.
  453. * Then try and merge consecutive leaves based on the validity
  454. * and proximity constraints.
  455. * If any pairs were successfully merged, then add groups
  456. * corresponding to the merged leaves to "grouping".
  457. */
  458. static isl_stat group_subsequence(__isl_keep isl_schedule_node *node,
  459. int first, int n, struct ppcg_grouping *grouping)
  460. {
  461. int n_merge;
  462. struct ppcg_grouping_leaf *leaves;
  463. if (ppcg_grouping_compute_dep(grouping) < 0)
  464. return isl_stat_error;
  465. leaves = extract_leaves(node, first, n);
  466. if (!leaves)
  467. return isl_stat_error;
  468. n_merge = merge_leaves(n, leaves, grouping->dep);
  469. if (n_merge >= 0 && n_merge < n &&
  470. add_groups(grouping, n_merge, leaves) < 0)
  471. return isl_stat_error;
  472. ppcg_grouping_leaf_free(n, leaves);
  473. return isl_stat_ok;
  474. }
  475. /* If "node" is a sequence, then check if it has any consecutive
  476. * leaves that should be merged together and store the results
  477. * in "grouping".
  478. *
  479. * In particular, call group_subsequence on each consecutive
  480. * sequence of (filtered) leaves among the children of "node".
  481. */
  482. static isl_bool detect_groups(__isl_keep isl_schedule_node *node, void *user)
  483. {
  484. int i, n, first;
  485. struct ppcg_grouping *grouping = user;
  486. if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence)
  487. return isl_bool_true;
  488. n = isl_schedule_node_n_children(node);
  489. if (n < 0)
  490. return isl_bool_error;
  491. first = -1;
  492. for (i = 0; i < n; ++i) {
  493. isl_schedule_node *child;
  494. enum isl_schedule_node_type type;
  495. child = isl_schedule_node_get_child(node, i);
  496. child = isl_schedule_node_child(child, 0);
  497. type = isl_schedule_node_get_type(child);
  498. isl_schedule_node_free(child);
  499. if (first >= 0 && type != isl_schedule_node_leaf) {
  500. if (group_subsequence(node, first, i - first,
  501. grouping) < 0)
  502. return isl_bool_error;
  503. first = -1;
  504. }
  505. if (first < 0 && type == isl_schedule_node_leaf)
  506. first = i;
  507. }
  508. if (first >= 0) {
  509. if (group_subsequence(node, first, n - first, grouping) < 0)
  510. return isl_bool_error;
  511. }
  512. return isl_bool_true;
  513. }
  514. /* Complete "grouping" to cover all statement instances in the domain
  515. * of grouping->sc.
  516. *
  517. * In particular, grouping->domain is set to the full set of statement
  518. * instances; group->contraction is extended with an identity
  519. * contraction on the additional instances and group->schedule
  520. * is extended with an independent schedule on those additional instances.
  521. * In the extension of group->contraction, the additional instances
  522. * are split into those belong to different statements and those
  523. * that belong to some of the same statements. The first group
  524. * is replaced by its universe in order to simplify the contraction extension.
  525. */
  526. static void complete_grouping(struct ppcg_grouping *grouping)
  527. {
  528. isl_union_set *domain, *left, *overlap;
  529. isl_union_pw_multi_aff *upma;
  530. isl_schedule *schedule;
  531. domain = isl_schedule_constraints_get_domain(grouping->sc);
  532. left = isl_union_set_subtract(isl_union_set_copy(domain),
  533. isl_union_set_copy(grouping->domain));
  534. schedule = isl_schedule_from_domain(isl_union_set_copy(left));
  535. schedule = isl_schedule_set(schedule, grouping->schedule);
  536. grouping->schedule = schedule;
  537. overlap = isl_union_set_universe(grouping->domain);
  538. grouping->domain = domain;
  539. overlap = isl_union_set_intersect(isl_union_set_copy(left), overlap);
  540. left = isl_union_set_subtract(left, isl_union_set_copy(overlap));
  541. left = isl_union_set_universe(left);
  542. left = isl_union_set_union(left, overlap);
  543. upma = isl_union_set_identity_union_pw_multi_aff(left);
  544. upma = isl_union_pw_multi_aff_union_add(upma, grouping->contraction);
  545. grouping->contraction = upma;
  546. }
  547. /* Compute a schedule on the domain of "sc" that respects the schedule
  548. * constraints in "sc".
  549. *
  550. * "schedule" is a known correct schedule that is used to combine
  551. * groups of statements if options->group_chains is set.
  552. * In particular, statements that are executed consecutively in a sequence
  553. * in this schedule and where all instances of the second depend on
  554. * the instance of the first that is executed in the same iteration
  555. * of outer band nodes are grouped together into a single statement.
  556. * The schedule constraints are then mapped to these groups of statements
  557. * and the resulting schedule is expanded again to refer to the original
  558. * statements.
  559. */
  560. __isl_give isl_schedule *ppcg_compute_schedule(
  561. __isl_take isl_schedule_constraints *sc,
  562. __isl_keep isl_schedule *schedule, struct ppcg_options *options)
  563. {
  564. struct ppcg_grouping grouping = { sc };
  565. isl_union_pw_multi_aff *contraction;
  566. isl_union_map *umap;
  567. isl_schedule *res, *expansion;
  568. if (!options->group_chains)
  569. return isl_schedule_constraints_compute_schedule(sc);
  570. grouping.group_id = 0;
  571. if (isl_schedule_foreach_schedule_node_top_down(schedule,
  572. &detect_groups, &grouping) < 0)
  573. goto error;
  574. if (!grouping.contraction) {
  575. ppcg_grouping_clear(&grouping);
  576. return isl_schedule_constraints_compute_schedule(sc);
  577. }
  578. complete_grouping(&grouping);
  579. contraction = isl_union_pw_multi_aff_copy(grouping.contraction);
  580. umap = isl_union_map_from_union_pw_multi_aff(contraction);
  581. sc = isl_schedule_constraints_apply(sc, umap);
  582. res = isl_schedule_constraints_compute_schedule(sc);
  583. contraction = isl_union_pw_multi_aff_copy(grouping.contraction);
  584. expansion = isl_schedule_copy(grouping.schedule);
  585. res = isl_schedule_expand(res, contraction, expansion);
  586. ppcg_grouping_clear(&grouping);
  587. return res;
  588. error:
  589. ppcg_grouping_clear(&grouping);
  590. isl_schedule_constraints_free(sc);
  591. return NULL;
  592. }