rename isl_ast_build_domain_type to isl_ast_loop_type
[isl.git] / isl_ast_build.c
blob1c5c9372e60b4203f5106eea8f5552bdc69b7d65
1 /*
2 * Copyright 2012-2013 Ecole Normale Superieure
3 * Copyright 2014 INRIA Rocquencourt
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege,
8 * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
9 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
10 * B.P. 105 - 78153 Le Chesnay, France
13 #include <isl/map.h>
14 #include <isl/aff.h>
15 #include <isl/map.h>
16 #include <isl_ast_build_private.h>
17 #include <isl_ast_private.h>
19 /* Construct a map that isolates the current dimension.
21 * Essentially, the current dimension of "set" is moved to the single output
22 * dimension in the result, with the current dimension in the domain replaced
23 * by an unconstrained variable.
25 __isl_give isl_map *isl_ast_build_map_to_iterator(
26 __isl_keep isl_ast_build *build, __isl_take isl_set *set)
28 isl_map *map;
30 map = isl_map_from_domain(set);
31 map = isl_map_add_dims(map, isl_dim_out, 1);
33 if (!build)
34 return isl_map_free(map);
36 map = isl_map_equate(map, isl_dim_in, build->depth, isl_dim_out, 0);
37 map = isl_map_eliminate(map, isl_dim_in, build->depth, 1);
39 return map;
42 /* Initialize the information derived during the AST generation to default
43 * values for a schedule domain in "space".
45 * We also check that the remaining fields are not NULL so that
46 * the calling functions don't have to perform this test.
48 static __isl_give isl_ast_build *isl_ast_build_init_derived(
49 __isl_take isl_ast_build *build, __isl_take isl_space *space)
51 isl_ctx *ctx;
52 isl_vec *strides;
54 build = isl_ast_build_cow(build);
55 if (!build || !build->domain)
56 goto error;
58 ctx = isl_ast_build_get_ctx(build);
59 strides = isl_vec_alloc(ctx, isl_space_dim(space, isl_dim_set));
60 strides = isl_vec_set_si(strides, 1);
62 isl_vec_free(build->strides);
63 build->strides = strides;
65 space = isl_space_map_from_set(space);
66 isl_multi_aff_free(build->offsets);
67 build->offsets = isl_multi_aff_zero(isl_space_copy(space));
68 isl_multi_aff_free(build->values);
69 build->values = isl_multi_aff_identity(space);
71 if (!build->iterators || !build->domain || !build->generated ||
72 !build->pending || !build->values ||
73 !build->strides || !build->offsets || !build->options)
74 return isl_ast_build_free(build);
76 return build;
77 error:
78 isl_space_free(space);
79 return isl_ast_build_free(build);
82 /* Return an isl_id called "c%d", with "%d" set to "i".
83 * If an isl_id with such a name already appears among the parameters
84 * in build->domain, then adjust the name to "c%d_%d".
86 static __isl_give isl_id *generate_name(isl_ctx *ctx, int i,
87 __isl_keep isl_ast_build *build)
89 int j;
90 char name[16];
91 isl_set *dom = build->domain;
93 snprintf(name, sizeof(name), "c%d", i);
94 j = 0;
95 while (isl_set_find_dim_by_name(dom, isl_dim_param, name) >= 0)
96 snprintf(name, sizeof(name), "c%d_%d", i, j++);
97 return isl_id_alloc(ctx, name, NULL);
100 /* Create an isl_ast_build with "set" as domain.
102 * The input set is usually a parameter domain, but we currently allow it to
103 * be any kind of set. We set the domain of the returned isl_ast_build
104 * to "set" and initialize all the other fields to default values.
106 __isl_give isl_ast_build *isl_ast_build_from_context(__isl_take isl_set *set)
108 int i, n;
109 isl_ctx *ctx;
110 isl_space *space;
111 isl_ast_build *build;
113 set = isl_set_compute_divs(set);
114 if (!set)
115 return NULL;
117 ctx = isl_set_get_ctx(set);
119 build = isl_calloc_type(ctx, isl_ast_build);
120 if (!build)
121 goto error;
123 build->ref = 1;
124 build->domain = set;
125 build->generated = isl_set_copy(build->domain);
126 build->pending = isl_set_universe(isl_set_get_space(build->domain));
127 build->options = isl_union_map_empty(isl_space_params_alloc(ctx, 0));
128 n = isl_set_dim(set, isl_dim_set);
129 build->depth = n;
130 build->iterators = isl_id_list_alloc(ctx, n);
131 for (i = 0; i < n; ++i) {
132 isl_id *id;
133 if (isl_set_has_dim_id(set, isl_dim_set, i))
134 id = isl_set_get_dim_id(set, isl_dim_set, i);
135 else
136 id = generate_name(ctx, i, build);
137 build->iterators = isl_id_list_add(build->iterators, id);
139 space = isl_set_get_space(set);
140 if (isl_space_is_params(space))
141 space = isl_space_set_from_params(space);
143 return isl_ast_build_init_derived(build, space);
144 error:
145 isl_set_free(set);
146 return NULL;
149 /* Create an isl_ast_build with a universe (parametric) context.
151 __isl_give isl_ast_build *isl_ast_build_alloc(isl_ctx *ctx)
153 isl_space *space;
154 isl_set *context;
156 space = isl_space_params_alloc(ctx, 0);
157 context = isl_set_universe(space);
159 return isl_ast_build_from_context(context);
162 __isl_give isl_ast_build *isl_ast_build_copy(__isl_keep isl_ast_build *build)
164 if (!build)
165 return NULL;
167 build->ref++;
168 return build;
171 __isl_give isl_ast_build *isl_ast_build_dup(__isl_keep isl_ast_build *build)
173 isl_ctx *ctx;
174 isl_ast_build *dup;
176 if (!build)
177 return NULL;
179 ctx = isl_ast_build_get_ctx(build);
180 dup = isl_calloc_type(ctx, isl_ast_build);
181 if (!dup)
182 return NULL;
184 dup->ref = 1;
185 dup->outer_pos = build->outer_pos;
186 dup->depth = build->depth;
187 dup->iterators = isl_id_list_copy(build->iterators);
188 dup->domain = isl_set_copy(build->domain);
189 dup->generated = isl_set_copy(build->generated);
190 dup->pending = isl_set_copy(build->pending);
191 dup->values = isl_multi_aff_copy(build->values);
192 dup->value = isl_pw_aff_copy(build->value);
193 dup->strides = isl_vec_copy(build->strides);
194 dup->offsets = isl_multi_aff_copy(build->offsets);
195 dup->executed = isl_union_map_copy(build->executed);
196 dup->single_valued = build->single_valued;
197 dup->options = isl_union_map_copy(build->options);
198 dup->at_each_domain = build->at_each_domain;
199 dup->at_each_domain_user = build->at_each_domain_user;
200 dup->before_each_for = build->before_each_for;
201 dup->before_each_for_user = build->before_each_for_user;
202 dup->after_each_for = build->after_each_for;
203 dup->after_each_for_user = build->after_each_for_user;
204 dup->create_leaf = build->create_leaf;
205 dup->create_leaf_user = build->create_leaf_user;
206 dup->node = isl_schedule_node_copy(build->node);
208 if (!dup->iterators || !dup->domain || !dup->generated ||
209 !dup->pending || !dup->values ||
210 !dup->strides || !dup->offsets || !dup->options ||
211 (build->executed && !dup->executed) ||
212 (build->value && !dup->value) ||
213 (build->node && !dup->node))
214 return isl_ast_build_free(dup);
216 return dup;
219 /* Align the parameters of "build" to those of "model", introducing
220 * additional parameters if needed.
222 __isl_give isl_ast_build *isl_ast_build_align_params(
223 __isl_take isl_ast_build *build, __isl_take isl_space *model)
225 build = isl_ast_build_cow(build);
226 if (!build)
227 goto error;
229 build->domain = isl_set_align_params(build->domain,
230 isl_space_copy(model));
231 build->generated = isl_set_align_params(build->generated,
232 isl_space_copy(model));
233 build->pending = isl_set_align_params(build->pending,
234 isl_space_copy(model));
235 build->values = isl_multi_aff_align_params(build->values,
236 isl_space_copy(model));
237 build->offsets = isl_multi_aff_align_params(build->offsets,
238 isl_space_copy(model));
239 build->options = isl_union_map_align_params(build->options,
240 isl_space_copy(model));
241 isl_space_free(model);
243 if (!build->domain || !build->values || !build->offsets ||
244 !build->options)
245 return isl_ast_build_free(build);
247 return build;
248 error:
249 isl_space_free(model);
250 return NULL;
253 __isl_give isl_ast_build *isl_ast_build_cow(__isl_take isl_ast_build *build)
255 if (!build)
256 return NULL;
258 if (build->ref == 1)
259 return build;
260 build->ref--;
261 return isl_ast_build_dup(build);
264 __isl_null isl_ast_build *isl_ast_build_free(
265 __isl_take isl_ast_build *build)
267 if (!build)
268 return NULL;
270 if (--build->ref > 0)
271 return NULL;
273 isl_id_list_free(build->iterators);
274 isl_set_free(build->domain);
275 isl_set_free(build->generated);
276 isl_set_free(build->pending);
277 isl_multi_aff_free(build->values);
278 isl_pw_aff_free(build->value);
279 isl_vec_free(build->strides);
280 isl_multi_aff_free(build->offsets);
281 isl_multi_aff_free(build->schedule_map);
282 isl_union_map_free(build->executed);
283 isl_union_map_free(build->options);
284 isl_schedule_node_free(build->node);
286 free(build);
288 return NULL;
291 isl_ctx *isl_ast_build_get_ctx(__isl_keep isl_ast_build *build)
293 return build ? isl_set_get_ctx(build->domain) : NULL;
296 /* Replace build->options by "options".
298 __isl_give isl_ast_build *isl_ast_build_set_options(
299 __isl_take isl_ast_build *build, __isl_take isl_union_map *options)
301 build = isl_ast_build_cow(build);
303 if (!build || !options)
304 goto error;
306 isl_union_map_free(build->options);
307 build->options = options;
309 return build;
310 error:
311 isl_union_map_free(options);
312 return isl_ast_build_free(build);
315 /* Set the iterators for the next code generation.
317 * If we still have some iterators left from the previous code generation
318 * (if any) or if iterators have already been set by a previous
319 * call to this function, then we remove them first.
321 __isl_give isl_ast_build *isl_ast_build_set_iterators(
322 __isl_take isl_ast_build *build, __isl_take isl_id_list *iterators)
324 int dim, n_it;
326 build = isl_ast_build_cow(build);
327 if (!build)
328 goto error;
330 dim = isl_set_dim(build->domain, isl_dim_set);
331 n_it = isl_id_list_n_id(build->iterators);
332 if (n_it < dim)
333 isl_die(isl_ast_build_get_ctx(build), isl_error_internal,
334 "isl_ast_build in inconsistent state", goto error);
335 if (n_it > dim)
336 build->iterators = isl_id_list_drop(build->iterators,
337 dim, n_it - dim);
338 build->iterators = isl_id_list_concat(build->iterators, iterators);
339 if (!build->iterators)
340 return isl_ast_build_free(build);
342 return build;
343 error:
344 isl_id_list_free(iterators);
345 return isl_ast_build_free(build);
348 /* Set the "at_each_domain" callback of "build" to "fn".
350 __isl_give isl_ast_build *isl_ast_build_set_at_each_domain(
351 __isl_take isl_ast_build *build,
352 __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
353 __isl_keep isl_ast_build *build, void *user), void *user)
355 build = isl_ast_build_cow(build);
357 if (!build)
358 return NULL;
360 build->at_each_domain = fn;
361 build->at_each_domain_user = user;
363 return build;
366 /* Set the "before_each_for" callback of "build" to "fn".
368 __isl_give isl_ast_build *isl_ast_build_set_before_each_for(
369 __isl_take isl_ast_build *build,
370 __isl_give isl_id *(*fn)(__isl_keep isl_ast_build *build,
371 void *user), void *user)
373 build = isl_ast_build_cow(build);
375 if (!build)
376 return NULL;
378 build->before_each_for = fn;
379 build->before_each_for_user = user;
381 return build;
384 /* Set the "after_each_for" callback of "build" to "fn".
386 __isl_give isl_ast_build *isl_ast_build_set_after_each_for(
387 __isl_take isl_ast_build *build,
388 __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_node *node,
389 __isl_keep isl_ast_build *build, void *user), void *user)
391 build = isl_ast_build_cow(build);
393 if (!build)
394 return NULL;
396 build->after_each_for = fn;
397 build->after_each_for_user = user;
399 return build;
402 /* Set the "create_leaf" callback of "build" to "fn".
404 __isl_give isl_ast_build *isl_ast_build_set_create_leaf(
405 __isl_take isl_ast_build *build,
406 __isl_give isl_ast_node *(*fn)(__isl_take isl_ast_build *build,
407 void *user), void *user)
409 build = isl_ast_build_cow(build);
411 if (!build)
412 return NULL;
414 build->create_leaf = fn;
415 build->create_leaf_user = user;
417 return build;
420 /* Clear all information that is specific to this code generation
421 * and that is (probably) not meaningful to any nested code generation.
423 __isl_give isl_ast_build *isl_ast_build_clear_local_info(
424 __isl_take isl_ast_build *build)
426 isl_space *space;
428 build = isl_ast_build_cow(build);
429 if (!build)
430 return NULL;
432 space = isl_union_map_get_space(build->options);
433 isl_union_map_free(build->options);
434 build->options = isl_union_map_empty(space);
436 build->at_each_domain = NULL;
437 build->at_each_domain_user = NULL;
438 build->before_each_for = NULL;
439 build->before_each_for_user = NULL;
440 build->after_each_for = NULL;
441 build->after_each_for_user = NULL;
442 build->create_leaf = NULL;
443 build->create_leaf_user = NULL;
445 if (!build->options)
446 return isl_ast_build_free(build);
448 return build;
451 /* Have any loops been eliminated?
452 * That is, do any of the original schedule dimensions have a fixed
453 * value that has been substituted?
455 static int any_eliminated(isl_ast_build *build)
457 int i;
459 for (i = 0; i < build->depth; ++i)
460 if (isl_ast_build_has_affine_value(build, i))
461 return 1;
463 return 0;
466 /* Clear build->schedule_map.
467 * This function should be called whenever anything that might affect
468 * the result of isl_ast_build_get_schedule_map_multi_aff changes.
469 * In particular, it should be called when the depth is changed or
470 * when an iterator is determined to have a fixed value.
472 static void isl_ast_build_reset_schedule_map(__isl_keep isl_ast_build *build)
474 if (!build)
475 return;
476 isl_multi_aff_free(build->schedule_map);
477 build->schedule_map = NULL;
480 /* Do we need a (non-trivial) schedule map?
481 * That is, is the internal schedule space different from
482 * the external schedule space?
484 * The internal and external schedule spaces are only the same
485 * if code has been generated for the entire schedule and if none
486 * of the loops have been eliminated.
488 __isl_give int isl_ast_build_need_schedule_map(__isl_keep isl_ast_build *build)
490 int dim;
492 if (!build)
493 return -1;
495 dim = isl_set_dim(build->domain, isl_dim_set);
496 return build->depth != dim || any_eliminated(build);
499 /* Return a mapping from the internal schedule space to the external
500 * schedule space in the form of an isl_multi_aff.
501 * The internal schedule space originally corresponds to that of the
502 * input schedule. This may change during the code generation if
503 * if isl_ast_build_insert_dim is ever called.
504 * The external schedule space corresponds to the
505 * loops that have been generated.
507 * Currently, the only difference between the internal schedule domain
508 * and the external schedule domain is that some dimensions are projected
509 * out in the external schedule domain. In particular, the dimensions
510 * for which no code has been generated yet and the dimensions that correspond
511 * to eliminated loops.
513 * We cache a copy of the schedule_map in build->schedule_map.
514 * The cache is cleared through isl_ast_build_reset_schedule_map
515 * whenever anything changes that might affect the result of this function.
517 __isl_give isl_multi_aff *isl_ast_build_get_schedule_map_multi_aff(
518 __isl_keep isl_ast_build *build)
520 isl_space *space;
521 isl_multi_aff *ma;
523 if (!build)
524 return NULL;
525 if (build->schedule_map)
526 return isl_multi_aff_copy(build->schedule_map);
528 space = isl_ast_build_get_space(build, 1);
529 space = isl_space_map_from_set(space);
530 ma = isl_multi_aff_identity(space);
531 if (isl_ast_build_need_schedule_map(build)) {
532 int i;
533 int dim = isl_set_dim(build->domain, isl_dim_set);
534 ma = isl_multi_aff_drop_dims(ma, isl_dim_out,
535 build->depth, dim - build->depth);
536 for (i = build->depth - 1; i >= 0; --i)
537 if (isl_ast_build_has_affine_value(build, i))
538 ma = isl_multi_aff_drop_dims(ma,
539 isl_dim_out, i, 1);
542 build->schedule_map = ma;
543 return isl_multi_aff_copy(build->schedule_map);
546 /* Return a mapping from the internal schedule space to the external
547 * schedule space in the form of an isl_map.
549 __isl_give isl_map *isl_ast_build_get_schedule_map(
550 __isl_keep isl_ast_build *build)
552 isl_multi_aff *ma;
554 ma = isl_ast_build_get_schedule_map_multi_aff(build);
555 return isl_map_from_multi_aff(ma);
558 /* Return the position of the dimension in build->domain for which
559 * an AST node is currently being generated.
561 int isl_ast_build_get_depth(__isl_keep isl_ast_build *build)
563 return build ? build->depth : -1;
566 /* Prepare for generating code for the next level.
567 * In particular, increase the depth and reset any information
568 * that is local to the current depth.
570 __isl_give isl_ast_build *isl_ast_build_increase_depth(
571 __isl_take isl_ast_build *build)
573 build = isl_ast_build_cow(build);
574 if (!build)
575 return NULL;
576 build->depth++;
577 isl_ast_build_reset_schedule_map(build);
578 build->value = isl_pw_aff_free(build->value);
579 return build;
582 void isl_ast_build_dump(__isl_keep isl_ast_build *build)
584 if (!build)
585 return;
587 fprintf(stderr, "domain: ");
588 isl_set_dump(build->domain);
589 fprintf(stderr, "generated: ");
590 isl_set_dump(build->generated);
591 fprintf(stderr, "pending: ");
592 isl_set_dump(build->pending);
593 fprintf(stderr, "iterators: ");
594 isl_id_list_dump(build->iterators);
595 fprintf(stderr, "values: ");
596 isl_multi_aff_dump(build->values);
597 if (build->value) {
598 fprintf(stderr, "value: ");
599 isl_pw_aff_dump(build->value);
601 fprintf(stderr, "strides: ");
602 isl_vec_dump(build->strides);
603 fprintf(stderr, "offsets: ");
604 isl_multi_aff_dump(build->offsets);
607 /* Initialize "build" for AST construction in schedule space "space"
608 * in the case that build->domain is a parameter set.
610 * build->iterators is assumed to have been updated already.
612 static __isl_give isl_ast_build *isl_ast_build_init(
613 __isl_take isl_ast_build *build, __isl_take isl_space *space)
615 isl_set *set;
617 build = isl_ast_build_cow(build);
618 if (!build)
619 goto error;
621 set = isl_set_universe(isl_space_copy(space));
622 build->domain = isl_set_intersect_params(isl_set_copy(set),
623 build->domain);
624 build->pending = isl_set_intersect_params(isl_set_copy(set),
625 build->pending);
626 build->generated = isl_set_intersect_params(set, build->generated);
628 return isl_ast_build_init_derived(build, space);
629 error:
630 isl_ast_build_free(build);
631 isl_space_free(space);
632 return NULL;
635 /* Assign "aff" to *user and return -1, effectively extracting
636 * the first (and presumably only) affine expression in the isl_pw_aff
637 * on which this function is used.
639 static int extract_single_piece(__isl_take isl_set *set,
640 __isl_take isl_aff *aff, void *user)
642 isl_aff **p = user;
644 *p = aff;
645 isl_set_free(set);
647 return -1;
650 /* Intersect "set" with the stride constraint of "build", if any.
652 static __isl_give isl_set *intersect_stride_constraint(__isl_take isl_set *set,
653 __isl_keep isl_ast_build *build)
655 isl_set *stride;
657 if (!build)
658 return isl_set_free(set);
659 if (!isl_ast_build_has_stride(build, build->depth))
660 return set;
662 stride = isl_ast_build_get_stride_constraint(build);
663 return isl_set_intersect(set, stride);
666 /* Check if the given bounds on the current dimension (together with
667 * the stride constraint, if any) imply that
668 * this current dimension attains only a single value (in terms of
669 * parameters and outer dimensions).
670 * If so, we record it in build->value.
671 * If, moreover, this value can be represented as a single affine expression,
672 * then we also update build->values, effectively marking the current
673 * dimension as "eliminated".
675 * When computing the gist of the fixed value that can be represented
676 * as a single affine expression, it is important to only take into
677 * account the domain constraints in the original AST build and
678 * not the domain of the affine expression itself.
679 * Otherwise, a [i/3] is changed into a i/3 because we know that i
680 * is a multiple of 3, but then we end up not expressing anywhere
681 * in the context that i is a multiple of 3.
683 static __isl_give isl_ast_build *update_values(
684 __isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds)
686 int sv;
687 isl_pw_multi_aff *pma;
688 isl_aff *aff = NULL;
689 isl_map *it_map;
690 isl_set *set;
692 set = isl_set_from_basic_set(bounds);
693 set = isl_set_intersect(set, isl_set_copy(build->domain));
694 set = intersect_stride_constraint(set, build);
695 it_map = isl_ast_build_map_to_iterator(build, set);
697 sv = isl_map_is_single_valued(it_map);
698 if (sv < 0)
699 build = isl_ast_build_free(build);
700 if (!build || !sv) {
701 isl_map_free(it_map);
702 return build;
705 pma = isl_pw_multi_aff_from_map(it_map);
706 build->value = isl_pw_multi_aff_get_pw_aff(pma, 0);
707 build->value = isl_ast_build_compute_gist_pw_aff(build, build->value);
708 build->value = isl_pw_aff_coalesce(build->value);
709 isl_pw_multi_aff_free(pma);
711 if (!build->value)
712 return isl_ast_build_free(build);
714 if (isl_pw_aff_n_piece(build->value) != 1)
715 return build;
717 isl_pw_aff_foreach_piece(build->value, &extract_single_piece, &aff);
719 build->values = isl_multi_aff_set_aff(build->values, build->depth, aff);
720 if (!build->values)
721 return isl_ast_build_free(build);
722 isl_ast_build_reset_schedule_map(build);
723 return build;
726 /* Update the AST build based on the given loop bounds for
727 * the current dimension and the stride information available in the build.
729 * We first make sure that the bounds do not refer to any iterators
730 * that have already been eliminated.
731 * Then, we check if the bounds imply that the current iterator
732 * has a fixed value.
733 * If they do and if this fixed value can be expressed as a single
734 * affine expression, we eliminate the iterators from the bounds.
735 * Note that we cannot simply plug in this single value using
736 * isl_basic_set_preimage_multi_aff as the single value may only
737 * be defined on a subset of the domain. Plugging in the value
738 * would restrict the build domain to this subset, while this
739 * restriction may not be reflected in the generated code.
740 * Finally, we intersect build->domain with the updated bounds.
741 * We also add the stride constraint unless we have been able
742 * to find a fixed value expressed as a single affine expression.
744 * Note that the check for a fixed value in update_values requires
745 * us to intersect the bounds with the current build domain.
746 * When we intersect build->domain with the updated bounds in
747 * the final step, we make sure that these updated bounds have
748 * not been intersected with the old build->domain.
749 * Otherwise, we would indirectly intersect the build domain with itself,
750 * which can lead to inefficiencies, in particular if the build domain
751 * contains any unknown divs.
753 __isl_give isl_ast_build *isl_ast_build_set_loop_bounds(
754 __isl_take isl_ast_build *build, __isl_take isl_basic_set *bounds)
756 isl_set *set;
758 build = isl_ast_build_cow(build);
759 if (!build)
760 goto error;
762 bounds = isl_basic_set_preimage_multi_aff(bounds,
763 isl_multi_aff_copy(build->values));
764 build = update_values(build, isl_basic_set_copy(bounds));
765 if (!build)
766 goto error;
767 set = isl_set_from_basic_set(isl_basic_set_copy(bounds));
768 if (isl_ast_build_has_affine_value(build, build->depth)) {
769 set = isl_set_eliminate(set, isl_dim_set, build->depth, 1);
770 set = isl_set_compute_divs(set);
771 build->pending = isl_set_intersect(build->pending,
772 isl_set_copy(set));
773 build->domain = isl_set_intersect(build->domain, set);
774 } else {
775 isl_basic_set *generated, *pending;
777 pending = isl_basic_set_copy(bounds);
778 pending = isl_basic_set_drop_constraints_involving_dims(pending,
779 isl_dim_set, build->depth, 1);
780 build->pending = isl_set_intersect(build->pending,
781 isl_set_from_basic_set(pending));
782 generated = isl_basic_set_copy(bounds);
783 generated = isl_basic_set_drop_constraints_not_involving_dims(
784 generated, isl_dim_set, build->depth, 1);
785 build->generated = isl_set_intersect(build->generated,
786 isl_set_from_basic_set(generated));
787 build->domain = isl_set_intersect(build->domain, set);
788 build = isl_ast_build_include_stride(build);
789 if (!build)
790 goto error;
792 isl_basic_set_free(bounds);
794 if (!build->domain || !build->pending || !build->generated)
795 return isl_ast_build_free(build);
797 return build;
798 error:
799 isl_ast_build_free(build);
800 isl_basic_set_free(bounds);
801 return NULL;
804 /* Intersect build->domain with "set", where "set" is specified
805 * in terms of the internal schedule domain.
807 static __isl_give isl_ast_build *isl_ast_build_restrict_internal(
808 __isl_take isl_ast_build *build, __isl_take isl_set *set)
810 build = isl_ast_build_cow(build);
811 if (!build)
812 goto error;
814 set = isl_set_compute_divs(set);
815 build->domain = isl_set_intersect(build->domain, set);
816 build->domain = isl_set_coalesce(build->domain);
818 if (!build->domain)
819 return isl_ast_build_free(build);
821 return build;
822 error:
823 isl_ast_build_free(build);
824 isl_set_free(set);
825 return NULL;
828 /* Intersect build->generated and build->domain with "set",
829 * where "set" is specified in terms of the internal schedule domain.
831 __isl_give isl_ast_build *isl_ast_build_restrict_generated(
832 __isl_take isl_ast_build *build, __isl_take isl_set *set)
834 set = isl_set_compute_divs(set);
835 build = isl_ast_build_restrict_internal(build, isl_set_copy(set));
836 build = isl_ast_build_cow(build);
837 if (!build)
838 goto error;
840 build->generated = isl_set_intersect(build->generated, set);
841 build->generated = isl_set_coalesce(build->generated);
843 if (!build->generated)
844 return isl_ast_build_free(build);
846 return build;
847 error:
848 isl_ast_build_free(build);
849 isl_set_free(set);
850 return NULL;
853 /* Replace the set of pending constraints by "guard", which is then
854 * no longer considered as pending.
855 * That is, add "guard" to the generated constraints and clear all pending
856 * constraints, making the domain equal to the generated constraints.
858 __isl_give isl_ast_build *isl_ast_build_replace_pending_by_guard(
859 __isl_take isl_ast_build *build, __isl_take isl_set *guard)
861 build = isl_ast_build_restrict_generated(build, guard);
862 build = isl_ast_build_cow(build);
863 if (!build)
864 return NULL;
866 isl_set_free(build->domain);
867 build->domain = isl_set_copy(build->generated);
868 isl_set_free(build->pending);
869 build->pending = isl_set_universe(isl_set_get_space(build->domain));
871 if (!build->pending)
872 return isl_ast_build_free(build);
874 return build;
877 /* Intersect build->pending and build->domain with "set",
878 * where "set" is specified in terms of the internal schedule domain.
880 __isl_give isl_ast_build *isl_ast_build_restrict_pending(
881 __isl_take isl_ast_build *build, __isl_take isl_set *set)
883 set = isl_set_compute_divs(set);
884 build = isl_ast_build_restrict_internal(build, isl_set_copy(set));
885 build = isl_ast_build_cow(build);
886 if (!build)
887 goto error;
889 build->pending = isl_set_intersect(build->pending, set);
890 build->pending = isl_set_coalesce(build->pending);
892 if (!build->pending)
893 return isl_ast_build_free(build);
895 return build;
896 error:
897 isl_ast_build_free(build);
898 isl_set_free(set);
899 return NULL;
902 /* Intersect build->domain with "set", where "set" is specified
903 * in terms of the external schedule domain.
905 __isl_give isl_ast_build *isl_ast_build_restrict(
906 __isl_take isl_ast_build *build, __isl_take isl_set *set)
908 if (isl_set_is_params(set))
909 return isl_ast_build_restrict_generated(build, set);
911 if (isl_ast_build_need_schedule_map(build)) {
912 isl_multi_aff *ma;
913 ma = isl_ast_build_get_schedule_map_multi_aff(build);
914 set = isl_set_preimage_multi_aff(set, ma);
916 return isl_ast_build_restrict_generated(build, set);
919 /* Replace build->executed by "executed".
921 __isl_give isl_ast_build *isl_ast_build_set_executed(
922 __isl_take isl_ast_build *build, __isl_take isl_union_map *executed)
924 build = isl_ast_build_cow(build);
925 if (!build)
926 goto error;
928 isl_union_map_free(build->executed);
929 build->executed = executed;
931 return build;
932 error:
933 isl_ast_build_free(build);
934 isl_union_map_free(executed);
935 return NULL;
938 /* Does "build" point to a band node?
939 * That is, are we currently handling a band node inside a schedule tree?
941 int isl_ast_build_has_schedule_node(__isl_keep isl_ast_build *build)
943 if (!build)
944 return -1;
945 return build->node != NULL;
948 /* Return a copy of the band node that "build" refers to.
950 __isl_give isl_schedule_node *isl_ast_build_get_schedule_node(
951 __isl_keep isl_ast_build *build)
953 if (!build)
954 return NULL;
955 return isl_schedule_node_copy(build->node);
958 /* Replace the band node that "build" refers to by "node".
960 __isl_give isl_ast_build *isl_ast_build_set_schedule_node(
961 __isl_take isl_ast_build *build,
962 __isl_take isl_schedule_node *node)
964 build = isl_ast_build_cow(build);
965 if (!build || !node)
966 goto error;
968 isl_schedule_node_free(build->node);
969 build->node = node;
971 return build;
972 error:
973 isl_ast_build_free(build);
974 isl_schedule_node_free(node);
975 return NULL;
978 /* Remove any reference to a band node from "build".
980 __isl_give isl_ast_build *isl_ast_build_reset_schedule_node(
981 __isl_take isl_ast_build *build)
983 build = isl_ast_build_cow(build);
984 if (!build)
985 return NULL;
987 isl_schedule_node_free(build->node);
988 build->node = NULL;
990 return build;
993 /* Return a copy of the current schedule domain.
995 __isl_give isl_set *isl_ast_build_get_domain(__isl_keep isl_ast_build *build)
997 return build ? isl_set_copy(build->domain) : NULL;
1000 /* Return a copy of the set of pending constraints.
1002 __isl_give isl_set *isl_ast_build_get_pending(
1003 __isl_keep isl_ast_build *build)
1005 return build ? isl_set_copy(build->pending) : NULL;
1008 /* Return a copy of the set of generated constraints.
1010 __isl_give isl_set *isl_ast_build_get_generated(
1011 __isl_keep isl_ast_build *build)
1013 return build ? isl_set_copy(build->generated) : NULL;
1016 /* Return the number of variables of the given type
1017 * in the (internal) schedule space.
1019 unsigned isl_ast_build_dim(__isl_keep isl_ast_build *build,
1020 enum isl_dim_type type)
1022 if (!build)
1023 return 0;
1024 return isl_set_dim(build->domain, type);
1027 /* Return the (schedule) space of "build".
1029 * If "internal" is set, then this space is the space of the internal
1030 * representation of the entire schedule, including those parts for
1031 * which no code has been generated yet.
1033 * If "internal" is not set, then this space is the external representation
1034 * of the loops generated so far.
1036 __isl_give isl_space *isl_ast_build_get_space(__isl_keep isl_ast_build *build,
1037 int internal)
1039 int i;
1040 int dim;
1041 isl_space *space;
1043 if (!build)
1044 return NULL;
1046 space = isl_set_get_space(build->domain);
1047 if (internal)
1048 return space;
1050 if (!isl_ast_build_need_schedule_map(build))
1051 return space;
1053 dim = isl_set_dim(build->domain, isl_dim_set);
1054 space = isl_space_drop_dims(space, isl_dim_set,
1055 build->depth, dim - build->depth);
1056 for (i = build->depth - 1; i >= 0; --i)
1057 if (isl_ast_build_has_affine_value(build, i))
1058 space = isl_space_drop_dims(space, isl_dim_set, i, 1);
1060 return space;
1063 /* Return the external representation of the schedule space of "build",
1064 * i.e., a space with a dimension for each loop generated so far,
1065 * with the names of the dimensions set to the loop iterators.
1067 __isl_give isl_space *isl_ast_build_get_schedule_space(
1068 __isl_keep isl_ast_build *build)
1070 isl_space *space;
1071 int i, skip;
1073 if (!build)
1074 return NULL;
1076 space = isl_ast_build_get_space(build, 0);
1078 skip = 0;
1079 for (i = 0; i < build->depth; ++i) {
1080 isl_id *id;
1082 if (isl_ast_build_has_affine_value(build, i)) {
1083 skip++;
1084 continue;
1087 id = isl_ast_build_get_iterator_id(build, i);
1088 space = isl_space_set_dim_id(space, isl_dim_set, i - skip, id);
1091 return space;
1094 /* Return the current schedule, as stored in build->executed, in terms
1095 * of the external schedule domain.
1097 __isl_give isl_union_map *isl_ast_build_get_schedule(
1098 __isl_keep isl_ast_build *build)
1100 isl_union_map *executed;
1101 isl_union_map *schedule;
1103 if (!build)
1104 return NULL;
1106 executed = isl_union_map_copy(build->executed);
1107 if (isl_ast_build_need_schedule_map(build)) {
1108 isl_map *proj = isl_ast_build_get_schedule_map(build);
1109 executed = isl_union_map_apply_domain(executed,
1110 isl_union_map_from_map(proj));
1112 schedule = isl_union_map_reverse(executed);
1114 return schedule;
1117 /* Return the iterator attached to the internal schedule dimension "pos".
1119 __isl_give isl_id *isl_ast_build_get_iterator_id(
1120 __isl_keep isl_ast_build *build, int pos)
1122 if (!build)
1123 return NULL;
1125 return isl_id_list_get_id(build->iterators, pos);
1128 /* Set the stride and offset of the current dimension to the given
1129 * value and expression.
1131 * If we had already found a stride before, then the two strides
1132 * are combined into a single stride.
1134 * In particular, if the new stride information is of the form
1136 * i = f + s (...)
1138 * and the old stride information is of the form
1140 * i = f2 + s2 (...)
1142 * then we compute the extended gcd of s and s2
1144 * a s + b s2 = g,
1146 * with g = gcd(s,s2), multiply the first equation with t1 = b s2/g
1147 * and the second with t2 = a s1/g.
1148 * This results in
1150 * i = (b s2 + a s1)/g i = t1 f + t2 f2 + (s s2)/g (...)
1152 * so that t1 f + t2 f2 is the combined offset and (s s2)/g = lcm(s,s2)
1153 * is the combined stride.
1155 static __isl_give isl_ast_build *set_stride(__isl_take isl_ast_build *build,
1156 __isl_take isl_val *stride, __isl_take isl_aff *offset)
1158 int pos;
1160 build = isl_ast_build_cow(build);
1161 if (!build || !stride || !offset)
1162 goto error;
1164 pos = build->depth;
1166 if (isl_ast_build_has_stride(build, pos)) {
1167 isl_val *stride2, *a, *b, *g;
1168 isl_aff *offset2;
1170 stride2 = isl_vec_get_element_val(build->strides, pos);
1171 g = isl_val_gcdext(isl_val_copy(stride), isl_val_copy(stride2),
1172 &a, &b);
1173 a = isl_val_mul(a, isl_val_copy(stride));
1174 a = isl_val_div(a, isl_val_copy(g));
1175 stride2 = isl_val_div(stride2, g);
1176 b = isl_val_mul(b, isl_val_copy(stride2));
1177 stride = isl_val_mul(stride, stride2);
1179 offset2 = isl_multi_aff_get_aff(build->offsets, pos);
1180 offset2 = isl_aff_scale_val(offset2, a);
1181 offset = isl_aff_scale_val(offset, b);
1182 offset = isl_aff_add(offset, offset2);
1185 build->strides = isl_vec_set_element_val(build->strides, pos, stride);
1186 build->offsets = isl_multi_aff_set_aff(build->offsets, pos, offset);
1187 if (!build->strides || !build->offsets)
1188 return isl_ast_build_free(build);
1190 return build;
1191 error:
1192 isl_val_free(stride);
1193 isl_aff_free(offset);
1194 return isl_ast_build_free(build);
1197 /* Return a set expressing the stride constraint at the current depth.
1199 * In particular, if the current iterator (i) is known to attain values
1201 * f + s a
1203 * where f is the offset and s is the stride, then the returned set
1204 * expresses the constraint
1206 * (f - i) mod s = 0
1208 __isl_give isl_set *isl_ast_build_get_stride_constraint(
1209 __isl_keep isl_ast_build *build)
1211 isl_aff *aff;
1212 isl_set *set;
1213 isl_val *stride;
1214 int pos;
1216 if (!build)
1217 return NULL;
1219 pos = build->depth;
1221 if (!isl_ast_build_has_stride(build, pos))
1222 return isl_set_universe(isl_ast_build_get_space(build, 1));
1224 stride = isl_ast_build_get_stride(build, pos);
1225 aff = isl_ast_build_get_offset(build, pos);
1226 aff = isl_aff_add_coefficient_si(aff, isl_dim_in, pos, -1);
1227 aff = isl_aff_mod_val(aff, stride);
1228 set = isl_set_from_basic_set(isl_aff_zero_basic_set(aff));
1230 return set;
1233 /* Return the expansion implied by the stride and offset at the current
1234 * depth.
1236 * That is, return the mapping
1238 * [i_0, ..., i_{d-1}, i_d, i_{d+1}, ...]
1239 * -> [i_0, ..., i_{d-1}, s * i_d + offset(i), i_{d+1}, ...]
1241 * where s is the stride at the current depth d and offset(i) is
1242 * the corresponding offset.
1244 __isl_give isl_multi_aff *isl_ast_build_get_stride_expansion(
1245 __isl_keep isl_ast_build *build)
1247 isl_space *space;
1248 isl_multi_aff *ma;
1249 int pos;
1250 isl_aff *aff, *offset;
1251 isl_val *stride;
1253 if (!build)
1254 return NULL;
1256 pos = isl_ast_build_get_depth(build);
1257 space = isl_ast_build_get_space(build, 1);
1258 space = isl_space_map_from_set(space);
1259 ma = isl_multi_aff_identity(space);
1261 if (!isl_ast_build_has_stride(build, pos))
1262 return ma;
1264 offset = isl_ast_build_get_offset(build, pos);
1265 stride = isl_ast_build_get_stride(build, pos);
1266 aff = isl_multi_aff_get_aff(ma, pos);
1267 aff = isl_aff_scale_val(aff, stride);
1268 aff = isl_aff_add(aff, offset);
1269 ma = isl_multi_aff_set_aff(ma, pos, aff);
1271 return ma;
1274 /* Add constraints corresponding to any previously detected
1275 * stride on the current dimension to build->domain.
1277 __isl_give isl_ast_build *isl_ast_build_include_stride(
1278 __isl_take isl_ast_build *build)
1280 isl_set *set;
1282 if (!build)
1283 return NULL;
1284 if (!isl_ast_build_has_stride(build, build->depth))
1285 return build;
1286 build = isl_ast_build_cow(build);
1287 if (!build)
1288 return NULL;
1290 set = isl_ast_build_get_stride_constraint(build);
1292 build->domain = isl_set_intersect(build->domain, isl_set_copy(set));
1293 build->generated = isl_set_intersect(build->generated, set);
1294 if (!build->domain || !build->generated)
1295 return isl_ast_build_free(build);
1297 return build;
1300 /* Information used inside detect_stride.
1302 * "build" may be updated by detect_stride to include stride information.
1303 * "pos" is equal to build->depth.
1305 struct isl_detect_stride_data {
1306 isl_ast_build *build;
1307 int pos;
1310 /* Check if constraint "c" imposes any stride on dimension data->pos
1311 * and, if so, update the stride information in data->build.
1313 * In order to impose a stride on the dimension, "c" needs to be an equality
1314 * and it needs to involve the dimension. Note that "c" may also be
1315 * a div constraint and thus an inequality that we cannot use.
1317 * Let c be of the form
1319 * h(p) + g * v * i + g * stride * f(alpha) = 0
1321 * with h(p) an expression in terms of the parameters and outer dimensions
1322 * and f(alpha) an expression in terms of the existentially quantified
1323 * variables. Note that the inner dimensions have been eliminated so
1324 * they do not appear in "c".
1326 * If "stride" is not zero and not one, then it represents a non-trivial stride
1327 * on "i". We compute a and b such that
1329 * a v + b stride = 1
1331 * We have
1333 * g v i = -h(p) + g stride f(alpha)
1335 * a g v i = -a h(p) + g stride f(alpha)
1337 * a g v i + b g stride i = -a h(p) + g stride * (...)
1339 * g i = -a h(p) + g stride * (...)
1341 * i = -a h(p)/g + stride * (...)
1343 * The expression "-a h(p)/g" can therefore be used as offset.
1345 static int detect_stride(__isl_take isl_constraint *c, void *user)
1347 struct isl_detect_stride_data *data = user;
1348 int i, n_div;
1349 isl_ctx *ctx;
1350 isl_val *v, *stride, *m;
1352 if (!isl_constraint_is_equality(c) ||
1353 !isl_constraint_involves_dims(c, isl_dim_set, data->pos, 1)) {
1354 isl_constraint_free(c);
1355 return 0;
1358 ctx = isl_constraint_get_ctx(c);
1359 stride = isl_val_zero(ctx);
1360 n_div = isl_constraint_dim(c, isl_dim_div);
1361 for (i = 0; i < n_div; ++i) {
1362 v = isl_constraint_get_coefficient_val(c, isl_dim_div, i);
1363 stride = isl_val_gcd(stride, v);
1366 v = isl_constraint_get_coefficient_val(c, isl_dim_set, data->pos);
1367 m = isl_val_gcd(isl_val_copy(stride), isl_val_copy(v));
1368 stride = isl_val_div(stride, isl_val_copy(m));
1369 v = isl_val_div(v, isl_val_copy(m));
1371 if (!isl_val_is_zero(stride) && !isl_val_is_one(stride)) {
1372 isl_aff *aff;
1373 isl_val *gcd, *a, *b;
1375 gcd = isl_val_gcdext(v, isl_val_copy(stride), &a, &b);
1376 isl_val_free(gcd);
1377 isl_val_free(b);
1379 aff = isl_constraint_get_aff(c);
1380 for (i = 0; i < n_div; ++i)
1381 aff = isl_aff_set_coefficient_si(aff,
1382 isl_dim_div, i, 0);
1383 aff = isl_aff_set_coefficient_si(aff, isl_dim_in, data->pos, 0);
1384 a = isl_val_neg(a);
1385 aff = isl_aff_scale_val(aff, a);
1386 aff = isl_aff_scale_down_val(aff, m);
1387 data->build = set_stride(data->build, stride, aff);
1388 } else {
1389 isl_val_free(stride);
1390 isl_val_free(m);
1391 isl_val_free(v);
1394 isl_constraint_free(c);
1395 return 0;
1398 /* Check if the constraints in "set" imply any stride on the current
1399 * dimension and, if so, record the stride information in "build"
1400 * and return the updated "build".
1402 * We compute the affine hull and then check if any of the constraints
1403 * in the hull imposes any stride on the current dimension.
1405 * We assume that inner dimensions have been eliminated from "set"
1406 * by the caller. This is needed because the common stride
1407 * may be imposed by different inner dimensions on different parts of
1408 * the domain.
1410 __isl_give isl_ast_build *isl_ast_build_detect_strides(
1411 __isl_take isl_ast_build *build, __isl_take isl_set *set)
1413 isl_basic_set *hull;
1414 struct isl_detect_stride_data data;
1416 if (!build)
1417 goto error;
1419 data.build = build;
1420 data.pos = isl_ast_build_get_depth(build);
1421 hull = isl_set_affine_hull(set);
1423 if (isl_basic_set_foreach_constraint(hull, &detect_stride, &data) < 0)
1424 data.build = isl_ast_build_free(data.build);
1426 isl_basic_set_free(hull);
1427 return data.build;
1428 error:
1429 isl_set_free(set);
1430 return NULL;
1433 struct isl_ast_build_involves_data {
1434 int depth;
1435 int involves;
1438 /* Check if "map" involves the input dimension data->depth.
1440 static int involves_depth(__isl_take isl_map *map, void *user)
1442 struct isl_ast_build_involves_data *data = user;
1444 data->involves = isl_map_involves_dims(map, isl_dim_in, data->depth, 1);
1445 isl_map_free(map);
1447 if (data->involves < 0 || data->involves)
1448 return -1;
1449 return 0;
1452 /* Do any options depend on the value of the dimension at the current depth?
1454 int isl_ast_build_options_involve_depth(__isl_keep isl_ast_build *build)
1456 struct isl_ast_build_involves_data data;
1458 if (!build)
1459 return -1;
1461 data.depth = build->depth;
1462 data.involves = 0;
1464 if (isl_union_map_foreach_map(build->options,
1465 &involves_depth, &data) < 0) {
1466 if (data.involves < 0 || !data.involves)
1467 return -1;
1470 return data.involves;
1473 /* Construct the map
1475 * { [i] -> [i] : i < pos; [i] -> [i + 1] : i >= pos }
1477 * with "space" the parameter space of the constructed map.
1479 static __isl_give isl_map *construct_insertion_map(__isl_take isl_space *space,
1480 int pos)
1482 isl_constraint *c;
1483 isl_basic_map *bmap1, *bmap2;
1485 space = isl_space_set_from_params(space);
1486 space = isl_space_add_dims(space, isl_dim_set, 1);
1487 space = isl_space_map_from_set(space);
1488 c = isl_equality_alloc(isl_local_space_from_space(space));
1489 c = isl_constraint_set_coefficient_si(c, isl_dim_in, 0, 1);
1490 c = isl_constraint_set_coefficient_si(c, isl_dim_out, 0, -1);
1491 bmap1 = isl_basic_map_from_constraint(isl_constraint_copy(c));
1492 c = isl_constraint_set_constant_si(c, 1);
1493 bmap2 = isl_basic_map_from_constraint(c);
1495 bmap1 = isl_basic_map_upper_bound_si(bmap1, isl_dim_in, 0, pos - 1);
1496 bmap2 = isl_basic_map_lower_bound_si(bmap2, isl_dim_in, 0, pos);
1498 return isl_basic_map_union(bmap1, bmap2);
1501 static const char *option_str[] = {
1502 [isl_ast_loop_atomic] = "atomic",
1503 [isl_ast_loop_unroll] = "unroll",
1504 [isl_ast_loop_separate] = "separate"
1507 /* Update the "options" to reflect the insertion of a dimension
1508 * at position "pos" in the schedule domain space.
1509 * "space" is the original domain space before the insertion and
1510 * may be named and/or structured.
1512 * The (relevant) input options all have "space" as domain, which
1513 * has to be mapped to the extended space.
1514 * The values of the ranges also refer to the schedule domain positions
1515 * and they therefore also need to be adjusted. In particular, values
1516 * smaller than pos do not need to change, while values greater than or
1517 * equal to pos need to be incremented.
1518 * That is, we need to apply the following map.
1520 * { atomic[i] -> atomic[i] : i < pos; [i] -> [i + 1] : i >= pos;
1521 * unroll[i] -> unroll[i] : i < pos; [i] -> [i + 1] : i >= pos;
1522 * separate[i] -> separate[i] : i < pos; [i] -> [i + 1] : i >= pos;
1523 * separation_class[[i] -> [c]]
1524 * -> separation_class[[i] -> [c]] : i < pos;
1525 * separation_class[[i] -> [c]]
1526 * -> separation_class[[i + 1] -> [c]] : i >= pos }
1528 static __isl_give isl_union_map *options_insert_dim(
1529 __isl_take isl_union_map *options, __isl_take isl_space *space, int pos)
1531 isl_map *map;
1532 isl_union_map *insertion;
1533 enum isl_ast_loop_type type;
1534 const char *name = "separation_class";
1536 space = isl_space_map_from_set(space);
1537 map = isl_map_identity(space);
1538 map = isl_map_insert_dims(map, isl_dim_out, pos, 1);
1539 options = isl_union_map_apply_domain(options,
1540 isl_union_map_from_map(map));
1542 if (!options)
1543 return NULL;
1545 map = construct_insertion_map(isl_union_map_get_space(options), pos);
1547 insertion = isl_union_map_empty(isl_union_map_get_space(options));
1549 for (type = isl_ast_loop_atomic;
1550 type <= isl_ast_loop_separate; ++type) {
1551 isl_map *map_type = isl_map_copy(map);
1552 const char *name = option_str[type];
1553 map_type = isl_map_set_tuple_name(map_type, isl_dim_in, name);
1554 map_type = isl_map_set_tuple_name(map_type, isl_dim_out, name);
1555 insertion = isl_union_map_add_map(insertion, map_type);
1558 map = isl_map_product(map, isl_map_identity(isl_map_get_space(map)));
1559 map = isl_map_set_tuple_name(map, isl_dim_in, name);
1560 map = isl_map_set_tuple_name(map, isl_dim_out, name);
1561 insertion = isl_union_map_add_map(insertion, map);
1563 options = isl_union_map_apply_range(options, insertion);
1565 return options;
1568 /* Insert a single dimension in the schedule domain at position "pos".
1569 * The new dimension is given an isl_id with the empty string as name.
1571 * The main difficulty is updating build->options to reflect the
1572 * extra dimension. This is handled in options_insert_dim.
1574 * Note that because of the dimension manipulations, the resulting
1575 * schedule domain space will always be unnamed and unstructured.
1576 * However, the original schedule domain space may be named and/or
1577 * structured, so we have to take this possibility into account
1578 * while performing the transformations.
1580 __isl_give isl_ast_build *isl_ast_build_insert_dim(
1581 __isl_take isl_ast_build *build, int pos)
1583 isl_ctx *ctx;
1584 isl_space *space, *ma_space;
1585 isl_id *id;
1586 isl_multi_aff *ma;
1588 build = isl_ast_build_cow(build);
1589 if (!build)
1590 return NULL;
1592 ctx = isl_ast_build_get_ctx(build);
1593 id = isl_id_alloc(ctx, "", NULL);
1594 if (!build->node)
1595 space = isl_ast_build_get_space(build, 1);
1596 build->iterators = isl_id_list_insert(build->iterators, pos, id);
1597 build->domain = isl_set_insert_dims(build->domain,
1598 isl_dim_set, pos, 1);
1599 build->generated = isl_set_insert_dims(build->generated,
1600 isl_dim_set, pos, 1);
1601 build->pending = isl_set_insert_dims(build->pending,
1602 isl_dim_set, pos, 1);
1603 build->strides = isl_vec_insert_els(build->strides, pos, 1);
1604 build->strides = isl_vec_set_element_si(build->strides, pos, 1);
1605 ma_space = isl_space_params(isl_multi_aff_get_space(build->offsets));
1606 ma_space = isl_space_set_from_params(ma_space);
1607 ma_space = isl_space_add_dims(ma_space, isl_dim_set, 1);
1608 ma_space = isl_space_map_from_set(ma_space);
1609 ma = isl_multi_aff_zero(isl_space_copy(ma_space));
1610 build->offsets = isl_multi_aff_splice(build->offsets, pos, pos, ma);
1611 ma = isl_multi_aff_identity(ma_space);
1612 build->values = isl_multi_aff_splice(build->values, pos, pos, ma);
1613 if (!build->node)
1614 build->options = options_insert_dim(build->options, space, pos);
1616 if (!build->iterators || !build->domain || !build->generated ||
1617 !build->pending || !build->values ||
1618 !build->strides || !build->offsets || !build->options)
1619 return isl_ast_build_free(build);
1621 return build;
1624 /* Scale down the current dimension by a factor of "m".
1625 * "umap" is an isl_union_map that implements the scaling down.
1626 * That is, it is of the form
1628 * { [.... i ....] -> [.... i' ....] : i = m i' }
1630 * This function is called right after the strides have been
1631 * detected, but before any constraints on the current dimension
1632 * have been included in build->domain.
1633 * We therefore only need to update stride, offset and the options.
1635 __isl_give isl_ast_build *isl_ast_build_scale_down(
1636 __isl_take isl_ast_build *build, __isl_take isl_val *m,
1637 __isl_take isl_union_map *umap)
1639 isl_aff *aff;
1640 isl_val *v;
1641 int depth;
1643 build = isl_ast_build_cow(build);
1644 if (!build || !umap || !m)
1645 goto error;
1647 depth = build->depth;
1649 v = isl_vec_get_element_val(build->strides, depth);
1650 v = isl_val_div(v, isl_val_copy(m));
1651 build->strides = isl_vec_set_element_val(build->strides, depth, v);
1653 aff = isl_multi_aff_get_aff(build->offsets, depth);
1654 aff = isl_aff_scale_down_val(aff, m);
1655 build->offsets = isl_multi_aff_set_aff(build->offsets, depth, aff);
1656 build->options = isl_union_map_apply_domain(build->options, umap);
1657 if (!build->strides || !build->offsets || !build->options)
1658 return isl_ast_build_free(build);
1660 return build;
1661 error:
1662 isl_val_free(m);
1663 isl_union_map_free(umap);
1664 return isl_ast_build_free(build);
1667 /* Return a list of "n" isl_ids called "c%d", with "%d" starting at "first".
1668 * If an isl_id with such a name already appears among the parameters
1669 * in build->domain, then adjust the name to "c%d_%d".
1671 static __isl_give isl_id_list *generate_names(isl_ctx *ctx, int n, int first,
1672 __isl_keep isl_ast_build *build)
1674 int i;
1675 isl_id_list *names;
1677 names = isl_id_list_alloc(ctx, n);
1678 for (i = 0; i < n; ++i) {
1679 isl_id *id;
1681 id = generate_name(ctx, first + i, build);
1682 names = isl_id_list_add(names, id);
1685 return names;
1688 /* Embed "options" into the given isl_ast_build space.
1690 * This function is called from within a nested call to
1691 * isl_ast_build_node_from_schedule_map.
1692 * "options" refers to the additional schedule,
1693 * while space refers to both the space of the outer isl_ast_build and
1694 * that of the additional schedule.
1695 * Specifically, space is of the form
1697 * [I -> S]
1699 * while options lives in the space(s)
1701 * S -> *
1703 * We compute
1705 * [I -> S] -> S
1707 * and compose this with options, to obtain the new options
1708 * living in the space(s)
1710 * [I -> S] -> *
1712 static __isl_give isl_union_map *embed_options(
1713 __isl_take isl_union_map *options, __isl_take isl_space *space)
1715 isl_map *map;
1717 map = isl_map_universe(isl_space_unwrap(space));
1718 map = isl_map_range_map(map);
1720 options = isl_union_map_apply_range(
1721 isl_union_map_from_map(map), options);
1723 return options;
1726 /* Update "build" for use in a (possibly nested) code generation. That is,
1727 * extend "build" from an AST build on some domain O to an AST build
1728 * on domain [O -> S], with S corresponding to "space".
1729 * If the original domain is a parameter domain, then the new domain is
1730 * simply S.
1731 * "iterators" is a list of iterators for S, but the number of elements
1732 * may be smaller or greater than the number of set dimensions of S.
1733 * If "keep_iterators" is set, then any extra ids in build->iterators
1734 * are reused for S. Otherwise, these extra ids are dropped.
1736 * We first update build->outer_pos to the current depth.
1737 * This depth is zero in case this is the outermost code generation.
1739 * We then add additional ids such that the number of iterators is at least
1740 * equal to the dimension of the new build domain.
1742 * If the original domain is parametric, then we are constructing
1743 * an isl_ast_build for the outer code generation and we pass control
1744 * to isl_ast_build_init.
1746 * Otherwise, we adjust the fields of "build" to include "space".
1748 __isl_give isl_ast_build *isl_ast_build_product(
1749 __isl_take isl_ast_build *build, __isl_take isl_space *space)
1751 isl_ctx *ctx;
1752 isl_vec *strides;
1753 isl_set *set;
1754 isl_multi_aff *embedding;
1755 int dim, n_it;
1757 build = isl_ast_build_cow(build);
1758 if (!build)
1759 goto error;
1761 build->outer_pos = build->depth;
1763 ctx = isl_ast_build_get_ctx(build);
1764 dim = isl_set_dim(build->domain, isl_dim_set);
1765 dim += isl_space_dim(space, isl_dim_set);
1766 n_it = isl_id_list_n_id(build->iterators);
1767 if (n_it < dim) {
1768 isl_id_list *l;
1769 l = generate_names(ctx, dim - n_it, n_it, build);
1770 build->iterators = isl_id_list_concat(build->iterators, l);
1773 if (isl_set_is_params(build->domain))
1774 return isl_ast_build_init(build, space);
1776 set = isl_set_universe(isl_space_copy(space));
1777 build->domain = isl_set_product(build->domain, isl_set_copy(set));
1778 build->pending = isl_set_product(build->pending, isl_set_copy(set));
1779 build->generated = isl_set_product(build->generated, set);
1781 strides = isl_vec_alloc(ctx, isl_space_dim(space, isl_dim_set));
1782 strides = isl_vec_set_si(strides, 1);
1783 build->strides = isl_vec_concat(build->strides, strides);
1785 space = isl_space_map_from_set(space);
1786 build->offsets = isl_multi_aff_align_params(build->offsets,
1787 isl_space_copy(space));
1788 build->offsets = isl_multi_aff_product(build->offsets,
1789 isl_multi_aff_zero(isl_space_copy(space)));
1790 build->values = isl_multi_aff_align_params(build->values,
1791 isl_space_copy(space));
1792 embedding = isl_multi_aff_identity(space);
1793 build->values = isl_multi_aff_product(build->values, embedding);
1795 space = isl_ast_build_get_space(build, 1);
1796 build->options = embed_options(build->options, space);
1798 if (!build->iterators || !build->domain || !build->generated ||
1799 !build->pending || !build->values ||
1800 !build->strides || !build->offsets || !build->options)
1801 return isl_ast_build_free(build);
1803 return build;
1804 error:
1805 isl_ast_build_free(build);
1806 isl_space_free(space);
1807 return NULL;
1810 /* Does "aff" only attain non-negative values over build->domain?
1811 * That is, does it not attain any negative values?
1813 int isl_ast_build_aff_is_nonneg(__isl_keep isl_ast_build *build,
1814 __isl_keep isl_aff *aff)
1816 isl_set *test;
1817 int empty;
1819 if (!build)
1820 return -1;
1822 aff = isl_aff_copy(aff);
1823 test = isl_set_from_basic_set(isl_aff_neg_basic_set(aff));
1824 test = isl_set_intersect(test, isl_set_copy(build->domain));
1825 empty = isl_set_is_empty(test);
1826 isl_set_free(test);
1828 return empty;
1831 /* Does the dimension at (internal) position "pos" have a non-trivial stride?
1833 int isl_ast_build_has_stride(__isl_keep isl_ast_build *build, int pos)
1835 isl_val *v;
1836 int has_stride;
1838 if (!build)
1839 return -1;
1841 v = isl_vec_get_element_val(build->strides, pos);
1842 if (!v)
1843 return -1;
1844 has_stride = !isl_val_is_one(v);
1845 isl_val_free(v);
1847 return has_stride;
1850 /* Given that the dimension at position "pos" takes on values
1852 * f + s a
1854 * with a an integer, return s through *stride.
1856 __isl_give isl_val *isl_ast_build_get_stride(__isl_keep isl_ast_build *build,
1857 int pos)
1859 if (!build)
1860 return NULL;
1862 return isl_vec_get_element_val(build->strides, pos);
1865 /* Given that the dimension at position "pos" takes on values
1867 * f + s a
1869 * with a an integer, return f.
1871 __isl_give isl_aff *isl_ast_build_get_offset(
1872 __isl_keep isl_ast_build *build, int pos)
1874 if (!build)
1875 return NULL;
1877 return isl_multi_aff_get_aff(build->offsets, pos);
1880 /* Is the dimension at position "pos" known to attain only a single
1881 * value that, moreover, can be described by a single affine expression
1882 * in terms of the outer dimensions and parameters?
1884 * If not, then the corresponding affine expression in build->values
1885 * is set to be equal to the same input dimension.
1886 * Otherwise, it is set to the requested expression in terms of
1887 * outer dimensions and parameters.
1889 int isl_ast_build_has_affine_value(__isl_keep isl_ast_build *build,
1890 int pos)
1892 isl_aff *aff;
1893 int involves;
1895 if (!build)
1896 return -1;
1898 aff = isl_multi_aff_get_aff(build->values, pos);
1899 involves = isl_aff_involves_dims(aff, isl_dim_in, pos, 1);
1900 isl_aff_free(aff);
1902 if (involves < 0)
1903 return -1;
1905 return !involves;
1908 /* Plug in the known values (fixed affine expressions in terms of
1909 * parameters and outer loop iterators) of all loop iterators
1910 * in the domain of "umap".
1912 * We simply precompose "umap" with build->values.
1914 __isl_give isl_union_map *isl_ast_build_substitute_values_union_map_domain(
1915 __isl_keep isl_ast_build *build, __isl_take isl_union_map *umap)
1917 isl_multi_aff *values;
1919 if (!build)
1920 return isl_union_map_free(umap);
1922 values = isl_multi_aff_copy(build->values);
1923 umap = isl_union_map_preimage_domain_multi_aff(umap, values);
1925 return umap;
1928 /* Is the current dimension known to attain only a single value?
1930 int isl_ast_build_has_value(__isl_keep isl_ast_build *build)
1932 if (!build)
1933 return -1;
1935 return build->value != NULL;
1938 /* Simplify the basic set "bset" based on what we know about
1939 * the iterators of already generated loops.
1941 * "bset" is assumed to live in the (internal) schedule domain.
1943 __isl_give isl_basic_set *isl_ast_build_compute_gist_basic_set(
1944 __isl_keep isl_ast_build *build, __isl_take isl_basic_set *bset)
1946 if (!build)
1947 goto error;
1949 bset = isl_basic_set_preimage_multi_aff(bset,
1950 isl_multi_aff_copy(build->values));
1951 bset = isl_basic_set_gist(bset,
1952 isl_set_simple_hull(isl_set_copy(build->domain)));
1954 return bset;
1955 error:
1956 isl_basic_set_free(bset);
1957 return NULL;
1960 /* Simplify the set "set" based on what we know about
1961 * the iterators of already generated loops.
1963 * "set" is assumed to live in the (internal) schedule domain.
1965 __isl_give isl_set *isl_ast_build_compute_gist(
1966 __isl_keep isl_ast_build *build, __isl_take isl_set *set)
1968 if (!build)
1969 goto error;
1971 if (!isl_set_is_params(set))
1972 set = isl_set_preimage_multi_aff(set,
1973 isl_multi_aff_copy(build->values));
1974 set = isl_set_gist(set, isl_set_copy(build->domain));
1976 return set;
1977 error:
1978 isl_set_free(set);
1979 return NULL;
1982 /* Include information about what we know about the iterators of
1983 * already generated loops to "set".
1985 * We currently only plug in the known affine values of outer loop
1986 * iterators.
1987 * In principle we could also introduce equalities or even other
1988 * constraints implied by the intersection of "set" and build->domain.
1990 __isl_give isl_set *isl_ast_build_specialize(__isl_keep isl_ast_build *build,
1991 __isl_take isl_set *set)
1993 if (!build)
1994 return isl_set_free(set);
1996 return isl_set_preimage_multi_aff(set,
1997 isl_multi_aff_copy(build->values));
2000 /* Simplify the map "map" based on what we know about
2001 * the iterators of already generated loops.
2003 * The domain of "map" is assumed to live in the (internal) schedule domain.
2005 __isl_give isl_map *isl_ast_build_compute_gist_map_domain(
2006 __isl_keep isl_ast_build *build, __isl_take isl_map *map)
2008 if (!build)
2009 goto error;
2011 map = isl_map_gist_domain(map, isl_set_copy(build->domain));
2013 return map;
2014 error:
2015 isl_map_free(map);
2016 return NULL;
2019 /* Simplify the affine expression "aff" based on what we know about
2020 * the iterators of already generated loops.
2022 * The domain of "aff" is assumed to live in the (internal) schedule domain.
2024 __isl_give isl_aff *isl_ast_build_compute_gist_aff(
2025 __isl_keep isl_ast_build *build, __isl_take isl_aff *aff)
2027 if (!build)
2028 goto error;
2030 aff = isl_aff_gist(aff, isl_set_copy(build->domain));
2032 return aff;
2033 error:
2034 isl_aff_free(aff);
2035 return NULL;
2038 /* Simplify the piecewise affine expression "aff" based on what we know about
2039 * the iterators of already generated loops.
2041 * The domain of "pa" is assumed to live in the (internal) schedule domain.
2043 __isl_give isl_pw_aff *isl_ast_build_compute_gist_pw_aff(
2044 __isl_keep isl_ast_build *build, __isl_take isl_pw_aff *pa)
2046 if (!build)
2047 goto error;
2049 if (!isl_set_is_params(build->domain))
2050 pa = isl_pw_aff_pullback_multi_aff(pa,
2051 isl_multi_aff_copy(build->values));
2052 pa = isl_pw_aff_gist(pa, isl_set_copy(build->domain));
2054 return pa;
2055 error:
2056 isl_pw_aff_free(pa);
2057 return NULL;
2060 /* Simplify the piecewise multi-affine expression "aff" based on what
2061 * we know about the iterators of already generated loops.
2063 * The domain of "pma" is assumed to live in the (internal) schedule domain.
2065 __isl_give isl_pw_multi_aff *isl_ast_build_compute_gist_pw_multi_aff(
2066 __isl_keep isl_ast_build *build, __isl_take isl_pw_multi_aff *pma)
2068 if (!build)
2069 goto error;
2071 pma = isl_pw_multi_aff_pullback_multi_aff(pma,
2072 isl_multi_aff_copy(build->values));
2073 pma = isl_pw_multi_aff_gist(pma, isl_set_copy(build->domain));
2075 return pma;
2076 error:
2077 isl_pw_multi_aff_free(pma);
2078 return NULL;
2081 /* Extract the schedule domain of the given type from build->options
2082 * at the current depth.
2084 * In particular, find the subset of build->options that is of
2085 * the following form
2087 * schedule_domain -> type[depth]
2089 * and return the corresponding domain, after eliminating inner dimensions
2090 * and divs that depend on the current dimension.
2092 * Note that the domain of build->options has been reformulated
2093 * in terms of the internal build space in embed_options,
2094 * but the position is still that within the current code generation.
2096 __isl_give isl_set *isl_ast_build_get_option_domain(
2097 __isl_keep isl_ast_build *build, enum isl_ast_loop_type type)
2099 const char *name;
2100 isl_space *space;
2101 isl_map *option;
2102 isl_set *domain;
2103 int local_pos;
2105 if (!build)
2106 return NULL;
2108 name = option_str[type];
2109 local_pos = build->depth - build->outer_pos;
2111 space = isl_ast_build_get_space(build, 1);
2112 space = isl_space_from_domain(space);
2113 space = isl_space_add_dims(space, isl_dim_out, 1);
2114 space = isl_space_set_tuple_name(space, isl_dim_out, name);
2116 option = isl_union_map_extract_map(build->options, space);
2117 option = isl_map_fix_si(option, isl_dim_out, 0, local_pos);
2119 domain = isl_map_domain(option);
2120 domain = isl_ast_build_eliminate(build, domain);
2122 return domain;
2125 /* Extract the separation class mapping at the current depth.
2127 * In particular, find and return the subset of build->options that is of
2128 * the following form
2130 * schedule_domain -> separation_class[[depth] -> [class]]
2132 * The caller is expected to eliminate inner dimensions from the domain.
2134 * Note that the domain of build->options has been reformulated
2135 * in terms of the internal build space in embed_options,
2136 * but the position is still that within the current code generation.
2138 __isl_give isl_map *isl_ast_build_get_separation_class(
2139 __isl_keep isl_ast_build *build)
2141 isl_ctx *ctx;
2142 isl_space *space_sep, *space;
2143 isl_map *res;
2144 int local_pos;
2146 if (!build)
2147 return NULL;
2149 local_pos = build->depth - build->outer_pos;
2150 ctx = isl_ast_build_get_ctx(build);
2151 space_sep = isl_space_alloc(ctx, 0, 1, 1);
2152 space_sep = isl_space_wrap(space_sep);
2153 space_sep = isl_space_set_tuple_name(space_sep, isl_dim_set,
2154 "separation_class");
2155 space = isl_ast_build_get_space(build, 1);
2156 space_sep = isl_space_align_params(space_sep, isl_space_copy(space));
2157 space = isl_space_map_from_domain_and_range(space, space_sep);
2159 res = isl_union_map_extract_map(build->options, space);
2160 res = isl_map_fix_si(res, isl_dim_out, 0, local_pos);
2161 res = isl_map_coalesce(res);
2163 return res;
2166 /* Eliminate dimensions inner to the current dimension.
2168 __isl_give isl_set *isl_ast_build_eliminate_inner(
2169 __isl_keep isl_ast_build *build, __isl_take isl_set *set)
2171 int dim;
2172 int depth;
2174 if (!build)
2175 return isl_set_free(set);
2177 dim = isl_set_dim(set, isl_dim_set);
2178 depth = build->depth;
2179 set = isl_set_detect_equalities(set);
2180 set = isl_set_eliminate(set, isl_dim_set, depth + 1, dim - (depth + 1));
2182 return set;
2185 /* Eliminate unknown divs and divs that depend on the current dimension.
2187 * Note that during the elimination of unknown divs, we may discover
2188 * an explicit representation of some other unknown divs, which may
2189 * depend on the current dimension. We therefore need to eliminate
2190 * unknown divs first.
2192 __isl_give isl_set *isl_ast_build_eliminate_divs(
2193 __isl_keep isl_ast_build *build, __isl_take isl_set *set)
2195 int depth;
2197 if (!build)
2198 return isl_set_free(set);
2200 set = isl_set_remove_unknown_divs(set);
2201 depth = build->depth;
2202 set = isl_set_remove_divs_involving_dims(set, isl_dim_set, depth, 1);
2204 return set;
2207 /* Eliminate dimensions inner to the current dimension as well as
2208 * unknown divs and divs that depend on the current dimension.
2209 * The result then consists only of constraints that are independent
2210 * of the current dimension and upper and lower bounds on the current
2211 * dimension.
2213 __isl_give isl_set *isl_ast_build_eliminate(
2214 __isl_keep isl_ast_build *build, __isl_take isl_set *domain)
2216 domain = isl_ast_build_eliminate_inner(build, domain);
2217 domain = isl_ast_build_eliminate_divs(build, domain);
2218 return domain;
2221 /* Replace build->single_valued by "sv".
2223 __isl_give isl_ast_build *isl_ast_build_set_single_valued(
2224 __isl_take isl_ast_build *build, int sv)
2226 if (!build)
2227 return build;
2228 if (build->single_valued == sv)
2229 return build;
2230 build = isl_ast_build_cow(build);
2231 if (!build)
2232 return build;
2233 build->single_valued = sv;
2235 return build;