1 /*
2  * Copyright 2011      Leiden University. All rights reserved.
3  * Copyright 2012-2014 Ecole Normale Superieure. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *    1. Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *
12  *    2. Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials provided
15  *       with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and documentation
30  * are those of the authors and should not be interpreted as
31  * representing official policies, either expressed or implied, of
32  * Leiden University.
33  */
34 
35 #include <string.h>
36 #include <isl/ctx.h>
37 #include <isl/id.h>
38 #include <isl/space.h>
39 #include <isl/local_space.h>
40 #include <isl/constraint.h>
41 #include <isl/val.h>
42 #include <isl/aff.h>
43 #include <isl/set.h>
44 #include <isl/map.h>
45 #include <isl/union_set.h>
46 #include <isl/union_map.h>
47 #include <isl/schedule_node.h>
48 
49 #include "aff.h"
50 #include "expr.h"
51 #include "expr_access_type.h"
52 #include "filter.h"
53 #include "loc.h"
54 #include "nest.h"
55 #include "scop.h"
56 #include "tree.h"
57 #include "print.h"
58 #include "value_bounds.h"
59 
60 /* pet_scop with extra information that is used during parsing and printing.
61  *
62  * In particular, we keep track of conditions under which we want
63  * to skip the rest of the current loop iteration (skip[pet_skip_now])
64  * and of conditions under which we want to skip subsequent
65  * loop iterations (skip[pet_skip_later]).
66  *
67  * The conditions are represented as index expressions defined
68  * over the outer loop iterators.  The index expression is either
69  * a boolean affine expression or an access to a variable, which
70  * is assumed to attain values zero and one.  The condition holds
71  * if the variable has value one or if the affine expression
72  * has value one (typically for only part of the domain).
73  *
74  * A missing condition (skip[type] == NULL) means that we don't want
75  * to skip anything.
76  *
77  * Additionally, we keep track of the original input file
78  * inside pet_transform_C_source.
79  */
80 struct pet_scop_ext {
81 	struct pet_scop scop;
82 
83 	isl_multi_pw_aff *skip[2];
84 	FILE *input;
85 };
86 
87 /* Construct a pet_stmt with given domain and statement number from a pet_tree.
88  * The input domain is anonymous and is the same as the domains
89  * of the access expressions inside "tree".
90  * These domains are modified to include the name of the statement.
91  * This name is given by tree->label if it is non-NULL.
92  * Otherwise, the name is constructed as S_<id>.
93  */
pet_stmt_from_pet_tree(__isl_take isl_set * domain,int id,__isl_take pet_tree * tree)94 struct pet_stmt *pet_stmt_from_pet_tree(__isl_take isl_set *domain,
95 	int id, __isl_take pet_tree *tree)
96 {
97 	struct pet_stmt *stmt;
98 	isl_ctx *ctx;
99 	isl_id *label;
100 	isl_space *space;
101 	isl_multi_aff *ma;
102 	isl_multi_pw_aff *add_name;
103 	char name[50];
104 
105 	if (!domain || !tree)
106 		goto error;
107 
108 	ctx = pet_tree_get_ctx(tree);
109 	stmt = isl_calloc_type(ctx, struct pet_stmt);
110 	if (!stmt)
111 		goto error;
112 
113 	if (tree->label) {
114 		label = isl_id_copy(tree->label);
115 	} else {
116 		snprintf(name, sizeof(name), "S_%d", id);
117 		label = isl_id_alloc(ctx, name, NULL);
118 	}
119 	domain = isl_set_set_tuple_id(domain, label);
120 	space = isl_set_get_space(domain);
121 	space = pet_nested_remove_from_space(space);
122 	ma = pet_prefix_projection(space, isl_space_dim(space, isl_dim_set));
123 
124 	add_name = isl_multi_pw_aff_from_multi_aff(ma);
125 	tree = pet_tree_update_domain(tree, add_name);
126 
127 	stmt->loc = pet_tree_get_loc(tree);
128 	stmt->domain = domain;
129 	stmt->body = tree;
130 
131 	if (!stmt->domain || !stmt->body)
132 		return pet_stmt_free(stmt);
133 
134 	return stmt;
135 error:
136 	isl_set_free(domain);
137 	pet_tree_free(tree);
138 	return NULL;
139 }
140 
pet_stmt_free(struct pet_stmt * stmt)141 void *pet_stmt_free(struct pet_stmt *stmt)
142 {
143 	int i;
144 
145 	if (!stmt)
146 		return NULL;
147 
148 	pet_loc_free(stmt->loc);
149 	isl_set_free(stmt->domain);
150 	pet_tree_free(stmt->body);
151 
152 	for (i = 0; i < stmt->n_arg; ++i)
153 		pet_expr_free(stmt->args[i]);
154 	free(stmt->args);
155 
156 	free(stmt);
157 	return NULL;
158 }
159 
160 /* Return the iteration space of "stmt".
161  *
162  * If the statement has arguments, then stmt->domain is a wrapped map
163  * mapping the iteration domain to the values of the arguments
164  * for which this statement is executed.
165  * In this case, we need to extract the domain space of this wrapped map.
166  */
pet_stmt_get_space(struct pet_stmt * stmt)167 __isl_give isl_space *pet_stmt_get_space(struct pet_stmt *stmt)
168 {
169 	isl_space *space;
170 
171 	if (!stmt)
172 		return NULL;
173 
174 	space = isl_set_get_space(stmt->domain);
175 	if (isl_space_is_wrapping(space))
176 		space = isl_space_domain(isl_space_unwrap(space));
177 
178 	return space;
179 }
180 
stmt_dump(struct pet_stmt * stmt,int indent)181 static void stmt_dump(struct pet_stmt *stmt, int indent)
182 {
183 	int i;
184 
185 	if (!stmt)
186 		return;
187 
188 	fprintf(stderr, "%*s%d\n", indent, "", pet_loc_get_line(stmt->loc));
189 	fprintf(stderr, "%*s", indent, "");
190 	isl_set_dump(stmt->domain);
191 	pet_tree_dump_with_indent(stmt->body, indent);
192 	for (i = 0; i < stmt->n_arg; ++i)
193 		pet_expr_dump_with_indent(stmt->args[i], indent + 2);
194 }
195 
pet_stmt_dump(struct pet_stmt * stmt)196 void pet_stmt_dump(struct pet_stmt *stmt)
197 {
198 	stmt_dump(stmt, 0);
199 }
200 
201 /* Allocate a new pet_type with the given "name" and "definition".
202  */
pet_type_alloc(isl_ctx * ctx,const char * name,const char * definition)203 struct pet_type *pet_type_alloc(isl_ctx *ctx, const char *name,
204 	const char *definition)
205 {
206 	struct pet_type *type;
207 
208 	type = isl_alloc_type(ctx, struct pet_type);
209 	if (!type)
210 		return NULL;
211 
212 	type->name = strdup(name);
213 	type->definition = strdup(definition);
214 
215 	if (!type->name || !type->definition)
216 		return pet_type_free(type);
217 
218 	return type;
219 }
220 
221 /* Free "type" and return NULL.
222  */
pet_type_free(struct pet_type * type)223 struct pet_type *pet_type_free(struct pet_type *type)
224 {
225 	if (!type)
226 		return NULL;
227 
228 	free(type->name);
229 	free(type->definition);
230 
231 	free(type);
232 	return NULL;
233 }
234 
pet_array_free(struct pet_array * array)235 struct pet_array *pet_array_free(struct pet_array *array)
236 {
237 	if (!array)
238 		return NULL;
239 
240 	isl_set_free(array->context);
241 	isl_set_free(array->extent);
242 	isl_set_free(array->value_bounds);
243 	free(array->element_type);
244 
245 	free(array);
246 	return NULL;
247 }
248 
pet_array_dump(struct pet_array * array)249 void pet_array_dump(struct pet_array *array)
250 {
251 	if (!array)
252 		return;
253 
254 	isl_set_dump(array->context);
255 	isl_set_dump(array->extent);
256 	isl_set_dump(array->value_bounds);
257 	fprintf(stderr, "%s%s%s\n", array->element_type,
258 		array->element_is_record ? " element-is-record" : "",
259 		array->live_out ? " live-out" : "");
260 }
261 
262 /* Alloc a pet_scop structure, with extra room for information that
263  * is only used during parsing.
264  */
pet_scop_alloc(isl_ctx * ctx)265 struct pet_scop *pet_scop_alloc(isl_ctx *ctx)
266 {
267 	return &isl_calloc_type(ctx, struct pet_scop_ext)->scop;
268 }
269 
270 /* Construct a pet_scop in the given space, with the given schedule and
271  * room for n statements.
272  *
273  * The context is initialized as a universe set in "space".
274  *
275  * Since no information on the location is known at this point,
276  * scop->loc is initialized with pet_loc_dummy.
277  */
scop_alloc(__isl_take isl_space * space,int n,__isl_take isl_schedule * schedule)278 static struct pet_scop *scop_alloc(__isl_take isl_space *space, int n,
279 	__isl_take isl_schedule *schedule)
280 {
281 	isl_ctx *ctx;
282 	struct pet_scop *scop;
283 
284 	if (!space || !schedule)
285 		goto error;
286 
287 	ctx = isl_space_get_ctx(space);
288 	scop = pet_scop_alloc(ctx);
289 	if (!scop)
290 		goto error;
291 
292 	scop->context = isl_set_universe(isl_space_copy(space));
293 	scop->context_value = isl_set_universe(isl_space_params(space));
294 	scop->stmts = isl_calloc_array(ctx, struct pet_stmt *, n);
295 	scop->schedule = schedule;
296 	if (!scop->context || !scop->stmts)
297 		return pet_scop_free(scop);
298 
299 	scop->loc = &pet_loc_dummy;
300 	scop->n_stmt = n;
301 
302 	return scop;
303 error:
304 	isl_space_free(space);
305 	isl_schedule_free(schedule);
306 	return NULL;
307 }
308 
309 /* Construct a pet_scop in the given space containing 0 statements
310  * (and therefore an empty iteration domain).
311  */
pet_scop_empty(__isl_take isl_space * space)312 struct pet_scop *pet_scop_empty(__isl_take isl_space *space)
313 {
314 	isl_schedule *schedule;
315 
316 	schedule = isl_schedule_empty(isl_space_copy(space));
317 
318 	return scop_alloc(space, 0, schedule);
319 }
320 
321 /* Given either an iteration domain or a wrapped map with
322  * the iteration domain in the domain and some arguments
323  * in the range, return the iteration domain.
324  * That is, drop the arguments if there are any.
325  */
drop_arguments(__isl_take isl_set * domain)326 static __isl_give isl_set *drop_arguments(__isl_take isl_set *domain)
327 {
328 	if (isl_set_is_wrapping(domain))
329 		domain = isl_map_domain(isl_set_unwrap(domain));
330 	return domain;
331 }
332 
333 /* Update "context" with the constraints imposed on the outer iteration
334  * domain by access expression "expr".
335  * "context" lives in an anonymous space, while the domain of the access
336  * relation of "expr" refers to a particular statement.
337  * This reference therefore needs to be stripped off.
338  */
access_extract_context(__isl_keep pet_expr * expr,__isl_take isl_set * context)339 static __isl_give isl_set *access_extract_context(__isl_keep pet_expr *expr,
340 	__isl_take isl_set *context)
341 {
342 	isl_multi_pw_aff *mpa;
343 	isl_set *domain;
344 
345 	mpa = pet_expr_access_get_index(expr);
346 	domain = drop_arguments(isl_multi_pw_aff_domain(mpa));
347 	domain = isl_set_reset_tuple_id(domain);
348 	context = isl_set_intersect(context, domain);
349 	return context;
350 }
351 
352 /* Update "context" with the constraints imposed on the outer iteration
353  * domain by "expr".
354  *
355  * "context" lives in an anonymous space, while the domains of
356  * the access relations in "expr" refer to a particular statement.
357  * This reference therefore needs to be stripped off.
358  *
359  * If "expr" represents a conditional operator, then a parameter or outer
360  * iterator value needs to be valid for the condition and
361  * for at least one of the remaining two arguments.
362  * If the condition is an affine expression, then we can be a bit more specific.
363  * The value then has to be valid for the second argument for
364  * non-zero accesses and valid for the third argument for zero accesses.
365  *
366  * If "expr" represents a kill statement, then its argument is the entire
367  * extent of the array being killed.  Do not update "context" based
368  * on this argument as that would impose constraints that ensure that
369  * the array is non-empty.
370  */
expr_extract_context(__isl_keep pet_expr * expr,__isl_take isl_set * context)371 static __isl_give isl_set *expr_extract_context(__isl_keep pet_expr *expr,
372 	__isl_take isl_set *context)
373 {
374 	int i;
375 
376 	if (expr->type == pet_expr_op && expr->op == pet_op_kill)
377 		return context;
378 
379 	if (expr->type == pet_expr_op && expr->op == pet_op_cond) {
380 		int is_aff;
381 		isl_set *context1, *context2;
382 
383 		is_aff = pet_expr_is_affine(expr->args[0]);
384 		if (is_aff < 0)
385 			goto error;
386 
387 		context = expr_extract_context(expr->args[0], context);
388 		context1 = expr_extract_context(expr->args[1],
389 						isl_set_copy(context));
390 		context2 = expr_extract_context(expr->args[2], context);
391 
392 		if (is_aff) {
393 			isl_multi_pw_aff *mpa;
394 			isl_pw_aff *pa;
395 			isl_set *zero_set;
396 
397 			mpa = pet_expr_access_get_index(expr->args[0]);
398 			pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);
399 			isl_multi_pw_aff_free(mpa);
400 			zero_set = drop_arguments(isl_pw_aff_zero_set(pa));
401 			zero_set = isl_set_reset_tuple_id(zero_set);
402 			context1 = isl_set_subtract(context1,
403 						    isl_set_copy(zero_set));
404 			context2 = isl_set_intersect(context2, zero_set);
405 		}
406 
407 		context = isl_set_union(context1, context2);
408 		context = isl_set_coalesce(context);
409 
410 		return context;
411 	}
412 
413 	for (i = 0; i < expr->n_arg; ++i)
414 		context = expr_extract_context(expr->args[i], context);
415 
416 	if (expr->type == pet_expr_access)
417 		context = access_extract_context(expr, context);
418 
419 	return context;
420 error:
421 	isl_set_free(context);
422 	return NULL;
423 }
424 
425 /* Is "stmt" an assume statement with an affine assumption?
426  */
pet_stmt_is_affine_assume(struct pet_stmt * stmt)427 isl_bool pet_stmt_is_affine_assume(struct pet_stmt *stmt)
428 {
429 	if (!stmt)
430 		return isl_bool_error;
431 	return pet_tree_is_affine_assume(stmt->body);
432 }
433 
434 /* Given an assume statement "stmt" with an access argument,
435  * return the index expression of the argument.
436  */
pet_stmt_assume_get_index(struct pet_stmt * stmt)437 __isl_give isl_multi_pw_aff *pet_stmt_assume_get_index(struct pet_stmt *stmt)
438 {
439 	if (!stmt)
440 		return NULL;
441 	return pet_tree_assume_get_index(stmt->body);
442 }
443 
444 /* Assuming "stmt" is an assume statement with an affine assumption,
445  * return the assumption as a set.
446  */
pet_stmt_assume_get_affine_condition(struct pet_stmt * stmt)447 __isl_give isl_set *pet_stmt_assume_get_affine_condition(struct pet_stmt *stmt)
448 {
449 	isl_multi_pw_aff *index;
450 	isl_pw_aff *pa;
451 
452 	index = pet_stmt_assume_get_index(stmt);
453 	pa = isl_multi_pw_aff_get_pw_aff(index, 0);
454 	isl_multi_pw_aff_free(index);
455 	return isl_pw_aff_non_zero_set(pa);
456 }
457 
458 /* Update "context" with the constraints imposed on the outer iteration
459  * domain by "stmt".
460  *
461  * If the statement is an assume statement with an affine expression,
462  * then intersect "context" with that expression.
463  * Otherwise, if the statement body is an expression tree,
464  * then intersect "context" with the context of this expression.
465  * Note that we cannot safely extract a context from subtrees
466  * of the statement body since we cannot tell when those subtrees
467  * are executed, if at all.
468  */
stmt_extract_context(struct pet_stmt * stmt,__isl_take isl_set * context)469 static __isl_give isl_set *stmt_extract_context(struct pet_stmt *stmt,
470 	__isl_take isl_set *context)
471 {
472 	int i;
473 	isl_bool affine;
474 	pet_expr *body;
475 
476 	affine = pet_stmt_is_affine_assume(stmt);
477 	if (affine < 0)
478 		return isl_set_free(context);
479 	if (affine) {
480 		isl_set *cond;
481 
482 		cond = pet_stmt_assume_get_affine_condition(stmt);
483 		cond = isl_set_reset_tuple_id(cond);
484 		return isl_set_intersect(context, cond);
485 	}
486 
487 	for (i = 0; i < stmt->n_arg; ++i)
488 		context = expr_extract_context(stmt->args[i], context);
489 
490 	if (pet_tree_get_type(stmt->body) != pet_tree_expr)
491 		return context;
492 
493 	body = pet_tree_expr_get_expr(stmt->body);
494 	context = expr_extract_context(body, context);
495 	pet_expr_free(body);
496 
497 	return context;
498 }
499 
500 /* Construct a pet_scop in the given space that contains the given pet_stmt.
501  * The initial schedule consists of only the iteration domain.
502  */
pet_scop_from_pet_stmt(__isl_take isl_space * space,struct pet_stmt * stmt)503 struct pet_scop *pet_scop_from_pet_stmt(__isl_take isl_space *space,
504 	struct pet_stmt *stmt)
505 {
506 	struct pet_scop *scop;
507 	isl_set *set;
508 	isl_union_set *domain;
509 	isl_schedule *schedule;
510 
511 	if (!stmt) {
512 		isl_space_free(space);
513 		return NULL;
514 	}
515 
516 	set = pet_nested_remove_from_set(isl_set_copy(stmt->domain));
517 	domain = isl_union_set_from_set(set);
518 	schedule = isl_schedule_from_domain(domain);
519 
520 	scop = scop_alloc(space, 1, schedule);
521 	if (!scop)
522 		goto error;
523 
524 	scop->context = stmt_extract_context(stmt, scop->context);
525 	if (!scop->context)
526 		goto error;
527 
528 	scop->stmts[0] = stmt;
529 	scop->loc = pet_loc_copy(stmt->loc);
530 
531 	if (!scop->loc)
532 		return pet_scop_free(scop);
533 
534 	return scop;
535 error:
536 	pet_stmt_free(stmt);
537 	pet_scop_free(scop);
538 	return NULL;
539 }
540 
541 /* Does "mpa" represent an access to an element of an unnamed space, i.e.,
542  * does it represent an affine expression?
543  */
multi_pw_aff_is_affine(__isl_keep isl_multi_pw_aff * mpa)544 static int multi_pw_aff_is_affine(__isl_keep isl_multi_pw_aff *mpa)
545 {
546 	int has_id;
547 
548 	has_id = isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out);
549 	if (has_id < 0)
550 		return -1;
551 
552 	return !has_id;
553 }
554 
555 /* Return the piecewise affine expression "set ? 1 : 0" defined on "dom".
556  */
indicator_function(__isl_take isl_set * set,__isl_take isl_set * dom)557 static __isl_give isl_pw_aff *indicator_function(__isl_take isl_set *set,
558 	__isl_take isl_set *dom)
559 {
560 	isl_pw_aff *pa;
561 	pa = isl_set_indicator_function(set);
562 	pa = isl_pw_aff_intersect_domain(pa, dom);
563 	return pa;
564 }
565 
566 /* Return "lhs || rhs", defined on the shared definition domain.
567  */
pw_aff_or(__isl_take isl_pw_aff * lhs,__isl_take isl_pw_aff * rhs)568 static __isl_give isl_pw_aff *pw_aff_or(__isl_take isl_pw_aff *lhs,
569 	__isl_take isl_pw_aff *rhs)
570 {
571 	isl_set *cond;
572 	isl_set *dom;
573 
574 	dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(lhs)),
575 				 isl_pw_aff_domain(isl_pw_aff_copy(rhs)));
576 	cond = isl_set_union(isl_pw_aff_non_zero_set(lhs),
577 			     isl_pw_aff_non_zero_set(rhs));
578 	cond = isl_set_coalesce(cond);
579 	return indicator_function(cond, dom);
580 }
581 
582 /* Combine ext1->skip[type] and ext2->skip[type] into ext->skip[type].
583  * ext may be equal to either ext1 or ext2.
584  *
585  * The two skips that need to be combined are assumed to be affine expressions.
586  *
587  * We need to skip in ext if we need to skip in either ext1 or ext2.
588  * We don't need to skip in ext if we don't need to skip in both ext1 and ext2.
589  */
combine_skips(struct pet_scop_ext * ext,struct pet_scop_ext * ext1,struct pet_scop_ext * ext2,enum pet_skip type)590 static struct pet_scop_ext *combine_skips(struct pet_scop_ext *ext,
591 	struct pet_scop_ext *ext1, struct pet_scop_ext *ext2,
592 	enum pet_skip type)
593 {
594 	isl_pw_aff *skip, *skip1, *skip2;
595 
596 	if (!ext)
597 		return NULL;
598 	if (!ext1->skip[type] && !ext2->skip[type])
599 		return ext;
600 	if (!ext1->skip[type]) {
601 		if (ext == ext2)
602 			return ext;
603 		ext->skip[type] = ext2->skip[type];
604 		ext2->skip[type] = NULL;
605 		return ext;
606 	}
607 	if (!ext2->skip[type]) {
608 		if (ext == ext1)
609 			return ext;
610 		ext->skip[type] = ext1->skip[type];
611 		ext1->skip[type] = NULL;
612 		return ext;
613 	}
614 
615 	if (!multi_pw_aff_is_affine(ext1->skip[type]) ||
616 	    !multi_pw_aff_is_affine(ext2->skip[type]))
617 		isl_die(isl_multi_pw_aff_get_ctx(ext1->skip[type]),
618 			isl_error_internal, "can only combine affine skips",
619 			goto error);
620 
621 	skip1 = isl_multi_pw_aff_get_pw_aff(ext1->skip[type], 0);
622 	skip2 = isl_multi_pw_aff_get_pw_aff(ext2->skip[type], 0);
623 	skip = pw_aff_or(skip1, skip2);
624 	isl_multi_pw_aff_free(ext1->skip[type]);
625 	ext1->skip[type] = NULL;
626 	isl_multi_pw_aff_free(ext2->skip[type]);
627 	ext2->skip[type] = NULL;
628 	ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
629 	if (!ext->skip[type])
630 		goto error;
631 
632 	return ext;
633 error:
634 	pet_scop_free(&ext->scop);
635 	return NULL;
636 }
637 
638 /* Combine scop1->skip[type] and scop2->skip[type] into scop->skip[type],
639  * where type takes on the values pet_skip_now and pet_skip_later.
640  * scop may be equal to either scop1 or scop2.
641  */
scop_combine_skips(struct pet_scop * scop,struct pet_scop * scop1,struct pet_scop * scop2)642 static struct pet_scop *scop_combine_skips(struct pet_scop *scop,
643 	struct pet_scop *scop1, struct pet_scop *scop2)
644 {
645 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
646 	struct pet_scop_ext *ext1 = (struct pet_scop_ext *) scop1;
647 	struct pet_scop_ext *ext2 = (struct pet_scop_ext *) scop2;
648 
649 	ext = combine_skips(ext, ext1, ext2, pet_skip_now);
650 	ext = combine_skips(ext, ext1, ext2, pet_skip_later);
651 	return &ext->scop;
652 }
653 
654 /* Update start and end of scop->loc to include the region from "start"
655  * to "end".  In particular, if scop->loc == &pet_loc_dummy, then "scop"
656  * does not have any offset information yet and we simply take the information
657  * from "start" and "end".  Otherwise, we update loc using "start" and "end".
658  */
pet_scop_update_start_end(struct pet_scop * scop,unsigned start,unsigned end)659 struct pet_scop *pet_scop_update_start_end(struct pet_scop *scop,
660 	unsigned start, unsigned end)
661 {
662 	if (!scop)
663 		return NULL;
664 
665 	if (scop->loc == &pet_loc_dummy)
666 		scop->loc = pet_loc_alloc(isl_set_get_ctx(scop->context),
667 					    start, end, -1, strdup(""));
668 	else
669 		scop->loc = pet_loc_update_start_end(scop->loc, start, end);
670 
671 	if (!scop->loc)
672 		return pet_scop_free(scop);
673 
674 	return scop;
675 }
676 
677 /* Update start and end of scop->loc to include the region identified
678  * by "loc".
679  */
pet_scop_update_start_end_from_loc(struct pet_scop * scop,__isl_keep pet_loc * loc)680 struct pet_scop *pet_scop_update_start_end_from_loc(struct pet_scop *scop,
681 	__isl_keep pet_loc *loc)
682 {
683 	return pet_scop_update_start_end(scop, pet_loc_get_start(loc),
684 						pet_loc_get_end(loc));
685 }
686 
687 /* Replace the location of "scop" by "loc".
688  */
pet_scop_set_loc(struct pet_scop * scop,__isl_take pet_loc * loc)689 struct pet_scop *pet_scop_set_loc(struct pet_scop *scop,
690 	__isl_take pet_loc *loc)
691 {
692 	if (!scop || !loc)
693 		goto error;
694 
695 	pet_loc_free(scop->loc);
696 	scop->loc = loc;
697 
698 	return scop;
699 error:
700 	pet_loc_free(loc);
701 	pet_scop_free(scop);
702 	return NULL;
703 }
704 
705 /* Does "implication" appear in the list of implications of "scop"?
706  */
is_known_implication(struct pet_scop * scop,struct pet_implication * implication)707 static int is_known_implication(struct pet_scop *scop,
708 	struct pet_implication *implication)
709 {
710 	int i;
711 
712 	for (i = 0; i < scop->n_implication; ++i) {
713 		struct pet_implication *pi = scop->implications[i];
714 		int equal;
715 
716 		if (pi->satisfied != implication->satisfied)
717 			continue;
718 		equal = isl_map_is_equal(pi->extension, implication->extension);
719 		if (equal < 0)
720 			return -1;
721 		if (equal)
722 			return 1;
723 	}
724 
725 	return 0;
726 }
727 
728 /* Store the concatenation of the implications of "scop1" and "scop2"
729  * in "scop", removing duplicates (i.e., implications in "scop2" that
730  * already appear in "scop1").
731  */
scop_collect_implications(isl_ctx * ctx,struct pet_scop * scop,struct pet_scop * scop1,struct pet_scop * scop2)732 static struct pet_scop *scop_collect_implications(isl_ctx *ctx,
733 	struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
734 {
735 	int i, j;
736 
737 	if (!scop)
738 		return NULL;
739 
740 	if (scop2->n_implication == 0) {
741 		scop->n_implication = scop1->n_implication;
742 		scop->implications = scop1->implications;
743 		scop1->n_implication = 0;
744 		scop1->implications = NULL;
745 		return scop;
746 	}
747 
748 	if (scop1->n_implication == 0) {
749 		scop->n_implication = scop2->n_implication;
750 		scop->implications = scop2->implications;
751 		scop2->n_implication = 0;
752 		scop2->implications = NULL;
753 		return scop;
754 	}
755 
756 	scop->implications = isl_calloc_array(ctx, struct pet_implication *,
757 				scop1->n_implication + scop2->n_implication);
758 	if (!scop->implications)
759 		return pet_scop_free(scop);
760 
761 	for (i = 0; i < scop1->n_implication; ++i) {
762 		scop->implications[i] = scop1->implications[i];
763 		scop1->implications[i] = NULL;
764 	}
765 
766 	scop->n_implication = scop1->n_implication;
767 	j = scop1->n_implication;
768 	for (i = 0; i < scop2->n_implication; ++i) {
769 		int known;
770 
771 		known = is_known_implication(scop, scop2->implications[i]);
772 		if (known < 0)
773 			return pet_scop_free(scop);
774 		if (known)
775 			continue;
776 		scop->implications[j++] = scop2->implications[i];
777 		scop2->implications[i] = NULL;
778 	}
779 	scop->n_implication = j;
780 
781 	return scop;
782 }
783 
784 /* Combine the offset information of "scop1" and "scop2" into "scop".
785  */
scop_combine_start_end(struct pet_scop * scop,struct pet_scop * scop1,struct pet_scop * scop2)786 static struct pet_scop *scop_combine_start_end(struct pet_scop *scop,
787 	struct pet_scop *scop1, struct pet_scop *scop2)
788 {
789 	if (scop1->loc != &pet_loc_dummy)
790 		scop = pet_scop_update_start_end_from_loc(scop, scop1->loc);
791 	if (scop2->loc != &pet_loc_dummy)
792 		scop = pet_scop_update_start_end_from_loc(scop, scop2->loc);
793 	return scop;
794 }
795 
796 /* Create and return an independence that filters out the dependences
797  * in "filter" with local variables "local".
798  */
new_independence(__isl_take isl_union_map * filter,__isl_take isl_union_set * local)799 static struct pet_independence *new_independence(
800 	__isl_take isl_union_map *filter, __isl_take isl_union_set *local)
801 {
802 	isl_ctx *ctx;
803 	struct pet_independence *independence;
804 
805 	if (!filter || !local)
806 		goto error;
807 	ctx = isl_union_map_get_ctx(filter);
808 	independence = isl_alloc_type(ctx, struct pet_independence);
809 	if (!independence)
810 		goto error;
811 
812 	independence->filter = filter;
813 	independence->local = local;
814 
815 	return independence;
816 error:
817 	isl_union_map_free(filter);
818 	isl_union_set_free(local);
819 	return NULL;
820 }
821 
822 /* Add an independence that filters out the dependences
823  * in "filter" with local variables "local" to "scop".
824  */
pet_scop_add_independence(struct pet_scop * scop,__isl_take isl_union_map * filter,__isl_take isl_union_set * local)825 struct pet_scop *pet_scop_add_independence(struct pet_scop *scop,
826 	__isl_take isl_union_map *filter, __isl_take isl_union_set *local)
827 {
828 	isl_ctx *ctx;
829 	struct pet_independence *independence;
830 	struct pet_independence **independences;
831 
832 	ctx = isl_union_map_get_ctx(filter);
833 	independence = new_independence(filter, local);
834 	if (!scop || !independence)
835 		goto error;
836 
837 	independences = isl_realloc_array(ctx, scop->independences,
838 					    struct pet_independence *,
839 					    scop->n_independence + 1);
840 	if (!independences)
841 		goto error;
842 	scop->independences = independences;
843 	scop->independences[scop->n_independence] = independence;
844 	scop->n_independence++;
845 
846 	return scop;
847 error:
848 	pet_independence_free(independence);
849 	pet_scop_free(scop);
850 	return NULL;
851 }
852 
853 /* Store the concatenation of the independences of "scop1" and "scop2"
854  * in "scop".
855  */
scop_collect_independences(isl_ctx * ctx,struct pet_scop * scop,struct pet_scop * scop1,struct pet_scop * scop2)856 static struct pet_scop *scop_collect_independences(isl_ctx *ctx,
857 	struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
858 {
859 	int i, off;
860 
861 	if (!scop)
862 		return NULL;
863 
864 	if (scop2->n_independence == 0) {
865 		scop->n_independence = scop1->n_independence;
866 		scop->independences = scop1->independences;
867 		scop1->n_independence = 0;
868 		scop1->independences = NULL;
869 		return scop;
870 	}
871 
872 	if (scop1->n_independence == 0) {
873 		scop->n_independence = scop2->n_independence;
874 		scop->independences = scop2->independences;
875 		scop2->n_independence = 0;
876 		scop2->independences = NULL;
877 		return scop;
878 	}
879 
880 	scop->independences = isl_calloc_array(ctx, struct pet_independence *,
881 				scop1->n_independence + scop2->n_independence);
882 	if (!scop->independences)
883 		return pet_scop_free(scop);
884 
885 	for (i = 0; i < scop1->n_independence; ++i) {
886 		scop->independences[i] = scop1->independences[i];
887 		scop1->independences[i] = NULL;
888 	}
889 
890 	off = scop1->n_independence;
891 	for (i = 0; i < scop2->n_independence; ++i) {
892 		scop->independences[off + i] = scop2->independences[i];
893 		scop2->independences[i] = NULL;
894 	}
895 	scop->n_independence = scop1->n_independence + scop2->n_independence;
896 
897 	return scop;
898 }
899 
900 /* Construct a pet_scop with the given schedule
901  * that contains the offset information,
902  * arrays, statements and skip information in "scop1" and "scop2".
903  */
pet_scop_add(isl_ctx * ctx,__isl_take isl_schedule * schedule,struct pet_scop * scop1,struct pet_scop * scop2)904 static struct pet_scop *pet_scop_add(isl_ctx *ctx,
905 	__isl_take isl_schedule *schedule, struct pet_scop *scop1,
906 	struct pet_scop *scop2)
907 {
908 	int i;
909 	isl_space *space;
910 	struct pet_scop *scop = NULL;
911 
912 	if (!scop1 || !scop2)
913 		goto error;
914 
915 	if (scop1->n_stmt == 0) {
916 		scop2 = scop_combine_skips(scop2, scop1, scop2);
917 		pet_scop_free(scop1);
918 		isl_schedule_free(schedule);
919 		return scop2;
920 	}
921 
922 	if (scop2->n_stmt == 0) {
923 		scop1 = scop_combine_skips(scop1, scop1, scop2);
924 		pet_scop_free(scop2);
925 		isl_schedule_free(schedule);
926 		return scop1;
927 	}
928 
929 	space = isl_set_get_space(scop1->context);
930 	scop = scop_alloc(space, scop1->n_stmt + scop2->n_stmt,
931 			isl_schedule_copy(schedule));
932 	if (!scop)
933 		goto error;
934 
935 	scop->arrays = isl_calloc_array(ctx, struct pet_array *,
936 					scop1->n_array + scop2->n_array);
937 	if (!scop->arrays)
938 		goto error;
939 	scop->n_array = scop1->n_array + scop2->n_array;
940 
941 	for (i = 0; i < scop1->n_stmt; ++i) {
942 		scop->stmts[i] = scop1->stmts[i];
943 		scop1->stmts[i] = NULL;
944 	}
945 
946 	for (i = 0; i < scop2->n_stmt; ++i) {
947 		scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
948 		scop2->stmts[i] = NULL;
949 	}
950 
951 	for (i = 0; i < scop1->n_array; ++i) {
952 		scop->arrays[i] = scop1->arrays[i];
953 		scop1->arrays[i] = NULL;
954 	}
955 
956 	for (i = 0; i < scop2->n_array; ++i) {
957 		scop->arrays[scop1->n_array + i] = scop2->arrays[i];
958 		scop2->arrays[i] = NULL;
959 	}
960 
961 	scop = scop_collect_implications(ctx, scop, scop1, scop2);
962 	scop = pet_scop_restrict_context(scop, isl_set_copy(scop1->context));
963 	scop = pet_scop_restrict_context(scop, isl_set_copy(scop2->context));
964 	scop = scop_combine_skips(scop, scop1, scop2);
965 	scop = scop_combine_start_end(scop, scop1, scop2);
966 	scop = scop_collect_independences(ctx, scop, scop1, scop2);
967 
968 	pet_scop_free(scop1);
969 	pet_scop_free(scop2);
970 	isl_schedule_free(schedule);
971 	return scop;
972 error:
973 	pet_scop_free(scop1);
974 	pet_scop_free(scop2);
975 	pet_scop_free(scop);
976 	isl_schedule_free(schedule);
977 	return NULL;
978 }
979 
980 /* Apply the skip condition "skip" to "scop".
981  * That is, make sure "scop" is not executed when the condition holds.
982  *
983  * If "skip" is an affine expression, we add the conditions under
984  * which the expression is zero to the context and the skip conditions
985  * of "scop".
986  * Otherwise, we add a filter on the variable attaining the value zero.
987  */
restrict_skip(struct pet_scop * scop,__isl_take isl_multi_pw_aff * skip)988 static struct pet_scop *restrict_skip(struct pet_scop *scop,
989 	__isl_take isl_multi_pw_aff *skip)
990 {
991 	isl_set *zero;
992 	isl_pw_aff *pa;
993 	int is_aff;
994 
995 	if (!scop || !skip)
996 		goto error;
997 
998 	is_aff = multi_pw_aff_is_affine(skip);
999 	if (is_aff < 0)
1000 		goto error;
1001 
1002 	if (!is_aff)
1003 		return pet_scop_filter(scop, skip, 0);
1004 
1005 	pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
1006 	isl_multi_pw_aff_free(skip);
1007 	zero = isl_pw_aff_zero_set(pa);
1008 	scop = pet_scop_restrict(scop, zero);
1009 
1010 	return scop;
1011 error:
1012 	isl_multi_pw_aff_free(skip);
1013 	return pet_scop_free(scop);
1014 }
1015 
1016 /* Construct a pet_scop that contains the arrays, statements and
1017  * skip information in "scop1" and "scop2", where the two scops
1018  * are executed "in sequence".  That is, breaks and continues
1019  * in scop1 have an effect on scop2 and the schedule of the result
1020  * is the sequence of the schedules of "scop1" and "scop2".
1021  */
pet_scop_add_seq(isl_ctx * ctx,struct pet_scop * scop1,struct pet_scop * scop2)1022 struct pet_scop *pet_scop_add_seq(isl_ctx *ctx, struct pet_scop *scop1,
1023 	struct pet_scop *scop2)
1024 {
1025 	isl_schedule *schedule;
1026 
1027 	if (!scop1 || !scop2)
1028 		goto error;
1029 
1030 	if (scop1 && pet_scop_has_skip(scop1, pet_skip_now))
1031 		scop2 = restrict_skip(scop2,
1032 					pet_scop_get_skip(scop1, pet_skip_now));
1033 	schedule = isl_schedule_sequence(isl_schedule_copy(scop1->schedule),
1034 					isl_schedule_copy(scop2->schedule));
1035 	return pet_scop_add(ctx, schedule, scop1, scop2);
1036 error:
1037 	pet_scop_free(scop1);
1038 	pet_scop_free(scop2);
1039 	return NULL;
1040 }
1041 
1042 /* Construct a pet_scop that contains the arrays, statements and
1043  * skip information in "scop1" and "scop2", where the two scops
1044  * are executed "in parallel".  That is, any break or continue
1045  * in scop1 has no effect on scop2 and the schedule of the result
1046  * is the set of the schedules of "scop1" and "scop2".
1047  */
pet_scop_add_par(isl_ctx * ctx,struct pet_scop * scop1,struct pet_scop * scop2)1048 struct pet_scop *pet_scop_add_par(isl_ctx *ctx, struct pet_scop *scop1,
1049 	struct pet_scop *scop2)
1050 {
1051 	isl_schedule *schedule;
1052 
1053 	if (!scop1 || !scop2)
1054 		goto error;
1055 
1056 	schedule = isl_schedule_set(isl_schedule_copy(scop1->schedule),
1057 					isl_schedule_copy(scop2->schedule));
1058 	return pet_scop_add(ctx, schedule, scop1, scop2);
1059 error:
1060 	pet_scop_free(scop1);
1061 	pet_scop_free(scop2);
1062 	return NULL;
1063 }
1064 
pet_implication_free(struct pet_implication * implication)1065 void *pet_implication_free(struct pet_implication *implication)
1066 {
1067 	if (!implication)
1068 		return NULL;
1069 
1070 	isl_map_free(implication->extension);
1071 
1072 	free(implication);
1073 	return NULL;
1074 }
1075 
pet_independence_free(struct pet_independence * independence)1076 void *pet_independence_free(struct pet_independence *independence)
1077 {
1078 	if (!independence)
1079 		return NULL;
1080 
1081 	isl_union_map_free(independence->filter);
1082 	isl_union_set_free(independence->local);
1083 
1084 	free(independence);
1085 	return NULL;
1086 }
1087 
pet_scop_free(struct pet_scop * scop)1088 struct pet_scop *pet_scop_free(struct pet_scop *scop)
1089 {
1090 	int i;
1091 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1092 
1093 	if (!scop)
1094 		return NULL;
1095 	pet_loc_free(scop->loc);
1096 	isl_set_free(scop->context);
1097 	isl_set_free(scop->context_value);
1098 	isl_schedule_free(scop->schedule);
1099 	if (scop->types)
1100 		for (i = 0; i < scop->n_type; ++i)
1101 			pet_type_free(scop->types[i]);
1102 	free(scop->types);
1103 	if (scop->arrays)
1104 		for (i = 0; i < scop->n_array; ++i)
1105 			pet_array_free(scop->arrays[i]);
1106 	free(scop->arrays);
1107 	if (scop->stmts)
1108 		for (i = 0; i < scop->n_stmt; ++i)
1109 			pet_stmt_free(scop->stmts[i]);
1110 	free(scop->stmts);
1111 	if (scop->implications)
1112 		for (i = 0; i < scop->n_implication; ++i)
1113 			pet_implication_free(scop->implications[i]);
1114 	free(scop->implications);
1115 	if (scop->independences)
1116 		for (i = 0; i < scop->n_independence; ++i)
1117 			pet_independence_free(scop->independences[i]);
1118 	free(scop->independences);
1119 	isl_multi_pw_aff_free(ext->skip[pet_skip_now]);
1120 	isl_multi_pw_aff_free(ext->skip[pet_skip_later]);
1121 	free(scop);
1122 	return NULL;
1123 }
1124 
pet_type_dump(struct pet_type * type)1125 void pet_type_dump(struct pet_type *type)
1126 {
1127 	if (!type)
1128 		return;
1129 
1130 	fprintf(stderr, "%s -> %s\n", type->name, type->definition);
1131 }
1132 
pet_implication_dump(struct pet_implication * implication)1133 void pet_implication_dump(struct pet_implication *implication)
1134 {
1135 	if (!implication)
1136 		return;
1137 
1138 	fprintf(stderr, "%d\n", implication->satisfied);
1139 	isl_map_dump(implication->extension);
1140 }
1141 
pet_scop_dump(struct pet_scop * scop)1142 void pet_scop_dump(struct pet_scop *scop)
1143 {
1144 	int i;
1145 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1146 
1147 	if (!scop)
1148 		return;
1149 
1150 	isl_set_dump(scop->context);
1151 	isl_set_dump(scop->context_value);
1152 	isl_schedule_dump(scop->schedule);
1153 	for (i = 0; i < scop->n_type; ++i)
1154 		pet_type_dump(scop->types[i]);
1155 	for (i = 0; i < scop->n_array; ++i)
1156 		pet_array_dump(scop->arrays[i]);
1157 	for (i = 0; i < scop->n_stmt; ++i)
1158 		pet_stmt_dump(scop->stmts[i]);
1159 	for (i = 0; i < scop->n_implication; ++i)
1160 		pet_implication_dump(scop->implications[i]);
1161 
1162 	if (ext->skip[0]) {
1163 		fprintf(stderr, "skip\n");
1164 		isl_multi_pw_aff_dump(ext->skip[0]);
1165 		isl_multi_pw_aff_dump(ext->skip[1]);
1166 	}
1167 }
1168 
1169 /* Return 1 if the two pet_arrays are equivalent.
1170  *
1171  * We don't compare element_size as this may be target dependent.
1172  */
pet_array_is_equal(struct pet_array * array1,struct pet_array * array2)1173 int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
1174 {
1175 	if (!array1 || !array2)
1176 		return 0;
1177 
1178 	if (!isl_set_is_equal(array1->context, array2->context))
1179 		return 0;
1180 	if (!isl_set_is_equal(array1->extent, array2->extent))
1181 		return 0;
1182 	if (!!array1->value_bounds != !!array2->value_bounds)
1183 		return 0;
1184 	if (array1->value_bounds &&
1185 	    !isl_set_is_equal(array1->value_bounds, array2->value_bounds))
1186 		return 0;
1187 	if (strcmp(array1->element_type, array2->element_type))
1188 		return 0;
1189 	if (array1->element_is_record != array2->element_is_record)
1190 		return 0;
1191 	if (array1->live_out != array2->live_out)
1192 		return 0;
1193 	if (array1->uniquely_defined != array2->uniquely_defined)
1194 		return 0;
1195 	if (array1->declared != array2->declared)
1196 		return 0;
1197 	if (array1->exposed != array2->exposed)
1198 		return 0;
1199 	if (array1->outer != array2->outer)
1200 		return 0;
1201 
1202 	return 1;
1203 }
1204 
1205 /* Return 1 if the two pet_stmts are equivalent.
1206  */
pet_stmt_is_equal(struct pet_stmt * stmt1,struct pet_stmt * stmt2)1207 int pet_stmt_is_equal(struct pet_stmt *stmt1, struct pet_stmt *stmt2)
1208 {
1209 	int i;
1210 
1211 	if (!stmt1 || !stmt2)
1212 		return 0;
1213 
1214 	if (pet_loc_get_line(stmt1->loc) != pet_loc_get_line(stmt2->loc))
1215 		return 0;
1216 	if (!isl_set_is_equal(stmt1->domain, stmt2->domain))
1217 		return 0;
1218 	if (!pet_tree_is_equal(stmt1->body, stmt2->body))
1219 		return 0;
1220 	if (stmt1->n_arg != stmt2->n_arg)
1221 		return 0;
1222 	for (i = 0; i < stmt1->n_arg; ++i) {
1223 		if (!pet_expr_is_equal(stmt1->args[i], stmt2->args[i]))
1224 			return 0;
1225 	}
1226 
1227 	return 1;
1228 }
1229 
1230 /* Return 1 if the two pet_types are equivalent.
1231  *
1232  * We only compare the names of the types since the exact representation
1233  * of the definition may depend on the version of clang being used.
1234  */
pet_type_is_equal(struct pet_type * type1,struct pet_type * type2)1235 int pet_type_is_equal(struct pet_type *type1, struct pet_type *type2)
1236 {
1237 	if (!type1 || !type2)
1238 		return 0;
1239 
1240 	if (strcmp(type1->name, type2->name))
1241 		return 0;
1242 
1243 	return 1;
1244 }
1245 
1246 /* Return 1 if the two pet_implications are equivalent.
1247  */
pet_implication_is_equal(struct pet_implication * implication1,struct pet_implication * implication2)1248 int pet_implication_is_equal(struct pet_implication *implication1,
1249 	struct pet_implication *implication2)
1250 {
1251 	if (!implication1 || !implication2)
1252 		return 0;
1253 
1254 	if (implication1->satisfied != implication2->satisfied)
1255 		return 0;
1256 	if (!isl_map_is_equal(implication1->extension, implication2->extension))
1257 		return 0;
1258 
1259 	return 1;
1260 }
1261 
1262 /* Return 1 if the two pet_independences are equivalent.
1263  */
pet_independence_is_equal(struct pet_independence * independence1,struct pet_independence * independence2)1264 int pet_independence_is_equal(struct pet_independence *independence1,
1265 	struct pet_independence *independence2)
1266 {
1267 	if (!independence1 || !independence2)
1268 		return 0;
1269 
1270 	if (!isl_union_map_is_equal(independence1->filter,
1271 					independence2->filter))
1272 		return 0;
1273 	if (!isl_union_set_is_equal(independence1->local, independence2->local))
1274 		return 0;
1275 
1276 	return 1;
1277 }
1278 
1279 /* Return 1 if the two pet_scops are equivalent.
1280  */
pet_scop_is_equal(struct pet_scop * scop1,struct pet_scop * scop2)1281 int pet_scop_is_equal(struct pet_scop *scop1, struct pet_scop *scop2)
1282 {
1283 	int i;
1284 	int equal;
1285 
1286 	if (!scop1 || !scop2)
1287 		return 0;
1288 
1289 	if (!isl_set_is_equal(scop1->context, scop2->context))
1290 		return 0;
1291 	if (!isl_set_is_equal(scop1->context_value, scop2->context_value))
1292 		return 0;
1293 	equal = isl_schedule_plain_is_equal(scop1->schedule, scop2->schedule);
1294 	if (equal < 0)
1295 		return -1;
1296 	if (!equal)
1297 		return 0;
1298 
1299 	if (scop1->n_type != scop2->n_type)
1300 		return 0;
1301 	for (i = 0; i < scop1->n_type; ++i)
1302 		if (!pet_type_is_equal(scop1->types[i], scop2->types[i]))
1303 			return 0;
1304 
1305 	if (scop1->n_array != scop2->n_array)
1306 		return 0;
1307 	for (i = 0; i < scop1->n_array; ++i)
1308 		if (!pet_array_is_equal(scop1->arrays[i], scop2->arrays[i]))
1309 			return 0;
1310 
1311 	if (scop1->n_stmt != scop2->n_stmt)
1312 		return 0;
1313 	for (i = 0; i < scop1->n_stmt; ++i)
1314 		if (!pet_stmt_is_equal(scop1->stmts[i], scop2->stmts[i]))
1315 			return 0;
1316 
1317 	if (scop1->n_implication != scop2->n_implication)
1318 		return 0;
1319 	for (i = 0; i < scop1->n_implication; ++i)
1320 		if (!pet_implication_is_equal(scop1->implications[i],
1321 						scop2->implications[i]))
1322 			return 0;
1323 
1324 	if (scop1->n_independence != scop2->n_independence)
1325 		return 0;
1326 	for (i = 0; i < scop1->n_independence; ++i)
1327 		if (!pet_independence_is_equal(scop1->independences[i],
1328 						scop2->independences[i]))
1329 			return 0;
1330 
1331 	return 1;
1332 }
1333 
1334 /* Does the set "extent" reference a virtual array, i.e.,
1335  * one with user pointer equal to NULL?
1336  * A virtual array does not have any members.
1337  */
extent_is_virtual_array(__isl_keep isl_set * extent)1338 static int extent_is_virtual_array(__isl_keep isl_set *extent)
1339 {
1340 	isl_id *id;
1341 	int is_virtual;
1342 
1343 	if (!isl_set_has_tuple_id(extent))
1344 		return 0;
1345 	if (isl_set_is_wrapping(extent))
1346 		return 0;
1347 	id = isl_set_get_tuple_id(extent);
1348 	is_virtual = !isl_id_get_user(id);
1349 	isl_id_free(id);
1350 
1351 	return is_virtual;
1352 }
1353 
1354 /* Intersect the initial dimensions of "array" with "domain", provided
1355  * that "array" represents a virtual array.
1356  *
1357  * If "array" is virtual, then We take the preimage of "domain"
1358  * over the projection of the extent of "array" onto its initial dimensions
1359  * and intersect this extent with the result.
1360  */
virtual_array_intersect_domain_prefix(struct pet_array * array,__isl_take isl_set * domain)1361 static struct pet_array *virtual_array_intersect_domain_prefix(
1362 	struct pet_array *array, __isl_take isl_set *domain)
1363 {
1364 	int n;
1365 	isl_space *space;
1366 	isl_multi_aff *ma;
1367 
1368 	if (!array || !extent_is_virtual_array(array->extent)) {
1369 		isl_set_free(domain);
1370 		return array;
1371 	}
1372 
1373 	space = isl_set_get_space(array->extent);
1374 	n = isl_set_dim(domain, isl_dim_set);
1375 	ma = pet_prefix_projection(space, n);
1376 	domain = isl_set_preimage_multi_aff(domain, ma);
1377 
1378 	array->extent = isl_set_intersect(array->extent, domain);
1379 	if (!array->extent)
1380 		return pet_array_free(array);
1381 
1382 	return array;
1383 }
1384 
1385 /* Intersect the initial dimensions of the domain of "stmt"
1386  * with "domain".
1387  *
1388  * We take the preimage of "domain" over the projection of the
1389  * domain of "stmt" onto its initial dimensions and intersect
1390  * the domain of "stmt" with the result.
1391  */
stmt_intersect_domain_prefix(struct pet_stmt * stmt,__isl_take isl_set * domain)1392 static struct pet_stmt *stmt_intersect_domain_prefix(struct pet_stmt *stmt,
1393 	__isl_take isl_set *domain)
1394 {
1395 	int n;
1396 	isl_space *space;
1397 	isl_multi_aff *ma;
1398 
1399 	if (!stmt)
1400 		goto error;
1401 
1402 	space = isl_set_get_space(stmt->domain);
1403 	n = isl_set_dim(domain, isl_dim_set);
1404 	ma = pet_prefix_projection(space, n);
1405 	domain = isl_set_preimage_multi_aff(domain, ma);
1406 
1407 	stmt->domain = isl_set_intersect(stmt->domain, domain);
1408 	if (!stmt->domain)
1409 		return pet_stmt_free(stmt);
1410 
1411 	return stmt;
1412 error:
1413 	isl_set_free(domain);
1414 	return pet_stmt_free(stmt);
1415 }
1416 
1417 /* Intersect the initial dimensions of the domain of "implication"
1418  * with "domain".
1419  *
1420  * We take the preimage of "domain" over the projection of the
1421  * domain of "implication" onto its initial dimensions and intersect
1422  * the domain of "implication" with the result.
1423  */
implication_intersect_domain_prefix(struct pet_implication * implication,__isl_take isl_set * domain)1424 static struct pet_implication *implication_intersect_domain_prefix(
1425 	struct pet_implication *implication, __isl_take isl_set *domain)
1426 {
1427 	int n;
1428 	isl_space *space;
1429 	isl_multi_aff *ma;
1430 
1431 	if (!implication)
1432 		goto error;
1433 
1434 	space = isl_map_get_space(implication->extension);
1435 	n = isl_set_dim(domain, isl_dim_set);
1436 	ma = pet_prefix_projection(isl_space_domain(space), n);
1437 	domain = isl_set_preimage_multi_aff(domain, ma);
1438 
1439 	implication->extension =
1440 		isl_map_intersect_domain(implication->extension, domain);
1441 	if (!implication->extension)
1442 		return pet_implication_free(implication);
1443 
1444 	return implication;
1445 error:
1446 	isl_set_free(domain);
1447 	return pet_implication_free(implication);
1448 }
1449 
1450 /* Intersect the initial dimensions of the domains in "scop" with "domain".
1451  *
1452  * The extents of the virtual arrays match the iteration domains,
1453  * so if the iteration domain changes, we need to change those extents too.
1454  *
1455  * The domain of the schedule is intersected with (i.e., replaced by)
1456  * the union of the updated iteration domains.
1457  */
pet_scop_intersect_domain_prefix(struct pet_scop * scop,__isl_take isl_set * domain)1458 struct pet_scop *pet_scop_intersect_domain_prefix(struct pet_scop *scop,
1459 	__isl_take isl_set *domain)
1460 {
1461 	int i;
1462 
1463 	if (!scop)
1464 		goto error;
1465 
1466 	for (i = 0; i < scop->n_array; ++i) {
1467 		scop->arrays[i] = virtual_array_intersect_domain_prefix(
1468 					scop->arrays[i], isl_set_copy(domain));
1469 		if (!scop->arrays[i])
1470 			goto error;
1471 	}
1472 
1473 	for (i = 0; i < scop->n_stmt; ++i) {
1474 		scop->stmts[i] = stmt_intersect_domain_prefix(scop->stmts[i],
1475 						    isl_set_copy(domain));
1476 		if (!scop->stmts[i])
1477 			goto error;
1478 	}
1479 
1480 	for (i = 0; i < scop->n_implication; ++i) {
1481 		scop->implications[i] =
1482 		    implication_intersect_domain_prefix(scop->implications[i],
1483 						    isl_set_copy(domain));
1484 		if (!scop->implications[i])
1485 			return pet_scop_free(scop);
1486 	}
1487 
1488 	scop->schedule = isl_schedule_intersect_domain(scop->schedule,
1489 					    pet_scop_get_instance_set(scop));
1490 	if (!scop->schedule)
1491 		goto error;
1492 
1493 	isl_set_free(domain);
1494 	return scop;
1495 error:
1496 	isl_set_free(domain);
1497 	return pet_scop_free(scop);
1498 }
1499 
1500 /* Update the context with respect to an embedding into a loop
1501  * with iteration domain "dom".
1502  * The input context lives in the same space as "dom".
1503  * The output context has the inner dimension removed.
1504  *
1505  * An outer loop iterator value is invalid for the embedding if
1506  * any of the corresponding inner iterator values is invalid.
1507  * That is, an outer loop iterator value is valid only if all the corresponding
1508  * inner iterator values are valid.
1509  * We therefore compute the set of outer loop iterators l
1510  *
1511  *	forall i: dom(l,i) => valid(l,i)
1512  *
1513  * or
1514  *
1515  *	forall i: not dom(l,i) or valid(l,i)
1516  *
1517  * or
1518  *
1519  *	not exists i: dom(l,i) and not valid(l,i)
1520  *
1521  * i.e.,
1522  *
1523  *	not exists i: (dom \ valid)(l,i)
1524  *
1525  * If there are any unnamed parameters in "dom", then we consider
1526  * a parameter value to be valid if it is valid for any value of those
1527  * unnamed parameters.  They are therefore projected out at the end.
1528  */
context_embed(__isl_take isl_set * context,__isl_keep isl_set * dom)1529 static __isl_give isl_set *context_embed(__isl_take isl_set *context,
1530 	__isl_keep isl_set *dom)
1531 {
1532 	int pos;
1533 
1534 	pos = isl_set_dim(context, isl_dim_set) - 1;
1535 	context = isl_set_subtract(isl_set_copy(dom), context);
1536 	context = isl_set_project_out(context, isl_dim_set, pos, 1);
1537 	context = isl_set_complement(context);
1538 	context = pet_nested_remove_from_set(context);
1539 
1540 	return context;
1541 }
1542 
1543 /* Internal data structure for outer_projection_mupa.
1544  *
1545  * "n" is the number of outer dimensions onto which to project.
1546  * "res" collects the result.
1547  */
1548 struct pet_outer_projection_data {
1549 	int n;
1550 	isl_union_pw_multi_aff *res;
1551 };
1552 
1553 /* Create a function that maps "set" onto its outer data->n dimensions and
1554  * add it to data->res.
1555  */
add_outer_projection(__isl_take isl_set * set,void * user)1556 static isl_stat add_outer_projection(__isl_take isl_set *set, void *user)
1557 {
1558 	struct pet_outer_projection_data *data = user;
1559 	int dim;
1560 	isl_space *space;
1561 	isl_pw_multi_aff *pma;
1562 
1563 	dim = isl_set_dim(set, isl_dim_set);
1564 	space = isl_set_get_space(set);
1565 	pma = isl_pw_multi_aff_project_out_map(space,
1566 					isl_dim_set, data->n, dim - data->n);
1567 	data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);
1568 
1569 	isl_set_free(set);
1570 
1571 	return isl_stat_ok;
1572 }
1573 
1574 /* Create and return a function that maps the sets in "domain"
1575  * onto their outer "n" dimensions.
1576  */
outer_projection_mupa(__isl_take isl_union_set * domain,int n)1577 static __isl_give isl_multi_union_pw_aff *outer_projection_mupa(
1578 	__isl_take isl_union_set *domain, int n)
1579 {
1580 	struct pet_outer_projection_data data;
1581 	isl_space *space;
1582 
1583 	space = isl_union_set_get_space(domain);
1584 	data.n = n;
1585 	data.res = isl_union_pw_multi_aff_empty(space);
1586 	if (isl_union_set_foreach_set(domain, &add_outer_projection, &data) < 0)
1587 		data.res = isl_union_pw_multi_aff_free(data.res);
1588 
1589 	isl_union_set_free(domain);
1590 	return isl_multi_union_pw_aff_from_union_pw_multi_aff(data.res);
1591 }
1592 
1593 /* Embed "schedule" in a loop with schedule "prefix".
1594  * The domain of "prefix" corresponds to the outer dimensions
1595  * of the iteration domains.
1596  * We therefore construct a projection onto these outer dimensions,
1597  * compose it with "prefix" and then add the result as a band schedule.
1598  *
1599  * If the domain of the schedule is empty, then there is no need
1600  * to insert any node.
1601  */
schedule_embed(__isl_take isl_schedule * schedule,__isl_keep isl_multi_aff * prefix)1602 static __isl_give isl_schedule *schedule_embed(
1603 	__isl_take isl_schedule *schedule, __isl_keep isl_multi_aff *prefix)
1604 {
1605 	int n;
1606 	int empty;
1607 	isl_union_set *domain;
1608 	isl_multi_aff *ma;
1609 	isl_multi_union_pw_aff *mupa;
1610 
1611 	domain = isl_schedule_get_domain(schedule);
1612 	empty = isl_union_set_is_empty(domain);
1613 	if (empty < 0 || empty) {
1614 		isl_union_set_free(domain);
1615 		return empty < 0 ? isl_schedule_free(schedule) : schedule;
1616 	}
1617 
1618 	n = isl_multi_aff_dim(prefix, isl_dim_in);
1619 	mupa = outer_projection_mupa(domain, n);
1620 	ma = isl_multi_aff_copy(prefix);
1621 	mupa = isl_multi_union_pw_aff_apply_multi_aff(mupa, ma);
1622 	schedule = isl_schedule_insert_partial_schedule(schedule, mupa);
1623 
1624 	return schedule;
1625 }
1626 
1627 /* Adjust the context and the schedule according to an embedding
1628  * in a loop with iteration domain "dom" and schedule "sched".
1629  */
pet_scop_embed(struct pet_scop * scop,__isl_take isl_set * dom,__isl_take isl_multi_aff * sched)1630 struct pet_scop *pet_scop_embed(struct pet_scop *scop, __isl_take isl_set *dom,
1631 	__isl_take isl_multi_aff *sched)
1632 {
1633 	if (!scop)
1634 		goto error;
1635 
1636 	scop->context = context_embed(scop->context, dom);
1637 	if (!scop->context)
1638 		goto error;
1639 
1640 	scop->schedule = schedule_embed(scop->schedule, sched);
1641 	if (!scop->schedule)
1642 		goto error;
1643 
1644 	isl_set_free(dom);
1645 	isl_multi_aff_free(sched);
1646 	return scop;
1647 error:
1648 	isl_set_free(dom);
1649 	isl_multi_aff_free(sched);
1650 	return pet_scop_free(scop);
1651 }
1652 
1653 /* Add extra conditions to scop->skip[type].
1654  *
1655  * The new skip condition only holds if it held before
1656  * and the condition is true.  It does not hold if it did not hold
1657  * before or the condition is false.
1658  *
1659  * The skip condition is assumed to be an affine expression.
1660  */
pet_scop_restrict_skip(struct pet_scop * scop,enum pet_skip type,__isl_keep isl_set * cond)1661 static struct pet_scop *pet_scop_restrict_skip(struct pet_scop *scop,
1662 	enum pet_skip type, __isl_keep isl_set *cond)
1663 {
1664 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1665 	isl_pw_aff *skip;
1666 	isl_set *dom;
1667 
1668 	if (!scop)
1669 		return NULL;
1670 	if (!ext->skip[type])
1671 		return scop;
1672 
1673 	if (!multi_pw_aff_is_affine(ext->skip[type]))
1674 		isl_die(isl_multi_pw_aff_get_ctx(ext->skip[type]),
1675 			isl_error_internal, "can only restrict affine skips",
1676 			return pet_scop_free(scop));
1677 
1678 	skip = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
1679 	dom = isl_pw_aff_domain(isl_pw_aff_copy(skip));
1680 	cond = isl_set_copy(cond);
1681 	cond = isl_set_intersect(cond, isl_pw_aff_non_zero_set(skip));
1682 	skip = indicator_function(cond, dom);
1683 	isl_multi_pw_aff_free(ext->skip[type]);
1684 	ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
1685 	if (!ext->skip[type])
1686 		return pet_scop_free(scop);
1687 
1688 	return scop;
1689 }
1690 
1691 /* Adjust the context and the skip conditions to the fact that
1692  * the scop was created in a context where "cond" holds.
1693  *
1694  * An outer loop iterator or parameter value is valid for the result
1695  * if it was valid for the original scop and satisfies "cond" or if it does
1696  * not satisfy "cond" as in this case the scop is not executed
1697  * and the original constraints on these values are irrelevant.
1698  */
pet_scop_restrict(struct pet_scop * scop,__isl_take isl_set * cond)1699 struct pet_scop *pet_scop_restrict(struct pet_scop *scop,
1700 	__isl_take isl_set *cond)
1701 {
1702 	scop = pet_scop_restrict_skip(scop, pet_skip_now, cond);
1703 	scop = pet_scop_restrict_skip(scop, pet_skip_later, cond);
1704 
1705 	if (!scop)
1706 		goto error;
1707 
1708 	scop->context = isl_set_intersect(scop->context, isl_set_copy(cond));
1709 	scop->context = isl_set_union(scop->context,
1710 				isl_set_complement(isl_set_copy(cond)));
1711 	scop->context = isl_set_coalesce(scop->context);
1712 	scop->context = pet_nested_remove_from_set(scop->context);
1713 	if (!scop->context)
1714 		goto error;
1715 
1716 	isl_set_free(cond);
1717 	return scop;
1718 error:
1719 	isl_set_free(cond);
1720 	return pet_scop_free(scop);
1721 }
1722 
1723 /* Insert an argument expression corresponding to "test" in front
1724  * of the list of arguments described by *n_arg and *args.
1725  */
args_insert_access(unsigned * n_arg,pet_expr *** args,__isl_keep isl_multi_pw_aff * test)1726 static int args_insert_access(unsigned *n_arg, pet_expr ***args,
1727 	__isl_keep isl_multi_pw_aff *test)
1728 {
1729 	int i;
1730 	isl_ctx *ctx = isl_multi_pw_aff_get_ctx(test);
1731 
1732 	if (!test)
1733 		return -1;
1734 
1735 	if (!*args) {
1736 		*args = isl_calloc_array(ctx, pet_expr *, 1);
1737 		if (!*args)
1738 			return -1;
1739 	} else {
1740 		pet_expr **ext;
1741 		ext = isl_calloc_array(ctx, pet_expr *, 1 + *n_arg);
1742 		if (!ext)
1743 			return -1;
1744 		for (i = 0; i < *n_arg; ++i)
1745 			ext[1 + i] = (*args)[i];
1746 		free(*args);
1747 		*args = ext;
1748 	}
1749 	(*n_arg)++;
1750 	(*args)[0] = pet_expr_from_index(isl_multi_pw_aff_copy(test));
1751 	if (!(*args)[0])
1752 		return -1;
1753 
1754 	return 0;
1755 }
1756 
1757 /* Look through the applications in "scop" for any that can be
1758  * applied to the filter expressed by "map" and "satisified".
1759  * If there is any, then apply it to "map" and return the result.
1760  * Otherwise, return "map".
1761  * "id" is the identifier of the virtual array.
1762  *
1763  * We only introduce at most one implication for any given virtual array,
1764  * so we can apply the implication and return as soon as we find one.
1765  */
apply_implications(struct pet_scop * scop,__isl_take isl_map * map,__isl_keep isl_id * id,int satisfied)1766 static __isl_give isl_map *apply_implications(struct pet_scop *scop,
1767 	__isl_take isl_map *map, __isl_keep isl_id *id, int satisfied)
1768 {
1769 	int i;
1770 
1771 	for (i = 0; i < scop->n_implication; ++i) {
1772 		struct pet_implication *pi = scop->implications[i];
1773 		isl_id *pi_id;
1774 
1775 		if (pi->satisfied != satisfied)
1776 			continue;
1777 		pi_id = isl_map_get_tuple_id(pi->extension, isl_dim_in);
1778 		isl_id_free(pi_id);
1779 		if (pi_id != id)
1780 			continue;
1781 
1782 		return isl_map_apply_range(map, isl_map_copy(pi->extension));
1783 	}
1784 
1785 	return map;
1786 }
1787 
1788 /* Is the filter expressed by "test" and "satisfied" implied
1789  * by filter "pos" on "domain", with filter "expr", taking into
1790  * account the implications of "scop"?
1791  *
1792  * For filter on domain implying that expressed by "test" and "satisfied",
1793  * the filter needs to be an access to the same (virtual) array as "test" and
1794  * the filter value needs to be equal to "satisfied".
1795  * Moreover, the filter access relation, possibly extended by
1796  * the implications in "scop" needs to contain "test".
1797  */
implies_filter(struct pet_scop * scop,__isl_keep isl_map * domain,int pos,__isl_keep pet_expr * expr,__isl_keep isl_map * test,int satisfied)1798 static int implies_filter(struct pet_scop *scop,
1799 	__isl_keep isl_map *domain, int pos, __isl_keep pet_expr *expr,
1800 	__isl_keep isl_map *test, int satisfied)
1801 {
1802 	isl_id *test_id, *arg_id;
1803 	isl_val *val;
1804 	int is_int;
1805 	int s;
1806 	int is_subset;
1807 	isl_map *implied;
1808 
1809 	if (expr->type != pet_expr_access)
1810 		return 0;
1811 	test_id = isl_map_get_tuple_id(test, isl_dim_out);
1812 	arg_id = pet_expr_access_get_id(expr);
1813 	isl_id_free(arg_id);
1814 	isl_id_free(test_id);
1815 	if (test_id != arg_id)
1816 		return 0;
1817 	val = isl_map_plain_get_val_if_fixed(domain, isl_dim_out, pos);
1818 	is_int = isl_val_is_int(val);
1819 	if (is_int)
1820 		s = isl_val_get_num_si(val);
1821 	isl_val_free(val);
1822 	if (!val)
1823 		return -1;
1824 	if (!is_int)
1825 		return 0;
1826 	if (s != satisfied)
1827 		return 0;
1828 
1829 	implied = isl_map_from_multi_pw_aff(pet_expr_access_get_index(expr));
1830 	implied = apply_implications(scop, implied, test_id, satisfied);
1831 	is_subset = isl_map_is_subset(test, implied);
1832 	isl_map_free(implied);
1833 
1834 	return is_subset;
1835 }
1836 
1837 /* Is the filter expressed by "test" and "satisfied" implied
1838  * by any of the filters on the domain of "stmt", taking into
1839  * account the implications of "scop"?
1840  */
filter_implied(struct pet_scop * scop,struct pet_stmt * stmt,__isl_keep isl_multi_pw_aff * test,int satisfied)1841 static int filter_implied(struct pet_scop *scop,
1842 	struct pet_stmt *stmt, __isl_keep isl_multi_pw_aff *test, int satisfied)
1843 {
1844 	int i;
1845 	int implied;
1846 	isl_map *domain;
1847 	isl_map *test_map;
1848 
1849 	if (!scop || !stmt || !test)
1850 		return -1;
1851 	if (scop->n_implication == 0)
1852 		return 0;
1853 	if (stmt->n_arg == 0)
1854 		return 0;
1855 
1856 	domain = isl_set_unwrap(isl_set_copy(stmt->domain));
1857 	test_map = isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(test));
1858 
1859 	implied = 0;
1860 	for (i = 0; i < stmt->n_arg; ++i) {
1861 		implied = implies_filter(scop, domain, i, stmt->args[i],
1862 					 test_map, satisfied);
1863 		if (implied < 0 || implied)
1864 			break;
1865 	}
1866 
1867 	isl_map_free(test_map);
1868 	isl_map_free(domain);
1869 	return implied;
1870 }
1871 
1872 /* Make the statement "stmt" depend on the value of "test"
1873  * being equal to "satisfied" by adjusting stmt->domain.
1874  *
1875  * The domain of "test" corresponds to the (zero or more) outer dimensions
1876  * of the iteration domain.
1877  *
1878  * We first extend "test" to apply to the entire iteration domain and
1879  * then check if the filter that we are about to add is implied
1880  * by any of the current filters, possibly taking into account
1881  * the implications in "scop".  If so, we leave "stmt" untouched and return.
1882  *
1883  * Otherwise, we insert an argument corresponding to a read to "test"
1884  * from the iteration domain of "stmt" in front of the list of arguments.
1885  * We also insert a corresponding output dimension in the wrapped
1886  * map contained in stmt->domain, with value set to "satisfied".
1887  */
stmt_filter(struct pet_scop * scop,struct pet_stmt * stmt,__isl_take isl_multi_pw_aff * test,int satisfied)1888 static struct pet_stmt *stmt_filter(struct pet_scop *scop,
1889 	struct pet_stmt *stmt, __isl_take isl_multi_pw_aff *test, int satisfied)
1890 {
1891 	int i;
1892 	int implied;
1893 	isl_id *id;
1894 	isl_pw_multi_aff *pma;
1895 	isl_multi_aff *add_dom;
1896 	isl_space *space;
1897 	isl_local_space *ls;
1898 	int n_test_dom;
1899 
1900 	if (!stmt || !test)
1901 		goto error;
1902 
1903 	space = pet_stmt_get_space(stmt);
1904 	n_test_dom = isl_multi_pw_aff_dim(test, isl_dim_in);
1905 	space = isl_space_from_domain(space);
1906 	space = isl_space_add_dims(space, isl_dim_out, n_test_dom);
1907 	add_dom = isl_multi_aff_zero(isl_space_copy(space));
1908 	ls = isl_local_space_from_space(isl_space_domain(space));
1909 	for (i = 0; i < n_test_dom; ++i) {
1910 		isl_aff *aff;
1911 		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
1912 					    isl_dim_set, i);
1913 		add_dom = isl_multi_aff_set_aff(add_dom, i, aff);
1914 	}
1915 	isl_local_space_free(ls);
1916 	test = isl_multi_pw_aff_pullback_multi_aff(test, add_dom);
1917 
1918 	implied = filter_implied(scop, stmt, test, satisfied);
1919 	if (implied < 0)
1920 		goto error;
1921 	if (implied) {
1922 		isl_multi_pw_aff_free(test);
1923 		return stmt;
1924 	}
1925 
1926 	id = isl_multi_pw_aff_get_tuple_id(test, isl_dim_out);
1927 	pma = pet_filter_insert_pma(isl_set_get_space(stmt->domain),
1928 					id, satisfied);
1929 	stmt->domain = isl_set_preimage_pw_multi_aff(stmt->domain, pma);
1930 
1931 	if (args_insert_access(&stmt->n_arg, &stmt->args, test) < 0)
1932 		goto error;
1933 
1934 	isl_multi_pw_aff_free(test);
1935 	return stmt;
1936 error:
1937 	isl_multi_pw_aff_free(test);
1938 	return pet_stmt_free(stmt);
1939 }
1940 
1941 /* Does "scop" have a skip condition of the given "type"?
1942  */
pet_scop_has_skip(struct pet_scop * scop,enum pet_skip type)1943 int pet_scop_has_skip(struct pet_scop *scop, enum pet_skip type)
1944 {
1945 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1946 
1947 	if (!scop)
1948 		return -1;
1949 	return ext->skip[type] != NULL;
1950 }
1951 
1952 /* Does "scop" have a skip condition of the given "type" that
1953  * is an affine expression?
1954  */
pet_scop_has_affine_skip(struct pet_scop * scop,enum pet_skip type)1955 int pet_scop_has_affine_skip(struct pet_scop *scop, enum pet_skip type)
1956 {
1957 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1958 
1959 	if (!scop)
1960 		return -1;
1961 	if (!ext->skip[type])
1962 		return 0;
1963 	return multi_pw_aff_is_affine(ext->skip[type]);
1964 }
1965 
1966 /* Does "scop" have a skip condition of the given "type" that
1967  * is not an affine expression?
1968  */
pet_scop_has_var_skip(struct pet_scop * scop,enum pet_skip type)1969 int pet_scop_has_var_skip(struct pet_scop *scop, enum pet_skip type)
1970 {
1971 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1972 	int aff;
1973 
1974 	if (!scop)
1975 		return -1;
1976 	if (!ext->skip[type])
1977 		return 0;
1978 	aff = multi_pw_aff_is_affine(ext->skip[type]);
1979 	if (aff < 0)
1980 		return -1;
1981 	return !aff;
1982 }
1983 
1984 /* Does "scop" have a skip condition of the given "type" that
1985  * is affine and holds on the entire domain?
1986  */
pet_scop_has_universal_skip(struct pet_scop * scop,enum pet_skip type)1987 int pet_scop_has_universal_skip(struct pet_scop *scop, enum pet_skip type)
1988 {
1989 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1990 	isl_pw_aff *pa;
1991 	isl_set *set;
1992 	int is_aff;
1993 	int is_univ;
1994 
1995 	is_aff = pet_scop_has_affine_skip(scop, type);
1996 	if (is_aff < 0 || !is_aff)
1997 		return is_aff;
1998 
1999 	pa = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
2000 	set = isl_pw_aff_non_zero_set(pa);
2001 	is_univ = isl_set_plain_is_universe(set);
2002 	isl_set_free(set);
2003 
2004 	return is_univ;
2005 }
2006 
2007 /* Replace scop->skip[type] by "skip".
2008  */
pet_scop_set_skip(struct pet_scop * scop,enum pet_skip type,__isl_take isl_multi_pw_aff * skip)2009 struct pet_scop *pet_scop_set_skip(struct pet_scop *scop,
2010 	enum pet_skip type, __isl_take isl_multi_pw_aff *skip)
2011 {
2012 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2013 
2014 	if (!scop || !skip)
2015 		goto error;
2016 
2017 	isl_multi_pw_aff_free(ext->skip[type]);
2018 	ext->skip[type] = skip;
2019 
2020 	return scop;
2021 error:
2022 	isl_multi_pw_aff_free(skip);
2023 	return pet_scop_free(scop);
2024 }
2025 
2026 /* Return a copy of scop->skip[type].
2027  */
pet_scop_get_skip(struct pet_scop * scop,enum pet_skip type)2028 __isl_give isl_multi_pw_aff *pet_scop_get_skip(struct pet_scop *scop,
2029 	enum pet_skip type)
2030 {
2031 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2032 
2033 	if (!scop)
2034 		return NULL;
2035 
2036 	return isl_multi_pw_aff_copy(ext->skip[type]);
2037 }
2038 
2039 /* Assuming scop->skip[type] is an affine expression,
2040  * return the constraints on the outer loop domain for which the skip condition
2041  * holds.
2042  */
pet_scop_get_affine_skip_domain(struct pet_scop * scop,enum pet_skip type)2043 __isl_give isl_set *pet_scop_get_affine_skip_domain(struct pet_scop *scop,
2044 	enum pet_skip type)
2045 {
2046 	isl_multi_pw_aff *skip;
2047 	isl_pw_aff *pa;
2048 
2049 	skip = pet_scop_get_skip(scop, type);
2050 	pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
2051 	isl_multi_pw_aff_free(skip);
2052 	return isl_pw_aff_non_zero_set(pa);
2053 }
2054 
2055 /* Return the identifier of the variable that is accessed by
2056  * the skip condition of the given type.
2057  *
2058  * The skip condition is assumed not to be an affine condition.
2059  */
pet_scop_get_skip_id(struct pet_scop * scop,enum pet_skip type)2060 __isl_give isl_id *pet_scop_get_skip_id(struct pet_scop *scop,
2061 	enum pet_skip type)
2062 {
2063 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2064 
2065 	if (!scop)
2066 		return NULL;
2067 
2068 	return isl_multi_pw_aff_get_tuple_id(ext->skip[type], isl_dim_out);
2069 }
2070 
2071 /* Return an access pet_expr corresponding to the skip condition
2072  * of the given type.
2073  */
pet_scop_get_skip_expr(struct pet_scop * scop,enum pet_skip type)2074 __isl_give pet_expr *pet_scop_get_skip_expr(struct pet_scop *scop,
2075 	enum pet_skip type)
2076 {
2077 	return pet_expr_from_index(pet_scop_get_skip(scop, type));
2078 }
2079 
2080 /* Drop the skip condition scop->skip[type].
2081  */
pet_scop_reset_skip(struct pet_scop * scop,enum pet_skip type)2082 void pet_scop_reset_skip(struct pet_scop *scop, enum pet_skip type)
2083 {
2084 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2085 
2086 	if (!scop)
2087 		return;
2088 
2089 	isl_multi_pw_aff_free(ext->skip[type]);
2090 	ext->skip[type] = NULL;
2091 }
2092 
2093 /* Drop all skip conditions on "scop".
2094  */
pet_scop_reset_skips(struct pet_scop * scop)2095 struct pet_scop *pet_scop_reset_skips(struct pet_scop *scop)
2096 {
2097 	pet_scop_reset_skip(scop, pet_skip_now);
2098 	pet_scop_reset_skip(scop, pet_skip_later);
2099 
2100 	return scop;
2101 }
2102 
2103 /* Make the skip condition (if any) depend on the value of "test" being
2104  * equal to "satisfied".
2105  *
2106  * We only support the case where the original skip condition is universal,
2107  * i.e., where skipping is unconditional, and where satisfied == 1.
2108  * In this case, the skip condition is changed to skip only when
2109  * "test" is equal to one.
2110  */
pet_scop_filter_skip(struct pet_scop * scop,enum pet_skip type,__isl_keep isl_multi_pw_aff * test,int satisfied)2111 static struct pet_scop *pet_scop_filter_skip(struct pet_scop *scop,
2112 	enum pet_skip type, __isl_keep isl_multi_pw_aff *test, int satisfied)
2113 {
2114 	int is_univ = 0;
2115 
2116 	if (!scop)
2117 		return NULL;
2118 	if (!pet_scop_has_skip(scop, type))
2119 		return scop;
2120 
2121 	if (satisfied)
2122 		is_univ = pet_scop_has_universal_skip(scop, type);
2123 	if (is_univ < 0)
2124 		return pet_scop_free(scop);
2125 	if (satisfied && is_univ) {
2126 		isl_multi_pw_aff *skip;
2127 		skip = isl_multi_pw_aff_copy(test);
2128 		scop = pet_scop_set_skip(scop, type, skip);
2129 		if (!scop)
2130 			return NULL;
2131 	} else {
2132 		isl_die(isl_multi_pw_aff_get_ctx(test), isl_error_internal,
2133 			"skip expression cannot be filtered",
2134 			return pet_scop_free(scop));
2135 	}
2136 
2137 	return scop;
2138 }
2139 
2140 /* Make all statements in "scop" depend on the value of "test"
2141  * being equal to "satisfied" by adjusting their domains.
2142  */
pet_scop_filter(struct pet_scop * scop,__isl_take isl_multi_pw_aff * test,int satisfied)2143 struct pet_scop *pet_scop_filter(struct pet_scop *scop,
2144 	__isl_take isl_multi_pw_aff *test, int satisfied)
2145 {
2146 	int i;
2147 
2148 	scop = pet_scop_filter_skip(scop, pet_skip_now, test, satisfied);
2149 	scop = pet_scop_filter_skip(scop, pet_skip_later, test, satisfied);
2150 
2151 	if (!scop || !test)
2152 		goto error;
2153 
2154 	for (i = 0; i < scop->n_stmt; ++i) {
2155 		scop->stmts[i] = stmt_filter(scop, scop->stmts[i],
2156 					isl_multi_pw_aff_copy(test), satisfied);
2157 		if (!scop->stmts[i])
2158 			goto error;
2159 	}
2160 
2161 	isl_multi_pw_aff_free(test);
2162 	return scop;
2163 error:
2164 	isl_multi_pw_aff_free(test);
2165 	return pet_scop_free(scop);
2166 }
2167 
2168 /* Add the parameters of the access expression "expr" to "space".
2169  */
access_collect_params(__isl_keep pet_expr * expr,void * user)2170 static int access_collect_params(__isl_keep pet_expr *expr, void *user)
2171 {
2172 	isl_space *expr_space;
2173 	isl_space **space = user;
2174 
2175 	expr_space = pet_expr_access_get_parameter_space(expr);
2176 	*space = isl_space_align_params(*space, expr_space);
2177 
2178 	return *space ? 0 : -1;
2179 }
2180 
2181 /* Add all parameters in "stmt" to "space" and return the result.
2182  */
stmt_collect_params(struct pet_stmt * stmt,__isl_take isl_space * space)2183 static __isl_give isl_space *stmt_collect_params(struct pet_stmt *stmt,
2184 	__isl_take isl_space *space)
2185 {
2186 	int i;
2187 
2188 	if (!stmt)
2189 		return isl_space_free(space);
2190 
2191 	space = isl_space_align_params(space, isl_set_get_space(stmt->domain));
2192 	for (i = 0; i < stmt->n_arg; ++i)
2193 		if (pet_expr_foreach_access_expr(stmt->args[i],
2194 					&access_collect_params, &space) < 0)
2195 			space = isl_space_free(space);
2196 	if (pet_tree_foreach_access_expr(stmt->body, &access_collect_params,
2197 					&space) < 0)
2198 		space = isl_space_free(space);
2199 
2200 	return space;
2201 }
2202 
2203 /* Add all parameters in "array" to "space" and return the result.
2204  */
array_collect_params(struct pet_array * array,__isl_take isl_space * space)2205 static __isl_give isl_space *array_collect_params(struct pet_array *array,
2206 	__isl_take isl_space *space)
2207 {
2208 	if (!array)
2209 		return isl_space_free(space);
2210 
2211 	space = isl_space_align_params(space,
2212 					isl_set_get_space(array->context));
2213 	space = isl_space_align_params(space, isl_set_get_space(array->extent));
2214 
2215 	return space;
2216 }
2217 
2218 /* Add all parameters in "independence" to "space" and return the result.
2219  */
independence_collect_params(struct pet_independence * independence,__isl_take isl_space * space)2220 static __isl_give isl_space *independence_collect_params(
2221 	struct pet_independence *independence, __isl_take isl_space *space)
2222 {
2223 	if (!independence)
2224 		return isl_space_free(space);
2225 
2226 	space = isl_space_align_params(space,
2227 				isl_union_map_get_space(independence->filter));
2228 	space = isl_space_align_params(space,
2229 				isl_union_set_get_space(independence->local));
2230 
2231 	return space;
2232 }
2233 
2234 /* Collect all parameters in "scop" in a parameter space and return the result.
2235  */
scop_collect_params(struct pet_scop * scop)2236 static __isl_give isl_space *scop_collect_params(struct pet_scop *scop)
2237 {
2238 	isl_space *space;
2239 	int i;
2240 
2241 	if (!scop)
2242 		return NULL;
2243 
2244 	space = isl_set_get_space(scop->context);
2245 
2246 	for (i = 0; i < scop->n_array; ++i)
2247 		space = array_collect_params(scop->arrays[i], space);
2248 
2249 	for (i = 0; i < scop->n_stmt; ++i)
2250 		space = stmt_collect_params(scop->stmts[i], space);
2251 
2252 	for (i = 0; i < scop->n_independence; ++i)
2253 		space = independence_collect_params(scop->independences[i],
2254 							space);
2255 
2256 	return space;
2257 }
2258 
2259 /* Add all parameters in "space" to the domain and
2260  * all access relations in "stmt".
2261  */
stmt_propagate_params(struct pet_stmt * stmt,__isl_take isl_space * space)2262 static struct pet_stmt *stmt_propagate_params(struct pet_stmt *stmt,
2263 	__isl_take isl_space *space)
2264 {
2265 	int i;
2266 
2267 	if (!stmt)
2268 		goto error;
2269 
2270 	stmt->domain = isl_set_align_params(stmt->domain,
2271 						isl_space_copy(space));
2272 
2273 	for (i = 0; i < stmt->n_arg; ++i) {
2274 		stmt->args[i] = pet_expr_align_params(stmt->args[i],
2275 						isl_space_copy(space));
2276 		if (!stmt->args[i])
2277 			goto error;
2278 	}
2279 	stmt->body = pet_tree_align_params(stmt->body, isl_space_copy(space));
2280 
2281 	if (!stmt->domain || !stmt->body)
2282 		goto error;
2283 
2284 	isl_space_free(space);
2285 	return stmt;
2286 error:
2287 	isl_space_free(space);
2288 	return pet_stmt_free(stmt);
2289 }
2290 
2291 /* Add all parameters in "space" to "array".
2292  */
array_propagate_params(struct pet_array * array,__isl_take isl_space * space)2293 static struct pet_array *array_propagate_params(struct pet_array *array,
2294 	__isl_take isl_space *space)
2295 {
2296 	if (!array)
2297 		goto error;
2298 
2299 	array->context = isl_set_align_params(array->context,
2300 						isl_space_copy(space));
2301 	array->extent = isl_set_align_params(array->extent,
2302 						isl_space_copy(space));
2303 	if (array->value_bounds) {
2304 		array->value_bounds = isl_set_align_params(array->value_bounds,
2305 							isl_space_copy(space));
2306 		if (!array->value_bounds)
2307 			goto error;
2308 	}
2309 
2310 	if (!array->context || !array->extent)
2311 		goto error;
2312 
2313 	isl_space_free(space);
2314 	return array;
2315 error:
2316 	isl_space_free(space);
2317 	return pet_array_free(array);
2318 }
2319 
2320 /* Add all parameters in "space" to "independence".
2321  */
independence_propagate_params(struct pet_independence * independence,__isl_take isl_space * space)2322 static struct pet_independence *independence_propagate_params(
2323 	struct pet_independence *independence, __isl_take isl_space *space)
2324 {
2325 	if (!independence)
2326 		goto error;
2327 
2328 	independence->filter = isl_union_map_align_params(independence->filter,
2329 						isl_space_copy(space));
2330 	independence->local = isl_union_set_align_params(independence->local,
2331 						isl_space_copy(space));
2332 	if (!independence->filter || !independence->local)
2333 		goto error;
2334 
2335 	isl_space_free(space);
2336 	return independence;
2337 error:
2338 	isl_space_free(space);
2339 	return pet_independence_free(independence);
2340 }
2341 
2342 /* Add all parameters in "space" to "scop".
2343  */
scop_propagate_params(struct pet_scop * scop,__isl_take isl_space * space)2344 static struct pet_scop *scop_propagate_params(struct pet_scop *scop,
2345 	__isl_take isl_space *space)
2346 {
2347 	int i;
2348 
2349 	if (!scop)
2350 		goto error;
2351 
2352 	scop->context = isl_set_align_params(scop->context,
2353 						isl_space_copy(space));
2354 	scop->schedule = isl_schedule_align_params(scop->schedule,
2355 						isl_space_copy(space));
2356 	if (!scop->context || !scop->schedule)
2357 		goto error;
2358 
2359 	for (i = 0; i < scop->n_array; ++i) {
2360 		scop->arrays[i] = array_propagate_params(scop->arrays[i],
2361 							isl_space_copy(space));
2362 		if (!scop->arrays[i])
2363 			goto error;
2364 	}
2365 
2366 	for (i = 0; i < scop->n_stmt; ++i) {
2367 		scop->stmts[i] = stmt_propagate_params(scop->stmts[i],
2368 							isl_space_copy(space));
2369 		if (!scop->stmts[i])
2370 			goto error;
2371 	}
2372 
2373 	for (i = 0; i < scop->n_independence; ++i) {
2374 		scop->independences[i] = independence_propagate_params(
2375 				scop->independences[i], isl_space_copy(space));
2376 		if (!scop->independences[i])
2377 			goto error;
2378 	}
2379 
2380 	isl_space_free(space);
2381 	return scop;
2382 error:
2383 	isl_space_free(space);
2384 	return pet_scop_free(scop);
2385 }
2386 
2387 /* Update all isl_sets and isl_maps in "scop" such that they all
2388  * have the same parameters.
2389  */
pet_scop_align_params(struct pet_scop * scop)2390 struct pet_scop *pet_scop_align_params(struct pet_scop *scop)
2391 {
2392 	isl_space *space;
2393 
2394 	if (!scop)
2395 		return NULL;
2396 
2397 	space = scop_collect_params(scop);
2398 
2399 	scop = scop_propagate_params(scop, space);
2400 
2401 	return scop;
2402 }
2403 
2404 /* Add the access relation of the give "type" of the access expression "expr"
2405  * to "accesses" and return the result.
2406  * The domain of the access relation is intersected with "domain".
2407  * If "tag" is set, then the access relation is tagged with
2408  * the corresponding reference identifier.
2409  */
expr_collect_access(__isl_keep pet_expr * expr,enum pet_expr_access_type type,int tag,__isl_take isl_union_map * accesses,__isl_keep isl_union_set * domain)2410 static __isl_give isl_union_map *expr_collect_access(__isl_keep pet_expr *expr,
2411 	enum pet_expr_access_type type, int tag,
2412 	__isl_take isl_union_map *accesses, __isl_keep isl_union_set *domain)
2413 {
2414 	isl_union_map *access;
2415 
2416 	access = pet_expr_access_get_access(expr, type);
2417 	access = isl_union_map_intersect_domain(access,
2418 						isl_union_set_copy(domain));
2419 	if (tag)
2420 		access = pet_expr_tag_access(expr, access);
2421 	return isl_union_map_union(accesses, access);
2422 }
2423 
2424 /* Internal data structure for expr_collect_accesses.
2425  *
2426  * "type" is the type of accesses we want to collect.
2427  * "tag" is set if the access relations should be tagged with
2428  * the corresponding reference identifiers.
2429  * "domain" are constraints on the domain of the access relations.
2430  * "accesses" collects the results.
2431  */
2432 struct pet_expr_collect_accesses_data {
2433 	enum pet_expr_access_type type;
2434 	int tag;
2435 	isl_union_set *domain;
2436 
2437 	isl_union_map *accesses;
2438 };
2439 
2440 /* Add the access relation of the access expression "expr"
2441  * to data->accesses if the access expression is a read and we are collecting
2442  * reads and/or it is a write and we are collecting writes.
2443  * The domains of the access relations are intersected with data->domain.
2444  * If data->tag is set, then the access relations are tagged with
2445  * the corresponding reference identifiers.
2446  *
2447  * If data->type is pet_expr_access_must_write, then we only add
2448  * the accesses that are definitely performed.  Otherwise, we add
2449  * all potential accesses.
2450  * In particular, if the access has any arguments, then in case of
2451  * pet_expr_access_must_write we currently skip the access completely.
2452  * In other cases, we project out the values of the access arguments.
2453  */
expr_collect_accesses(__isl_keep pet_expr * expr,void * user)2454 static int expr_collect_accesses(__isl_keep pet_expr *expr, void *user)
2455 {
2456 	struct pet_expr_collect_accesses_data *data = user;
2457 
2458 	if (!expr)
2459 		return -1;
2460 
2461 	if (pet_expr_is_affine(expr))
2462 		return 0;
2463 	if (data->type == pet_expr_access_must_write && expr->n_arg != 0)
2464 		return 0;
2465 
2466 	if ((data->type == pet_expr_access_may_read && expr->acc.read) ||
2467 	    ((data->type == pet_expr_access_may_write ||
2468 	      data->type == pet_expr_access_must_write) && expr->acc.write))
2469 		data->accesses = expr_collect_access(expr,
2470 						data->type, data->tag,
2471 						data->accesses, data->domain);
2472 
2473 	return data->accesses ? 0 : -1;
2474 }
2475 
2476 /* Collect and return all access relations of the given "type" in "stmt".
2477  * If "tag" is set, then the access relations are tagged with
2478  * the corresponding reference identifiers.
2479  * If "type" is pet_expr_access_killed, then "stmt" is a kill statement and
2480  * we simply add the argument of the kill operation.
2481  *
2482  * If we are looking for definite accesses (pet_expr_access_must_write
2483  * or pet_expr_access_killed), then we only add the accesses that are
2484  * definitely performed.  Otherwise, we add all potential accesses.
2485  * In particular, if the statement has any arguments, then if we are looking
2486  * for definite accesses we currently skip the statement completely.  Othewise,
2487  * we project out the values of the statement arguments.
2488  * If the statement body is not an expression tree, then we cannot
2489  * know for sure if/when the accesses inside the tree are performed.
2490  * We therefore ignore such statements when we are looking for
2491  * definite accesses.
2492  */
stmt_collect_accesses(struct pet_stmt * stmt,enum pet_expr_access_type type,int tag,__isl_take isl_space * dim)2493 static __isl_give isl_union_map *stmt_collect_accesses(struct pet_stmt *stmt,
2494 	enum pet_expr_access_type type, int tag, __isl_take isl_space *dim)
2495 {
2496 	struct pet_expr_collect_accesses_data data = { type, tag };
2497 	int must;
2498 	isl_set *domain;
2499 
2500 	if (!stmt)
2501 		return NULL;
2502 
2503 	data.accesses = isl_union_map_empty(dim);
2504 
2505 	if (type == pet_expr_access_must_write ||
2506 	    type == pet_expr_access_killed)
2507 		must = 1;
2508 	else
2509 		must = 0;
2510 
2511 	if (must && stmt->n_arg > 0)
2512 		return data.accesses;
2513 	if (must && pet_tree_get_type(stmt->body) != pet_tree_expr)
2514 		return data.accesses;
2515 
2516 	domain = drop_arguments(isl_set_copy(stmt->domain));
2517 	data.domain = isl_union_set_from_set(domain);
2518 
2519 	if (type == pet_expr_access_killed) {
2520 		pet_expr *body, *arg;
2521 
2522 		body = pet_tree_expr_get_expr(stmt->body);
2523 		arg = pet_expr_get_arg(body, 0);
2524 		data.accesses = expr_collect_access(arg,
2525 						pet_expr_access_killed, tag,
2526 						data.accesses, data.domain);
2527 		pet_expr_free(arg);
2528 		pet_expr_free(body);
2529 	} else if (pet_tree_foreach_access_expr(stmt->body,
2530 					&expr_collect_accesses, &data) < 0)
2531 		data.accesses = isl_union_map_free(data.accesses);
2532 
2533 	isl_union_set_free(data.domain);
2534 
2535 	return data.accesses;
2536 }
2537 
2538 /* Is "stmt" an assignment statement?
2539  */
pet_stmt_is_assign(struct pet_stmt * stmt)2540 int pet_stmt_is_assign(struct pet_stmt *stmt)
2541 {
2542 	if (!stmt)
2543 		return 0;
2544 	return pet_tree_is_assign(stmt->body);
2545 }
2546 
2547 /* Is "stmt" a kill statement?
2548  */
pet_stmt_is_kill(struct pet_stmt * stmt)2549 int pet_stmt_is_kill(struct pet_stmt *stmt)
2550 {
2551 	if (!stmt)
2552 		return 0;
2553 	return pet_tree_is_kill(stmt->body);
2554 }
2555 
2556 /* Is "stmt" an assume statement?
2557  */
pet_stmt_is_assume(struct pet_stmt * stmt)2558 int pet_stmt_is_assume(struct pet_stmt *stmt)
2559 {
2560 	if (!stmt)
2561 		return 0;
2562 	return pet_tree_is_assume(stmt->body);
2563 }
2564 
2565 /* Given a map "map" that represents an expansion from a lower-dimensional
2566  * domain to the space of "set", add those constraints of "set" to the range
2567  * that cannot be derived from the corresponding constraints on the domain.
2568  * That is, add the constraints that apply to variables in the range
2569  * that do not appear in the domain.
2570  */
set_inner_domain(__isl_take isl_map * map,__isl_keep isl_set * dom)2571 static __isl_give isl_map *set_inner_domain(__isl_take isl_map *map,
2572 	__isl_keep isl_set *dom)
2573 {
2574 	isl_map *copy;
2575 
2576 	copy = isl_map_copy(map);
2577 	copy = isl_map_intersect_range(copy, isl_set_copy(dom));
2578 	dom = isl_map_domain(isl_map_copy(copy));
2579 	copy = isl_map_gist_domain(copy, dom);
2580 	dom = isl_map_range(copy);
2581 	map = isl_map_intersect_range(map, dom);
2582 
2583 	return map;
2584 }
2585 
2586 /* Compute a mapping from all arrays (of structs) in scop
2587  * to their members.
2588  *
2589  * If "from_outermost" is set, then the domain only consists
2590  * of outermost arrays.
2591  * If "to_innermost" is set, then the range only consists
2592  * of innermost arrays.
2593  *
2594  * For each array, the construction starts from an identity mapping
2595  * on the space in which the array lives.
2596  * The references to members are then successively removed from
2597  * the domain of this mapping until the domain refers to an outer array.
2598  * Whenever a nesting level is removed from the domain,
2599  * the corresponding constraints on the extent are added to the range.
2600  */
compute_to_inner(struct pet_scop * scop,int from_outermost,int to_innermost)2601 static __isl_give isl_union_map *compute_to_inner(struct pet_scop *scop,
2602 	int from_outermost, int to_innermost)
2603 {
2604 	int i;
2605 	isl_union_map *to_inner;
2606 
2607 	if (!scop)
2608 		return NULL;
2609 
2610 	to_inner = isl_union_map_empty(isl_set_get_space(scop->context));
2611 
2612 	for (i = 0; i < scop->n_array; ++i) {
2613 		struct pet_array *array = scop->arrays[i];
2614 		isl_space *space;
2615 		isl_set *set;
2616 		isl_map *map;
2617 
2618 		if (to_innermost && array->outer)
2619 			continue;
2620 
2621 		set = isl_set_copy(array->extent);
2622 		space = isl_set_get_space(set);
2623 		map = isl_set_identity(isl_set_universe(space));
2624 
2625 		while (map && isl_map_domain_is_wrapping(map)) {
2626 			if (!from_outermost)
2627 				to_inner = isl_union_map_add_map(to_inner,
2628 							    isl_map_copy(map));
2629 
2630 			map = isl_map_domain_factor_domain(map);
2631 			map = set_inner_domain(map, set);
2632 		}
2633 		isl_set_free(set);
2634 
2635 		to_inner = isl_union_map_add_map(to_inner, map);
2636 	}
2637 
2638 	return to_inner;
2639 }
2640 
2641 /* Compute a mapping from all arrays (of structs) in scop
2642  * to their innermost arrays.
2643  *
2644  * In particular, for each array of a primitive type, the result
2645  * contains the identity mapping on that array.
2646  * For each array involving member accesses, the result
2647  * contains a mapping from the elements of any intermediate array of structs
2648  * to all corresponding elements of the innermost nested arrays.
2649  */
pet_scop_compute_any_to_inner(struct pet_scop * scop)2650 static __isl_give isl_union_map *pet_scop_compute_any_to_inner(
2651 	struct pet_scop *scop)
2652 {
2653 	return compute_to_inner(scop, 0, 1);
2654 }
2655 
2656 /* Compute a mapping from all outermost arrays (of structs) in scop
2657  * to their innermost members.
2658  */
pet_scop_compute_outer_to_inner(struct pet_scop * scop)2659 __isl_give isl_union_map *pet_scop_compute_outer_to_inner(struct pet_scop *scop)
2660 {
2661 	return compute_to_inner(scop, 1, 1);
2662 }
2663 
2664 /* Compute a mapping from all outermost arrays (of structs) in scop
2665  * to their members, including the outermost arrays themselves.
2666  */
pet_scop_compute_outer_to_any(struct pet_scop * scop)2667 __isl_give isl_union_map *pet_scop_compute_outer_to_any(struct pet_scop *scop)
2668 {
2669 	return compute_to_inner(scop, 1, 0);
2670 }
2671 
2672 /* Collect and return all access relations of the given "type" in "scop".
2673  * If "type" is pet_expr_access_killed, then we only add the arguments of
2674  * kill operations.
2675  * If we are looking for definite accesses (pet_expr_access_must_write
2676  * or pet_expr_access_killed), then we only add the accesses that are
2677  * definitely performed.  Otherwise, we add all potential accesses.
2678  * If "tag" is set, then the access relations are tagged with
2679  * the corresponding reference identifiers.
2680  * For accesses to structures, the returned access relation accesses
2681  * all individual fields in the structures.
2682  */
scop_collect_accesses(struct pet_scop * scop,enum pet_expr_access_type type,int tag)2683 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
2684 	enum pet_expr_access_type type, int tag)
2685 {
2686 	int i;
2687 	isl_union_map *accesses;
2688 	isl_union_set *arrays;
2689 	isl_union_map *to_inner;
2690 
2691 	if (!scop)
2692 		return NULL;
2693 
2694 	accesses = isl_union_map_empty(isl_set_get_space(scop->context));
2695 
2696 	for (i = 0; i < scop->n_stmt; ++i) {
2697 		struct pet_stmt *stmt = scop->stmts[i];
2698 		isl_union_map *accesses_i;
2699 		isl_space *space;
2700 
2701 		if (type == pet_expr_access_killed && !pet_stmt_is_kill(stmt))
2702 			continue;
2703 
2704 		space = isl_set_get_space(scop->context);
2705 		accesses_i = stmt_collect_accesses(stmt, type, tag, space);
2706 		accesses = isl_union_map_union(accesses, accesses_i);
2707 	}
2708 
2709 	arrays = isl_union_set_empty(isl_union_map_get_space(accesses));
2710 	for (i = 0; i < scop->n_array; ++i) {
2711 		isl_set *extent = isl_set_copy(scop->arrays[i]->extent);
2712 		arrays = isl_union_set_add_set(arrays, extent);
2713 	}
2714 	accesses = isl_union_map_intersect_range(accesses, arrays);
2715 
2716 	to_inner = pet_scop_compute_any_to_inner(scop);
2717 	accesses = isl_union_map_apply_range(accesses, to_inner);
2718 
2719 	return accesses;
2720 }
2721 
2722 /* Return the potential read access relation.
2723  */
pet_scop_get_may_reads(struct pet_scop * scop)2724 __isl_give isl_union_map *pet_scop_get_may_reads(struct pet_scop *scop)
2725 {
2726 	return scop_collect_accesses(scop, pet_expr_access_may_read, 0);
2727 }
2728 
2729 /* Return the potential write access relation.
2730  */
pet_scop_get_may_writes(struct pet_scop * scop)2731 __isl_give isl_union_map *pet_scop_get_may_writes(struct pet_scop *scop)
2732 {
2733 	return scop_collect_accesses(scop, pet_expr_access_may_write, 0);
2734 }
2735 
2736 /* Return the definite write access relation.
2737  */
pet_scop_get_must_writes(struct pet_scop * scop)2738 __isl_give isl_union_map *pet_scop_get_must_writes(struct pet_scop *scop)
2739 {
2740 	return scop_collect_accesses(scop, pet_expr_access_must_write, 0);
2741 }
2742 
2743 /* Return the definite kill access relation.
2744  */
pet_scop_get_must_kills(struct pet_scop * scop)2745 __isl_give isl_union_map *pet_scop_get_must_kills(struct pet_scop *scop)
2746 {
2747 	return scop_collect_accesses(scop, pet_expr_access_killed, 0);
2748 }
2749 
2750 /* Return the tagged potential read access relation.
2751  */
pet_scop_get_tagged_may_reads(struct pet_scop * scop)2752 __isl_give isl_union_map *pet_scop_get_tagged_may_reads(
2753 	struct pet_scop *scop)
2754 {
2755 	return scop_collect_accesses(scop, pet_expr_access_may_read, 1);
2756 }
2757 
2758 /* Return the tagged potential write access relation.
2759  */
pet_scop_get_tagged_may_writes(struct pet_scop * scop)2760 __isl_give isl_union_map *pet_scop_get_tagged_may_writes(
2761 	struct pet_scop *scop)
2762 {
2763 	return scop_collect_accesses(scop, pet_expr_access_may_write, 1);
2764 }
2765 
2766 /* Return the tagged definite write access relation.
2767  */
pet_scop_get_tagged_must_writes(struct pet_scop * scop)2768 __isl_give isl_union_map *pet_scop_get_tagged_must_writes(
2769 	struct pet_scop *scop)
2770 {
2771 	return scop_collect_accesses(scop, pet_expr_access_must_write, 1);
2772 }
2773 
2774 /* Return the tagged definite kill access relation.
2775  */
pet_scop_get_tagged_must_kills(struct pet_scop * scop)2776 __isl_give isl_union_map *pet_scop_get_tagged_must_kills(
2777 	struct pet_scop *scop)
2778 {
2779 	return scop_collect_accesses(scop, pet_expr_access_killed, 1);
2780 }
2781 
2782 /* Collect and return the set of all statement instances in "scop".
2783  */
pet_scop_get_instance_set(struct pet_scop * scop)2784 __isl_give isl_union_set *pet_scop_get_instance_set(struct pet_scop *scop)
2785 {
2786 	int i;
2787 	isl_set *domain_i;
2788 	isl_union_set *domain;
2789 
2790 	if (!scop)
2791 		return NULL;
2792 
2793 	domain = isl_union_set_empty(isl_set_get_space(scop->context));
2794 
2795 	for (i = 0; i < scop->n_stmt; ++i) {
2796 		domain_i = isl_set_copy(scop->stmts[i]->domain);
2797 		if (scop->stmts[i]->n_arg > 0)
2798 			domain_i = isl_map_domain(isl_set_unwrap(domain_i));
2799 		domain = isl_union_set_add_set(domain, domain_i);
2800 	}
2801 
2802 	return domain;
2803 }
2804 
2805 /* Return the context of "scop".
2806  */
pet_scop_get_context(__isl_keep pet_scop * scop)2807 __isl_give isl_set *pet_scop_get_context(__isl_keep pet_scop *scop)
2808 {
2809 	if (!scop)
2810 		return NULL;
2811 
2812 	return isl_set_copy(scop->context);
2813 }
2814 
2815 /* Return the schedule of "scop".
2816  */
pet_scop_get_schedule(__isl_keep pet_scop * scop)2817 __isl_give isl_schedule *pet_scop_get_schedule(__isl_keep pet_scop *scop)
2818 {
2819 	if (!scop)
2820 		return NULL;
2821 
2822 	return isl_schedule_copy(scop->schedule);
2823 }
2824 
2825 /* Add a reference identifier to all access expressions in "stmt".
2826  * "n_ref" points to an integer that contains the sequence number
2827  * of the next reference.
2828  */
stmt_add_ref_ids(struct pet_stmt * stmt,int * n_ref)2829 static struct pet_stmt *stmt_add_ref_ids(struct pet_stmt *stmt, int *n_ref)
2830 {
2831 	int i;
2832 
2833 	if (!stmt)
2834 		return NULL;
2835 
2836 	for (i = 0; i < stmt->n_arg; ++i) {
2837 		stmt->args[i] = pet_expr_add_ref_ids(stmt->args[i], n_ref);
2838 		if (!stmt->args[i])
2839 			return pet_stmt_free(stmt);
2840 	}
2841 
2842 	stmt->body = pet_tree_add_ref_ids(stmt->body, n_ref);
2843 	if (!stmt->body)
2844 		return pet_stmt_free(stmt);
2845 
2846 	return stmt;
2847 }
2848 
2849 /* Add a reference identifier to all access expressions in "scop".
2850  */
pet_scop_add_ref_ids(struct pet_scop * scop)2851 struct pet_scop *pet_scop_add_ref_ids(struct pet_scop *scop)
2852 {
2853 	int i;
2854 	int n_ref;
2855 
2856 	if (!scop)
2857 		return NULL;
2858 
2859 	n_ref = 0;
2860 	for (i = 0; i < scop->n_stmt; ++i) {
2861 		scop->stmts[i] = stmt_add_ref_ids(scop->stmts[i], &n_ref);
2862 		if (!scop->stmts[i])
2863 			return pet_scop_free(scop);
2864 	}
2865 
2866 	return scop;
2867 }
2868 
2869 /* Reset the user pointer on all parameter ids in "array".
2870  */
array_anonymize(struct pet_array * array)2871 static struct pet_array *array_anonymize(struct pet_array *array)
2872 {
2873 	if (!array)
2874 		return NULL;
2875 
2876 	array->context = isl_set_reset_user(array->context);
2877 	array->extent = isl_set_reset_user(array->extent);
2878 	if (!array->context || !array->extent)
2879 		return pet_array_free(array);
2880 
2881 	return array;
2882 }
2883 
2884 /* Reset the user pointer on all parameter and tuple ids in "stmt".
2885  */
stmt_anonymize(struct pet_stmt * stmt)2886 static struct pet_stmt *stmt_anonymize(struct pet_stmt *stmt)
2887 {
2888 	int i;
2889 
2890 	if (!stmt)
2891 		return NULL;
2892 
2893 	stmt->domain = isl_set_reset_user(stmt->domain);
2894 	if (!stmt->domain)
2895 		return pet_stmt_free(stmt);
2896 
2897 	for (i = 0; i < stmt->n_arg; ++i) {
2898 		stmt->args[i] = pet_expr_anonymize(stmt->args[i]);
2899 		if (!stmt->args[i])
2900 			return pet_stmt_free(stmt);
2901 	}
2902 
2903 	stmt->body = pet_tree_anonymize(stmt->body);
2904 	if (!stmt->body)
2905 		return pet_stmt_free(stmt);
2906 
2907 	return stmt;
2908 }
2909 
2910 /* Reset the user pointer on the tuple ids and all parameter ids
2911  * in "implication".
2912  */
implication_anonymize(struct pet_implication * implication)2913 static struct pet_implication *implication_anonymize(
2914 	struct pet_implication *implication)
2915 {
2916 	if (!implication)
2917 		return NULL;
2918 
2919 	implication->extension = isl_map_reset_user(implication->extension);
2920 	if (!implication->extension)
2921 		return pet_implication_free(implication);
2922 
2923 	return implication;
2924 }
2925 
2926 /* Reset the user pointer on the tuple ids and all parameter ids
2927  * in "independence".
2928  */
independence_anonymize(struct pet_independence * independence)2929 static struct pet_independence *independence_anonymize(
2930 	struct pet_independence *independence)
2931 {
2932 	if (!independence)
2933 		return NULL;
2934 
2935 	independence->filter = isl_union_map_reset_user(independence->filter);
2936 	independence->local = isl_union_set_reset_user(independence->local);
2937 	if (!independence->filter || !independence->local)
2938 		return pet_independence_free(independence);
2939 
2940 	return independence;
2941 }
2942 
2943 /* Reset the user pointer on all parameter and tuple ids in "scop".
2944  */
pet_scop_anonymize(struct pet_scop * scop)2945 struct pet_scop *pet_scop_anonymize(struct pet_scop *scop)
2946 {
2947 	int i;
2948 
2949 	if (!scop)
2950 		return NULL;
2951 
2952 	scop->context = isl_set_reset_user(scop->context);
2953 	scop->context_value = isl_set_reset_user(scop->context_value);
2954 	scop->schedule = isl_schedule_reset_user(scop->schedule);
2955 	if (!scop->context || !scop->context_value || !scop->schedule)
2956 		return pet_scop_free(scop);
2957 
2958 	for (i = 0; i < scop->n_array; ++i) {
2959 		scop->arrays[i] = array_anonymize(scop->arrays[i]);
2960 		if (!scop->arrays[i])
2961 			return pet_scop_free(scop);
2962 	}
2963 
2964 	for (i = 0; i < scop->n_stmt; ++i) {
2965 		scop->stmts[i] = stmt_anonymize(scop->stmts[i]);
2966 		if (!scop->stmts[i])
2967 			return pet_scop_free(scop);
2968 	}
2969 
2970 	for (i = 0; i < scop->n_implication; ++i) {
2971 		scop->implications[i] =
2972 				implication_anonymize(scop->implications[i]);
2973 		if (!scop->implications[i])
2974 			return pet_scop_free(scop);
2975 	}
2976 
2977 	for (i = 0; i < scop->n_independence; ++i) {
2978 		scop->independences[i] =
2979 				independence_anonymize(scop->independences[i]);
2980 		if (!scop->independences[i])
2981 			return pet_scop_free(scop);
2982 	}
2983 
2984 	return scop;
2985 }
2986 
2987 /* Compute the gist of the iteration domain and all access relations
2988  * of "stmt" based on the constraints on the parameters specified by "context"
2989  * and the constraints on the values of nested accesses specified
2990  * by "value_bounds".
2991  */
stmt_gist(struct pet_stmt * stmt,__isl_keep isl_set * context,__isl_keep isl_union_map * value_bounds)2992 static struct pet_stmt *stmt_gist(struct pet_stmt *stmt,
2993 	__isl_keep isl_set *context, __isl_keep isl_union_map *value_bounds)
2994 {
2995 	int i;
2996 	isl_set *domain;
2997 
2998 	if (!stmt)
2999 		return NULL;
3000 
3001 	domain = isl_set_copy(stmt->domain);
3002 	if (stmt->n_arg > 0)
3003 		domain = isl_map_domain(isl_set_unwrap(domain));
3004 
3005 	domain = isl_set_intersect_params(domain, isl_set_copy(context));
3006 
3007 	for (i = 0; i < stmt->n_arg; ++i) {
3008 		stmt->args[i] = pet_expr_gist(stmt->args[i],
3009 							domain, value_bounds);
3010 		if (!stmt->args[i])
3011 			goto error;
3012 	}
3013 
3014 	stmt->body = pet_tree_gist(stmt->body, domain, value_bounds);
3015 	if (!stmt->body)
3016 		goto error;
3017 
3018 	isl_set_free(domain);
3019 
3020 	domain = isl_set_universe(pet_stmt_get_space(stmt));
3021 	domain = isl_set_intersect_params(domain, isl_set_copy(context));
3022 	if (stmt->n_arg > 0)
3023 		domain = pet_value_bounds_apply(domain, stmt->n_arg, stmt->args,
3024 						value_bounds);
3025 	stmt->domain = isl_set_gist(stmt->domain, domain);
3026 	if (!stmt->domain)
3027 		return pet_stmt_free(stmt);
3028 
3029 	return stmt;
3030 error:
3031 	isl_set_free(domain);
3032 	return pet_stmt_free(stmt);
3033 }
3034 
3035 /* Compute the gist of the extent of the array
3036  * based on the constraints on the parameters specified by "context".
3037  */
array_gist(struct pet_array * array,__isl_keep isl_set * context)3038 static struct pet_array *array_gist(struct pet_array *array,
3039 	__isl_keep isl_set *context)
3040 {
3041 	if (!array)
3042 		return NULL;
3043 
3044 	array->extent = isl_set_gist_params(array->extent,
3045 						isl_set_copy(context));
3046 	if (!array->extent)
3047 		return pet_array_free(array);
3048 
3049 	return array;
3050 }
3051 
3052 /* Compute the gist of all sets and relations in "scop"
3053  * based on the constraints on the parameters specified by "scop->context"
3054  * and the constraints on the values of nested accesses specified
3055  * by "value_bounds".
3056  */
pet_scop_gist(struct pet_scop * scop,__isl_keep isl_union_map * value_bounds)3057 struct pet_scop *pet_scop_gist(struct pet_scop *scop,
3058 	__isl_keep isl_union_map *value_bounds)
3059 {
3060 	int i;
3061 
3062 	if (!scop)
3063 		return NULL;
3064 
3065 	scop->context = isl_set_coalesce(scop->context);
3066 	if (!scop->context)
3067 		return pet_scop_free(scop);
3068 
3069 	scop->schedule = isl_schedule_gist_domain_params(scop->schedule,
3070 					isl_set_copy(scop->context));
3071 	if (!scop->schedule)
3072 		return pet_scop_free(scop);
3073 
3074 	for (i = 0; i < scop->n_array; ++i) {
3075 		scop->arrays[i] = array_gist(scop->arrays[i], scop->context);
3076 		if (!scop->arrays[i])
3077 			return pet_scop_free(scop);
3078 	}
3079 
3080 	for (i = 0; i < scop->n_stmt; ++i) {
3081 		scop->stmts[i] = stmt_gist(scop->stmts[i], scop->context,
3082 					    value_bounds);
3083 		if (!scop->stmts[i])
3084 			return pet_scop_free(scop);
3085 	}
3086 
3087 	return scop;
3088 }
3089 
3090 /* Intersect the context of "scop" with "context".
3091  * To ensure that we don't introduce any unnamed parameters in
3092  * the context of "scop", we first remove the unnamed parameters
3093  * from "context".
3094  */
pet_scop_restrict_context(struct pet_scop * scop,__isl_take isl_set * context)3095 struct pet_scop *pet_scop_restrict_context(struct pet_scop *scop,
3096 	__isl_take isl_set *context)
3097 {
3098 	if (!scop)
3099 		goto error;
3100 
3101 	context = pet_nested_remove_from_set(context);
3102 	scop->context = isl_set_intersect(scop->context, context);
3103 	if (!scop->context)
3104 		return pet_scop_free(scop);
3105 
3106 	return scop;
3107 error:
3108 	isl_set_free(context);
3109 	return pet_scop_free(scop);
3110 }
3111 
3112 /* Drop the current context of "scop".  That is, replace the context
3113  * by a universal set.
3114  */
pet_scop_reset_context(struct pet_scop * scop)3115 struct pet_scop *pet_scop_reset_context(struct pet_scop *scop)
3116 {
3117 	isl_space *space;
3118 
3119 	if (!scop)
3120 		return NULL;
3121 
3122 	space = isl_set_get_space(scop->context);
3123 	isl_set_free(scop->context);
3124 	scop->context = isl_set_universe(space);
3125 	if (!scop->context)
3126 		return pet_scop_free(scop);
3127 
3128 	return scop;
3129 }
3130 
3131 /* Append "array" to the arrays of "scop".
3132  */
pet_scop_add_array(struct pet_scop * scop,struct pet_array * array)3133 struct pet_scop *pet_scop_add_array(struct pet_scop *scop,
3134 	struct pet_array *array)
3135 {
3136 	isl_ctx *ctx;
3137 	struct pet_array **arrays;
3138 
3139 	if (!array || !scop)
3140 		goto error;
3141 
3142 	ctx = isl_set_get_ctx(scop->context);
3143 	arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
3144 				    scop->n_array + 1);
3145 	if (!arrays)
3146 		goto error;
3147 	scop->arrays = arrays;
3148 	scop->arrays[scop->n_array] = array;
3149 	scop->n_array++;
3150 	scop->context = isl_set_intersect_params(scop->context,
3151 						isl_set_copy(array->context));
3152 	if (!scop->context)
3153 		return pet_scop_free(scop);
3154 
3155 	return scop;
3156 error:
3157 	pet_array_free(array);
3158 	return pet_scop_free(scop);
3159 }
3160 
3161 /* Create an index expression for an access to a virtual array
3162  * representing the result of a condition.
3163  * Unlike other accessed data, the id of the array is NULL as
3164  * there is no ValueDecl in the program corresponding to the virtual
3165  * array.
3166  * The index expression is created as an identity mapping on "space".
3167  * That is, the dimension of the array is the same as that of "space".
3168  */
pet_create_test_index(__isl_take isl_space * space,int test_nr)3169 __isl_give isl_multi_pw_aff *pet_create_test_index(__isl_take isl_space *space,
3170 	int test_nr)
3171 {
3172 	isl_id *id;
3173 	char name[50];
3174 
3175 	snprintf(name, sizeof(name), "__pet_test_%d", test_nr);
3176 	id = isl_id_alloc(isl_space_get_ctx(space), name, NULL);
3177 	space = isl_space_map_from_set(space);
3178 	space = isl_space_set_tuple_id(space, isl_dim_out, id);
3179 	return isl_multi_pw_aff_identity(space);
3180 }
3181 
3182 /* Add an array with the given extent to the list
3183  * of arrays in "scop" and return the extended pet_scop.
3184  * Specifically, the extent is determined by the image of "domain"
3185  * under "index".
3186  * "int_size" is the number of bytes needed to represent values of type "int".
3187  * The array is marked as attaining values 0 and 1 only and
3188  * as each element being assigned at most once.
3189  */
pet_scop_add_boolean_array(struct pet_scop * scop,__isl_take isl_set * domain,__isl_take isl_multi_pw_aff * index,int int_size)3190 struct pet_scop *pet_scop_add_boolean_array(struct pet_scop *scop,
3191 	__isl_take isl_set *domain, __isl_take isl_multi_pw_aff *index,
3192 	int int_size)
3193 {
3194 	isl_ctx *ctx;
3195 	isl_space *space;
3196 	struct pet_array *array;
3197 	isl_map *access;
3198 
3199 	if (!scop || !domain || !index)
3200 		goto error;
3201 
3202 	ctx = isl_multi_pw_aff_get_ctx(index);
3203 	array = isl_calloc_type(ctx, struct pet_array);
3204 	if (!array)
3205 		goto error;
3206 
3207 	access = isl_map_from_multi_pw_aff(index);
3208 	access = isl_map_intersect_domain(access, domain);
3209 	array->extent = isl_map_range(access);
3210 	space = isl_space_params_alloc(ctx, 0);
3211 	array->context = isl_set_universe(space);
3212 	space = isl_space_set_alloc(ctx, 0, 1);
3213 	array->value_bounds = isl_set_universe(space);
3214 	array->value_bounds = isl_set_lower_bound_si(array->value_bounds,
3215 						isl_dim_set, 0, 0);
3216 	array->value_bounds = isl_set_upper_bound_si(array->value_bounds,
3217 						isl_dim_set, 0, 1);
3218 	array->element_type = strdup("int");
3219 	array->element_size = int_size;
3220 	array->uniquely_defined = 1;
3221 
3222 	if (!array->extent || !array->context)
3223 		array = pet_array_free(array);
3224 
3225 	scop = pet_scop_add_array(scop, array);
3226 
3227 	return scop;
3228 error:
3229 	isl_set_free(domain);
3230 	isl_multi_pw_aff_free(index);
3231 	return pet_scop_free(scop);
3232 }
3233 
3234 /* Create and return an implication on filter values equal to "satisfied"
3235  * with extension "map".
3236  */
new_implication(__isl_take isl_map * map,int satisfied)3237 static struct pet_implication *new_implication(__isl_take isl_map *map,
3238 	int satisfied)
3239 {
3240 	isl_ctx *ctx;
3241 	struct pet_implication *implication;
3242 
3243 	if (!map)
3244 		return NULL;
3245 	ctx = isl_map_get_ctx(map);
3246 	implication = isl_alloc_type(ctx, struct pet_implication);
3247 	if (!implication)
3248 		goto error;
3249 
3250 	implication->extension = map;
3251 	implication->satisfied = satisfied;
3252 
3253 	return implication;
3254 error:
3255 	isl_map_free(map);
3256 	return NULL;
3257 }
3258 
3259 /* Add an implication on filter values equal to "satisfied"
3260  * with extension "map" to "scop".
3261  */
pet_scop_add_implication(struct pet_scop * scop,__isl_take isl_map * map,int satisfied)3262 struct pet_scop *pet_scop_add_implication(struct pet_scop *scop,
3263 	__isl_take isl_map *map, int satisfied)
3264 {
3265 	isl_ctx *ctx;
3266 	struct pet_implication *implication;
3267 	struct pet_implication **implications;
3268 
3269 	implication = new_implication(map, satisfied);
3270 	if (!scop || !implication)
3271 		goto error;
3272 
3273 	ctx = isl_set_get_ctx(scop->context);
3274 	implications = isl_realloc_array(ctx, scop->implications,
3275 					    struct pet_implication *,
3276 					    scop->n_implication + 1);
3277 	if (!implications)
3278 		goto error;
3279 	scop->implications = implications;
3280 	scop->implications[scop->n_implication] = implication;
3281 	scop->n_implication++;
3282 
3283 	return scop;
3284 error:
3285 	pet_implication_free(implication);
3286 	return pet_scop_free(scop);
3287 }
3288 
3289 /* Create and return a function that maps the iteration domains
3290  * of the statements in "scop" onto their outer "n" dimensions.
3291  * "space" is the parameters space of the created function.
3292  */
outer_projection(struct pet_scop * scop,__isl_take isl_space * space,int n)3293 static __isl_give isl_union_pw_multi_aff *outer_projection(
3294 	struct pet_scop *scop, __isl_take isl_space *space, int n)
3295 {
3296 	int i;
3297 	isl_union_pw_multi_aff *res;
3298 
3299 	res = isl_union_pw_multi_aff_empty(space);
3300 
3301 	if (!scop)
3302 		return isl_union_pw_multi_aff_free(res);
3303 
3304 	for (i = 0; i < scop->n_stmt; ++i) {
3305 		struct pet_stmt *stmt = scop->stmts[i];
3306 		isl_space *space;
3307 		isl_multi_aff *ma;
3308 		isl_pw_multi_aff *pma;
3309 
3310 		space = pet_stmt_get_space(stmt);
3311 		ma = pet_prefix_projection(space, n);
3312 		pma = isl_pw_multi_aff_from_multi_aff(ma);
3313 		res = isl_union_pw_multi_aff_add_pw_multi_aff(res, pma);
3314 	}
3315 
3316 	return res;
3317 }
3318 
3319 /* Add an independence to "scop" for the inner iterator of "domain"
3320  * with local variables "local", where "domain" represents the outer
3321  * loop iterators of all statements in "scop".
3322  * If "sign" is positive, then the inner iterator increases.
3323  * Otherwise it decreases.
3324  *
3325  * The independence is supposed to filter out any dependence of
3326  * an iteration of domain on a previous iteration along the inner dimension.
3327  * We therefore create a mapping from an iteration to later iterations and
3328  * then plug in the projection of the iterations domains of "scop"
3329  * onto the outer loop iterators.
3330  */
pet_scop_set_independent(struct pet_scop * scop,__isl_keep isl_set * domain,__isl_take isl_union_set * local,int sign)3331 struct pet_scop *pet_scop_set_independent(struct pet_scop *scop,
3332 	__isl_keep isl_set *domain, __isl_take isl_union_set *local, int sign)
3333 {
3334 	int i, dim;
3335 	isl_space *space;
3336 	isl_map *map;
3337 	isl_union_map *independence;
3338 	isl_union_pw_multi_aff *proj;
3339 
3340 	if (!scop || !domain || !local)
3341 		goto error;
3342 
3343 	dim = isl_set_dim(domain, isl_dim_set);
3344 	space = isl_space_map_from_set(isl_set_get_space(domain));
3345 	map = isl_map_universe(space);
3346 	for (i = 0; i + 1 < dim; ++i)
3347 		map = isl_map_equate(map, isl_dim_in, i, isl_dim_out, i);
3348 	if (sign > 0)
3349 		map = isl_map_order_lt(map,
3350 				    isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3351 	else
3352 		map = isl_map_order_gt(map,
3353 				    isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3354 
3355 	independence = isl_union_map_from_map(map);
3356 	space = isl_space_params(isl_set_get_space(domain));
3357 	proj = outer_projection(scop, space, dim);
3358 	independence = isl_union_map_preimage_domain_union_pw_multi_aff(
3359 			    independence, isl_union_pw_multi_aff_copy(proj));
3360 	independence = isl_union_map_preimage_range_union_pw_multi_aff(
3361 			    independence, proj);
3362 
3363 	scop = pet_scop_add_independence(scop, independence, local);
3364 
3365 	return scop;
3366 error:
3367 	isl_union_set_free(local);
3368 	return pet_scop_free(scop);
3369 }
3370 
3371 /* Given an access expression, check if it is data dependent.
3372  * If so, set *found and abort the search.
3373  */
is_data_dependent(__isl_keep pet_expr * expr,void * user)3374 static int is_data_dependent(__isl_keep pet_expr *expr, void *user)
3375 {
3376 	int *found = user;
3377 
3378 	if (pet_expr_get_n_arg(expr) > 0) {
3379 		*found = 1;
3380 		return -1;
3381 	}
3382 
3383 	return 0;
3384 }
3385 
3386 /* Does "scop" contain any data dependent accesses?
3387  *
3388  * Check the body of each statement for such accesses.
3389  */
pet_scop_has_data_dependent_accesses(struct pet_scop * scop)3390 int pet_scop_has_data_dependent_accesses(struct pet_scop *scop)
3391 {
3392 	int i;
3393 	int found = 0;
3394 
3395 	if (!scop)
3396 		return -1;
3397 
3398 	for (i = 0; i < scop->n_stmt; ++i) {
3399 		int r = pet_tree_foreach_access_expr(scop->stmts[i]->body,
3400 					&is_data_dependent, &found);
3401 		if (r < 0 && !found)
3402 			return -1;
3403 		if (found)
3404 			return found;
3405 	}
3406 
3407 	return found;
3408 }
3409 
3410 /* Does "scop" contain and data dependent conditions?
3411  */
pet_scop_has_data_dependent_conditions(struct pet_scop * scop)3412 int pet_scop_has_data_dependent_conditions(struct pet_scop *scop)
3413 {
3414 	int i;
3415 
3416 	if (!scop)
3417 		return -1;
3418 
3419 	for (i = 0; i < scop->n_stmt; ++i)
3420 		if (scop->stmts[i]->n_arg > 0)
3421 			return 1;
3422 
3423 	return 0;
3424 }
3425 
3426 /* Keep track of the "input" file inside the (extended) "scop".
3427  */
pet_scop_set_input_file(struct pet_scop * scop,FILE * input)3428 struct pet_scop *pet_scop_set_input_file(struct pet_scop *scop, FILE *input)
3429 {
3430 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3431 
3432 	if (!scop)
3433 		return NULL;
3434 
3435 	ext->input = input;
3436 
3437 	return scop;
3438 }
3439 
3440 /* Print the original code corresponding to "scop" to printer "p".
3441  *
3442  * pet_scop_print_original can only be called from
3443  * a pet_transform_C_source callback.  This means that the input
3444  * file is stored in the extended scop and that the printer prints
3445  * to a file.
3446  */
pet_scop_print_original(struct pet_scop * scop,__isl_take isl_printer * p)3447 __isl_give isl_printer *pet_scop_print_original(struct pet_scop *scop,
3448 	__isl_take isl_printer *p)
3449 {
3450 	struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3451 	FILE *output;
3452 	unsigned start, end;
3453 
3454 	if (!scop || !p)
3455 		return isl_printer_free(p);
3456 
3457 	if (!ext->input)
3458 		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
3459 			"no input file stored in scop",
3460 			return isl_printer_free(p));
3461 
3462 	output = isl_printer_get_file(p);
3463 	if (!output)
3464 		return isl_printer_free(p);
3465 
3466 	start = pet_loc_get_start(scop->loc);
3467 	end = pet_loc_get_end(scop->loc);
3468 	if (copy(ext->input, output, start, end) < 0)
3469 		return isl_printer_free(p);
3470 
3471 	return p;
3472 }
3473