tree2scop.c: map_to_previous: handle higher dimensional domains
[pet.git] / pet_check_code.c
blob9cd46dd2bf0d0cb8db42b8cff38e8589bc2a43ed
1 /*
2 * Copyright 2012-2014 Ecole Normale Superieure. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY ECOLE NORMALE SUPERIEURE ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECOLE NORMALE SUPERIEURE OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
31 * Ecole Normale Superieure.
34 #include <assert.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <isl/arg.h>
38 #include <isl/aff.h>
39 #include <isl/options.h>
40 #include <isl/set.h>
41 #include <isl/union_map.h>
42 #include <isl/id_to_pw_aff.h>
43 #include <pet.h>
45 #include "aff.h"
47 struct options {
48 struct isl_options *isl;
49 struct pet_options *pet;
50 char *schedule;
51 char *code;
54 ISL_ARGS_START(struct options, options_args)
55 ISL_ARG_CHILD(struct options, isl, "isl", &isl_options_args, "isl options")
56 ISL_ARG_CHILD(struct options, pet, NULL, &pet_options_args, "pet options")
57 ISL_ARG_ARG(struct options, schedule, "schedule", NULL)
58 ISL_ARG_ARG(struct options, code, "code", NULL)
59 ISL_ARGS_END
61 ISL_ARG_DEF(options, struct options, options_args)
63 static __isl_give isl_pw_aff *expr_extract_pw_aff(__isl_keep pet_expr *expr,
64 __isl_keep isl_space *space, __isl_keep isl_id_to_pw_aff *assignments);
66 /* Extract an affine expression from the call to floord in "expr",
67 * possibly exploiting "assignments".
69 * "space" is the iteration space of the statement containing the expression.
71 static __isl_give isl_pw_aff *expr_extract_floord(__isl_keep pet_expr *expr,
72 __isl_keep isl_space *space, __isl_keep isl_id_to_pw_aff *assignments)
74 isl_pw_aff *lhs, *rhs;
75 pet_expr *arg;
77 arg = pet_expr_get_arg(expr, 0);
78 lhs = expr_extract_pw_aff(arg, space, assignments);
79 pet_expr_free(arg);
80 arg = pet_expr_get_arg(expr, 1);
81 rhs = expr_extract_pw_aff(arg, space, assignments);
82 pet_expr_free(arg);
83 return isl_pw_aff_floor(isl_pw_aff_div(lhs, rhs));
86 /* Extract an affine expression from the call in "expr",
87 * possibly exploiting "assignments".
89 * "space" is the iteration space of the statement containing the expression.
91 * We only support calls to the "floord" function for now.
93 static __isl_give isl_pw_aff *call_expr_extract_pw_aff(
94 __isl_keep pet_expr *expr, __isl_keep isl_space *space,
95 __isl_keep isl_id_to_pw_aff *assignments)
97 const char *name;
99 name = pet_expr_call_get_name(expr);
100 if (!name)
101 return NULL;
102 if (!strcmp(name, "floord"))
103 return expr_extract_floord(expr, space, assignments);
105 isl_die(isl_id_to_pw_aff_get_ctx(assignments), isl_error_unsupported,
106 "unsupported expression", return NULL);
109 /* Is the variable accessed by "index" assigned in "assignments"?
111 * The assignments map variable identifiers to functions of the form
113 * { domain -> value }
115 static int is_assigned(__isl_keep isl_multi_pw_aff *index,
116 __isl_keep isl_id_to_pw_aff *assignments)
118 isl_id *var;
119 int assigned;
121 var = isl_multi_pw_aff_get_tuple_id(index, isl_dim_out);
122 assigned = isl_id_to_pw_aff_has(assignments, var);
123 isl_id_free(var);
125 return assigned;
128 /* Apply the appropriate assignment in "assignments"
129 * to the index expression "index".
131 * "index" is of the form
133 * { access_domain -> variable }
135 * "assignments" maps variable identifiers to functions of the form
137 * { assignment_domain -> value }
139 * We assume the assignment precedes the access in the code.
140 * In particular, we assume that the loops around the assignment
141 * are the same as the first loops around the access.
143 * We compute
145 * { access_domain -> assignment_domain }
147 * equating the iterators of assignment_domain to the corresponding iterators
148 * in access_domain and then plug that into the assigned value, obtaining
150 * { access_domain -> value }
152 static __isl_give isl_pw_aff *apply_assignment(
153 __isl_take isl_multi_pw_aff *index,
154 __isl_keep isl_id_to_pw_aff *assignments)
156 isl_id *id;
157 isl_set *dom;
158 isl_pw_aff *val;
159 isl_multi_aff *ma;
160 isl_space *space, *dom_space;
161 isl_local_space *ls;
162 int i, n;
164 id = isl_multi_pw_aff_get_tuple_id(index, isl_dim_out);
165 dom = isl_multi_pw_aff_domain(index);
166 val = isl_id_to_pw_aff_get(assignments, id);
167 space = isl_pw_aff_get_domain_space(val);
168 dom_space = isl_set_get_space(dom);
169 space = isl_space_map_from_domain_and_range(dom_space, space);
170 ma = isl_multi_aff_zero(space);
171 ls = isl_local_space_from_space(isl_set_get_space(dom));
172 n = isl_multi_aff_dim(ma, isl_dim_out);
173 for (i = 0; i < n; ++i) {
174 isl_aff *aff;
176 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
177 isl_dim_set, i);
178 ma = isl_multi_aff_set_aff(ma, i, aff);
180 isl_local_space_free(ls);
182 val = isl_pw_aff_pullback_multi_aff(val, ma);
183 val = isl_pw_aff_intersect_domain(val, dom);
185 return val;
188 /* Extract an affine expression from the access to a named space in "index",
189 * possibly exploiting "assignments".
191 * If the variable has been assigned a value, we return the corresponding
192 * assignment. Otherwise, we assume we are accessing a 0D space and
193 * we turn that into an expression equal to a parameter of the same name.
195 static __isl_give isl_pw_aff *resolve_access(__isl_take isl_multi_pw_aff *index,
196 __isl_keep isl_id_to_pw_aff *assignments)
198 isl_id *id;
199 isl_set *dom;
200 isl_aff *aff;
201 isl_local_space *ls;
202 isl_pw_aff *pa;
204 if (is_assigned(index, assignments))
205 return apply_assignment(index, assignments);
207 id = isl_multi_pw_aff_get_tuple_id(index, isl_dim_out);
208 dom = isl_multi_pw_aff_domain(index);
209 dom = isl_set_insert_dims(dom, isl_dim_param, 0, 1);
210 dom = isl_set_set_dim_id(dom, isl_dim_param, 0, id);
211 ls = isl_local_space_from_space(isl_set_get_space(dom));
212 aff = isl_aff_var_on_domain(ls, isl_dim_param, 0);
213 pa = isl_pw_aff_alloc(dom, aff);
215 return pa;
218 /* Extract an affine expression from the access expression "expr",
219 * possibly exploiting "assignments".
221 * If we are accessing a (1D) anonymous space, then we are actually
222 * computing an affine expression and we simply return that expression.
223 * Otherwise, we try and convert the access to an affine expression in
224 * resolve_access().
226 static __isl_give isl_pw_aff *access_expr_extract_pw_aff(
227 __isl_keep pet_expr *expr, __isl_keep isl_id_to_pw_aff *assignments)
229 isl_pw_aff *pa;
230 isl_multi_pw_aff *index;
232 index = pet_expr_access_get_index(expr);
233 if (isl_multi_pw_aff_has_tuple_id(index, isl_dim_out)) {
234 pa = resolve_access(index, assignments);
235 } else {
236 pa = isl_multi_pw_aff_get_pw_aff(index, 0);
237 isl_multi_pw_aff_free(index);
239 return pa;
242 /* Extract an affine expression defined over iteration space "space"
243 * from the integer expression "expr".
245 static __isl_give isl_pw_aff *int_expr_extract_pw_aff(
246 __isl_keep pet_expr *expr, __isl_keep isl_space *space)
248 isl_local_space *ls;
249 isl_aff *aff;
251 ls = isl_local_space_from_space(isl_space_copy(space));
252 aff = isl_aff_zero_on_domain(ls);
253 aff = isl_aff_add_constant_val(aff, pet_expr_int_get_val(expr));
254 return isl_pw_aff_from_aff(aff);
257 /* Extract an affine expression from the operation in "expr",
258 * possibly exploiting "assignments".
260 * "space" is the iteration space of the statement containing the expression.
262 * We only handle the kinds of expressions that we would expect
263 * as arguments to a function call in code generated by isl.
265 static __isl_give isl_pw_aff *op_expr_extract_pw_aff(__isl_keep pet_expr *expr,
266 __isl_keep isl_space *space, __isl_keep isl_id_to_pw_aff *assignments)
268 isl_pw_aff *pa, *pa1, *pa2;
269 pet_expr *arg;
270 enum pet_op_type type;
272 switch (pet_expr_get_n_arg(expr)) {
273 case 1:
274 if (pet_expr_op_get_type(expr) == pet_op_minus) {
275 arg = pet_expr_get_arg(expr, 0);
276 pa = expr_extract_pw_aff(arg, space, assignments);
277 pet_expr_free(arg);
278 return isl_pw_aff_neg(pa);
280 assert(0);
281 case 2:
282 arg = pet_expr_get_arg(expr, 0);
283 pa1 = expr_extract_pw_aff(arg, space, assignments);
284 pet_expr_free(arg);
285 arg = pet_expr_get_arg(expr, 1);
286 pa2 = expr_extract_pw_aff(arg, space, assignments);
287 pet_expr_free(arg);
288 type = pet_expr_op_get_type(expr);
289 switch (type) {
290 case pet_op_mul:
291 pa = isl_pw_aff_mul(pa1, pa2);
292 break;
293 case pet_op_add:
294 pa = isl_pw_aff_add(pa1, pa2);
295 break;
296 case pet_op_sub:
297 pa = isl_pw_aff_sub(pa1, pa2);
298 break;
299 case pet_op_div:
300 pa = isl_pw_aff_tdiv_q(pa1, pa2);
301 break;
302 case pet_op_mod:
303 pa = isl_pw_aff_tdiv_r(pa1, pa2);
304 break;
305 case pet_op_eq:
306 case pet_op_ne:
307 case pet_op_le:
308 case pet_op_ge:
309 case pet_op_lt:
310 case pet_op_gt:
311 pa = pet_comparison(type, pa1, pa2);
312 break;
313 case pet_op_land:
314 case pet_op_lor:
315 pa = pet_boolean(type, pa1, pa2);
316 break;
317 default:
318 assert(0);
320 return pa;
321 case 3:
322 arg = pet_expr_get_arg(expr, 0);
323 pa = expr_extract_pw_aff(arg, space, assignments);
324 pet_expr_free(arg);
325 arg = pet_expr_get_arg(expr, 1);
326 pa1 = expr_extract_pw_aff(arg, space, assignments);
327 pet_expr_free(arg);
328 arg = pet_expr_get_arg(expr, 2);
329 pa2 = expr_extract_pw_aff(arg, space, assignments);
330 pet_expr_free(arg);
331 return isl_pw_aff_cond(pa, pa1, pa2);
332 default:
333 assert(0);
337 /* Extract an affine expression from "expr", possibly exploiting "assignments",
338 * in the form of an isl_pw_aff.
340 * "space" is the iteration space of the statement containing the expression.
342 * We only handle the kinds of expressions that we would expect
343 * as arguments to a function call in code generated by isl.
345 static __isl_give isl_pw_aff *expr_extract_pw_aff(__isl_keep pet_expr *expr,
346 __isl_keep isl_space *space, __isl_keep isl_id_to_pw_aff *assignments)
348 switch (pet_expr_get_type(expr)) {
349 case pet_expr_int:
350 return int_expr_extract_pw_aff(expr, space);
351 case pet_expr_access:
352 return access_expr_extract_pw_aff(expr, assignments);
353 case pet_expr_op:
354 return op_expr_extract_pw_aff(expr, space, assignments);
355 case pet_expr_call:
356 return call_expr_extract_pw_aff(expr, space, assignments);
357 case pet_expr_cast:
358 case pet_expr_double:
359 case pet_expr_error:
360 assert(0);
364 /* Extract an affine expression from "expr", possibly exploiting "assignments",
365 * in the form of an isl_map.
367 * "space" is the iteration space of the statement containing the expression.
369 static __isl_give isl_map *expr_extract_map(__isl_keep pet_expr *expr,
370 __isl_keep isl_space *space, __isl_keep isl_id_to_pw_aff *assignments)
372 isl_pw_aff *pa;
374 pa = expr_extract_pw_aff(expr, space, assignments);
375 return isl_map_from_pw_aff(pa);
378 /* Extract a call from "stmt", possibly exploiting "assignments".
380 * The returned map is of the form
382 * { domain -> function[arguments] }
384 static __isl_give isl_map *stmt_extract_call(struct pet_stmt *stmt,
385 __isl_keep isl_id_to_pw_aff *assignments)
387 int i, n;
388 isl_set *domain;
389 isl_map *call;
390 const char *name;
392 domain = isl_set_copy(stmt->domain);
393 call = isl_map_from_domain(domain);
395 assert(pet_expr_get_type(stmt->body) == pet_expr_call);
397 n = pet_expr_get_n_arg(stmt->body);
398 for (i = 0; i < n; ++i) {
399 isl_map *map_i;
400 isl_space *space;
401 pet_expr *arg;
403 arg = pet_expr_get_arg(stmt->body, i);
404 space = pet_stmt_get_space(stmt);
405 map_i = expr_extract_map(arg, space, assignments);
406 isl_space_free(space);
407 pet_expr_free(arg);
408 call = isl_map_flat_range_product(call, map_i);
411 name = pet_expr_call_get_name(stmt->body);
412 call = isl_map_set_tuple_name(call, isl_dim_out, name);
414 return call;
417 /* Add the assignment in "stmt" to "assignments".
419 * We extract the accessed variable identifier "var"
420 * and the assigned value
422 * { domain -> value }
424 * and map "var" to this value in "assignments", replacing
425 * any possible previously assigned value to the same variable.
427 static __isl_give isl_id_to_pw_aff *add_assignment(
428 __isl_take isl_id_to_pw_aff *assignments, struct pet_stmt *stmt)
430 isl_id *var;
431 isl_space *space;
432 isl_pw_aff *val;
433 pet_expr *arg;
435 assert(pet_stmt_is_assign(stmt));
436 arg = pet_expr_get_arg(stmt->body, 0);
437 assert(pet_expr_get_type(arg) == pet_expr_access);
438 var = pet_expr_access_get_id(arg);
439 pet_expr_free(arg);
440 arg = pet_expr_get_arg(stmt->body, 1);
441 space = pet_stmt_get_space(stmt);
442 val = expr_extract_pw_aff(arg, space, assignments);
443 isl_space_free(space);
444 pet_expr_free(arg);
446 assignments = isl_id_to_pw_aff_set(assignments, var, val);
448 return assignments;
451 /* Extract a mapping from the iterations domains of "scop" to
452 * the calls in the corresponding statements.
454 * While scanning "scop", we keep track of assignments to variables
455 * so that we can plug them in in the arguments of the calls.
456 * Note that we do not perform any dependence analysis on the assigned
457 * variables. In code generated by isl, such assignments should only
458 * appear immediately before they are used.
460 * The assignments are kept as an associative array between
461 * variable identifiers and assignments of the form
463 * { domain -> value }
465 * We skip kill statements.
466 * Other than assignments and kill statements, all statements are assumed
467 * to be function calls.
469 static __isl_give isl_union_map *scop_collect_calls(struct pet_scop *scop)
471 int i;
472 isl_ctx *ctx;
473 isl_map *call_i;
474 isl_id_to_pw_aff *assignments;
475 isl_union_map *call;
477 if (!scop)
478 return NULL;
480 call = isl_union_map_empty(isl_set_get_space(scop->context));
481 ctx = isl_set_get_ctx(scop->context);
482 assignments = isl_id_to_pw_aff_alloc(ctx, 0);
484 for (i = 0; i < scop->n_stmt; ++i) {
485 struct pet_stmt *stmt;
487 stmt = scop->stmts[i];
488 if (pet_stmt_is_assign(stmt)) {
489 assignments = add_assignment(assignments, stmt);
490 continue;
492 if (pet_stmt_is_kill(stmt))
493 continue;
494 call_i = stmt_extract_call(scop->stmts[i], assignments);
495 call = isl_union_map_add_map(call, call_i);
498 isl_id_to_pw_aff_free(assignments);
500 return call;
503 /* Extract a schedule on the original domains from "scop".
504 * The original domain elements appear as calls in "scop".
506 * We first extract a schedule on the code iteration domains
507 * and a mapping from the code iteration domains to the calls
508 * (i.e., the original domain) and then combine the two.
510 static __isl_give isl_union_map *extract_code_schedule(struct pet_scop *scop)
512 isl_union_map *schedule;
513 isl_union_map *calls;
515 schedule = pet_scop_collect_schedule(scop);
517 calls = scop_collect_calls(scop);
519 schedule = isl_union_map_apply_domain(schedule, calls);
521 return schedule;
524 /* Check that schedule and code_schedule have the same domain,
525 * i.e., that they execute the same statement instances.
527 static int check_domain(__isl_keep isl_union_map *schedule,
528 __isl_keep isl_union_map *code_schedule)
530 isl_union_set *dom1, *dom2;
531 int equal;
532 isl_set *s1, *s2;;
533 isl_id *id1, *id2;
534 int r = 0;
536 dom1 = isl_union_map_domain(isl_union_map_copy(schedule));
537 dom2 = isl_union_map_domain(isl_union_map_copy(code_schedule));
538 equal = isl_union_set_is_equal(dom1, dom2);
540 if (equal < 0)
541 r = -1;
542 else if (!equal) {
543 isl_union_set_dump(dom1);
544 isl_union_set_dump(dom2);
545 isl_die(isl_union_map_get_ctx(schedule), isl_error_unknown,
546 "domains not identical", r = -1);
549 isl_union_set_free(dom1);
550 isl_union_set_free(dom2);
552 return r;
555 /* Check that the relative order specified by the input schedule is respected
556 * by the schedule extracted from the code, in case the original schedule
557 * is single valued.
559 * In particular, check that there is no pair of statement instances
560 * such that the first should be scheduled _before_ the second,
561 * but is actually scheduled _after_ the second in the code.
563 static int check_order_sv(__isl_keep isl_union_map *schedule,
564 __isl_keep isl_union_map *code_schedule)
566 isl_union_map *t1;
567 isl_union_map *t2;
568 int empty;
570 t1 = isl_union_map_lex_lt_union_map(isl_union_map_copy(schedule),
571 isl_union_map_copy(schedule));
572 t2 = isl_union_map_lex_gt_union_map(isl_union_map_copy(code_schedule),
573 isl_union_map_copy(code_schedule));
574 t1 = isl_union_map_intersect(t1, t2);
575 empty = isl_union_map_is_empty(t1);
576 isl_union_map_free(t1);
578 if (empty < 0)
579 return -1;
580 if (!empty)
581 isl_die(isl_union_map_get_ctx(schedule), isl_error_unknown,
582 "order not respected", return -1);
584 return 0;
587 /* Check that the relative order specified by the input schedule is respected
588 * by the schedule extracted from the code, in case the original schedule
589 * is not single valued.
591 * In particular, check that the order imposed by the schedules on pairs
592 * of statement instances is the same.
594 static int check_order_not_sv(__isl_keep isl_union_map *schedule,
595 __isl_keep isl_union_map *code_schedule)
597 isl_union_map *t1;
598 isl_union_map *t2;
599 int equal;
601 t1 = isl_union_map_lex_lt_union_map(isl_union_map_copy(schedule),
602 isl_union_map_copy(schedule));
603 t2 = isl_union_map_lex_lt_union_map(isl_union_map_copy(code_schedule),
604 isl_union_map_copy(code_schedule));
605 equal = isl_union_map_is_equal(t1, t2);
606 isl_union_map_free(t1);
607 isl_union_map_free(t2);
609 if (equal < 0)
610 return -1;
611 if (!equal)
612 isl_die(isl_union_map_get_ctx(schedule), isl_error_unknown,
613 "order not respected", return -1);
615 return 0;
618 /* Check that the relative order specified by the input schedule is respected
619 * by the schedule extracted from the code.
621 * "sv" indicated whether the original schedule is single valued.
622 * If so, we use a cheaper test. Otherwise, we fall back on a more
623 * expensive test.
625 static int check_order(__isl_keep isl_union_map *schedule,
626 __isl_keep isl_union_map *code_schedule, int sv)
628 if (sv)
629 return check_order_sv(schedule, code_schedule);
630 else
631 return check_order_not_sv(schedule, code_schedule);
634 /* If the original schedule was single valued ("sv" is set),
635 * then the schedule extracted from the code should be single valued as well.
637 static int check_single_valued(__isl_keep isl_union_map *code_schedule, int sv)
639 if (!sv)
640 return 0;
642 sv = isl_union_map_is_single_valued(code_schedule);
643 if (sv < 0)
644 return -1;
646 if (!sv)
647 isl_die(isl_union_map_get_ctx(code_schedule), isl_error_unknown,
648 "schedule not single valued", return -1);
650 return 0;
653 /* Read a schedule and a context from the first argument and
654 * C code from the second argument and check that the C code
655 * corresponds to the schedule on the context.
657 * In particular, check that
658 * - the domains are identical, i.e., the calls in the C code
659 * correspond to the domain elements of the schedule
660 * - no function is called twice with the same arguments, provided
661 * the schedule is single-valued
662 * - the calls are performed in an order that is compatible
663 * with the schedule
665 * If the schedule is not single-valued then we would have to check
666 * that each function with a given set of arguments is called
667 * the same number of times as there are images in the schedule,
668 * but this is considerably more difficult.
670 int main(int argc, char **argv)
672 isl_ctx *ctx;
673 isl_set *context;
674 isl_union_map *schedule, *code_schedule;
675 struct pet_scop *scop;
676 struct options *options;
677 FILE *file;
678 int r;
679 int sv;
681 options = options_new_with_defaults();
682 assert(options);
683 ctx = isl_ctx_alloc_with_options(&options_args, options);
684 pet_options_set_signed_overflow(ctx, PET_OVERFLOW_IGNORE);
685 argc = options_parse(options, argc, argv, ISL_ARG_ALL);
687 file = fopen(options->schedule, "r");
688 assert(file);
689 schedule = isl_union_map_read_from_file(ctx, file);
690 context = isl_set_read_from_file(ctx, file);
691 fclose(file);
693 scop = pet_scop_extract_from_C_source(ctx, options->code, NULL);
695 schedule = isl_union_map_intersect_params(schedule,
696 isl_set_copy(context));
697 code_schedule = extract_code_schedule(scop);
698 code_schedule = isl_union_map_intersect_params(code_schedule, context);
700 sv = isl_union_map_is_single_valued(schedule);
701 r = sv < 0 ||
702 check_domain(schedule, code_schedule) ||
703 check_single_valued(code_schedule, sv) ||
704 check_order(schedule, code_schedule, sv);
706 pet_scop_free(scop);
707 isl_union_map_free(schedule);
708 isl_union_map_free(code_schedule);
709 isl_ctx_free(ctx);
711 return r;