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
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.
39 #include <isl/options.h>
41 #include <isl/union_map.h>
42 #include <isl/id_to_pw_aff.h>
48 struct isl_options
*isl
;
49 struct pet_options
*pet
;
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
)
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
);
66 /* Extract an affine expression from the call to floord in "expr".
68 * "space" is the iteration space of the statement containing the expression.
70 static __isl_give isl_pw_aff
*expr_extract_floord(__isl_keep pet_expr
*expr
,
71 __isl_keep isl_space
*space
)
73 isl_pw_aff
*lhs
, *rhs
;
76 arg
= pet_expr_get_arg(expr
, 0);
77 lhs
= expr_extract_pw_aff(arg
, space
);
79 arg
= pet_expr_get_arg(expr
, 1);
80 rhs
= expr_extract_pw_aff(arg
, space
);
82 return isl_pw_aff_floor(isl_pw_aff_div(lhs
, rhs
));
85 /* Extract an affine expression from the call in "expr".
87 * "space" is the iteration space of the statement containing the expression.
89 * We only support calls to the "floord" function for now.
91 static __isl_give isl_pw_aff
*call_expr_extract_pw_aff(
92 __isl_keep pet_expr
*expr
, __isl_keep isl_space
*space
)
96 name
= pet_expr_call_get_name(expr
);
99 if (!strcmp(name
, "floord"))
100 return expr_extract_floord(expr
, space
);
102 isl_die(isl_space_get_ctx(space
), isl_error_unsupported
,
103 "unsupported expression", return NULL
);
106 /* Extract an affine expression from the access to a named space in "index".
108 * We assume we are accessing a 0D space and
109 * we turn that into an expression equal to a parameter of the same name.
111 static __isl_give isl_pw_aff
*resolve_access(__isl_take isl_multi_pw_aff
*index
)
119 id
= isl_multi_pw_aff_get_tuple_id(index
, isl_dim_out
);
120 dom
= isl_multi_pw_aff_domain(index
);
121 dom
= isl_set_insert_dims(dom
, isl_dim_param
, 0, 1);
122 dom
= isl_set_set_dim_id(dom
, isl_dim_param
, 0, id
);
123 ls
= isl_local_space_from_space(isl_set_get_space(dom
));
124 aff
= isl_aff_var_on_domain(ls
, isl_dim_param
, 0);
125 pa
= isl_pw_aff_alloc(dom
, aff
);
130 /* Extract an affine expression from the access expression "expr".
132 * If we are accessing a (1D) anonymous space, then we are actually
133 * computing an affine expression and we simply return that expression.
134 * Otherwise, we try and convert the access to an affine expression in
137 static __isl_give isl_pw_aff
*access_expr_extract_pw_aff(
138 __isl_keep pet_expr
*expr
)
141 isl_multi_pw_aff
*index
;
143 index
= pet_expr_access_get_index(expr
);
144 if (isl_multi_pw_aff_has_tuple_id(index
, isl_dim_out
)) {
145 pa
= resolve_access(index
);
147 pa
= isl_multi_pw_aff_get_pw_aff(index
, 0);
148 isl_multi_pw_aff_free(index
);
153 /* Extract an affine expression defined over iteration space "space"
154 * from the integer expression "expr".
156 static __isl_give isl_pw_aff
*int_expr_extract_pw_aff(
157 __isl_keep pet_expr
*expr
, __isl_keep isl_space
*space
)
162 ls
= isl_local_space_from_space(isl_space_copy(space
));
163 aff
= isl_aff_zero_on_domain(ls
);
164 aff
= isl_aff_add_constant_val(aff
, pet_expr_int_get_val(expr
));
165 return isl_pw_aff_from_aff(aff
);
168 /* Extract an affine expression from the operation in "expr".
170 * "space" is the iteration space of the statement containing the expression.
172 * We only handle the kinds of expressions that we would expect
173 * as arguments to a function call in code generated by isl.
175 static __isl_give isl_pw_aff
*op_expr_extract_pw_aff(__isl_keep pet_expr
*expr
,
176 __isl_keep isl_space
*space
)
178 isl_pw_aff
*pa
, *pa1
, *pa2
;
180 enum pet_op_type type
;
182 switch (pet_expr_get_n_arg(expr
)) {
184 if (pet_expr_op_get_type(expr
) == pet_op_minus
) {
185 arg
= pet_expr_get_arg(expr
, 0);
186 pa
= expr_extract_pw_aff(arg
, space
);
188 return isl_pw_aff_neg(pa
);
192 arg
= pet_expr_get_arg(expr
, 0);
193 pa1
= expr_extract_pw_aff(arg
, space
);
195 arg
= pet_expr_get_arg(expr
, 1);
196 pa2
= expr_extract_pw_aff(arg
, space
);
198 type
= pet_expr_op_get_type(expr
);
201 pa
= isl_pw_aff_mul(pa1
, pa2
);
204 pa
= isl_pw_aff_add(pa1
, pa2
);
207 pa
= isl_pw_aff_sub(pa1
, pa2
);
210 pa
= isl_pw_aff_tdiv_q(pa1
, pa2
);
213 pa
= isl_pw_aff_tdiv_r(pa1
, pa2
);
221 pa
= pet_comparison(type
, pa1
, pa2
);
225 pa
= pet_boolean(type
, pa1
, pa2
);
232 arg
= pet_expr_get_arg(expr
, 0);
233 pa
= expr_extract_pw_aff(arg
, space
);
235 arg
= pet_expr_get_arg(expr
, 1);
236 pa1
= expr_extract_pw_aff(arg
, space
);
238 arg
= pet_expr_get_arg(expr
, 2);
239 pa2
= expr_extract_pw_aff(arg
, space
);
241 return isl_pw_aff_cond(pa
, pa1
, pa2
);
247 /* Extract an affine expression from "expr" in the form of an isl_pw_aff.
249 * "space" is the iteration space of the statement containing the expression.
251 * We only handle the kinds of expressions that we would expect
252 * as arguments to a function call in code generated by isl.
254 static __isl_give isl_pw_aff
*expr_extract_pw_aff(__isl_keep pet_expr
*expr
,
255 __isl_keep isl_space
*space
)
257 switch (pet_expr_get_type(expr
)) {
259 return int_expr_extract_pw_aff(expr
, space
);
260 case pet_expr_access
:
261 return access_expr_extract_pw_aff(expr
);
263 return op_expr_extract_pw_aff(expr
, space
);
265 return call_expr_extract_pw_aff(expr
, space
);
267 case pet_expr_double
:
273 /* Extract an affine expression from "expr" in the form of an isl_map.
275 * "space" is the iteration space of the statement containing the expression.
277 static __isl_give isl_map
*expr_extract_map(__isl_keep pet_expr
*expr
,
278 __isl_keep isl_space
*space
)
282 pa
= expr_extract_pw_aff(expr
, space
);
283 return isl_map_from_pw_aff(pa
);
286 /* Extract a call from "stmt".
288 * The returned map is of the form
290 * { domain -> function[arguments] }
292 static __isl_give isl_map
*stmt_extract_call(struct pet_stmt
*stmt
)
299 domain
= isl_set_copy(stmt
->domain
);
300 call
= isl_map_from_domain(domain
);
302 assert(pet_expr_get_type(stmt
->body
) == pet_expr_call
);
304 n
= pet_expr_get_n_arg(stmt
->body
);
305 for (i
= 0; i
< n
; ++i
) {
310 arg
= pet_expr_get_arg(stmt
->body
, i
);
311 space
= pet_stmt_get_space(stmt
);
312 map_i
= expr_extract_map(arg
, space
);
313 isl_space_free(space
);
315 call
= isl_map_flat_range_product(call
, map_i
);
318 name
= pet_expr_call_get_name(stmt
->body
);
319 call
= isl_map_set_tuple_name(call
, isl_dim_out
, name
);
324 /* Extract a mapping from the iterations domains of "scop" to
325 * the calls in the corresponding statements.
327 * We skip assignment and kill statements.
328 * Other than assignments and kill statements, all statements are assumed
329 * to be function calls.
331 static __isl_give isl_union_map
*scop_collect_calls(struct pet_scop
*scop
)
341 call
= isl_union_map_empty(isl_set_get_space(scop
->context
));
342 ctx
= isl_set_get_ctx(scop
->context
);
344 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
345 struct pet_stmt
*stmt
;
347 stmt
= scop
->stmts
[i
];
348 if (pet_stmt_is_assign(stmt
))
350 if (pet_stmt_is_kill(stmt
))
352 call_i
= stmt_extract_call(scop
->stmts
[i
]);
353 call
= isl_union_map_add_map(call
, call_i
);
359 /* Extract a schedule on the original domains from "scop".
360 * The original domain elements appear as calls in "scop".
362 * We first extract a schedule on the code iteration domains
363 * and a mapping from the code iteration domains to the calls
364 * (i.e., the original domain) and then combine the two.
366 static __isl_give isl_union_map
*extract_code_schedule(struct pet_scop
*scop
)
368 isl_union_map
*schedule
;
369 isl_union_map
*calls
;
371 schedule
= pet_scop_collect_schedule(scop
);
373 calls
= scop_collect_calls(scop
);
375 schedule
= isl_union_map_apply_domain(schedule
, calls
);
380 /* Check that schedule and code_schedule have the same domain,
381 * i.e., that they execute the same statement instances.
383 static int check_domain(__isl_keep isl_union_map
*schedule
,
384 __isl_keep isl_union_map
*code_schedule
)
386 isl_union_set
*dom1
, *dom2
;
392 dom1
= isl_union_map_domain(isl_union_map_copy(schedule
));
393 dom2
= isl_union_map_domain(isl_union_map_copy(code_schedule
));
394 equal
= isl_union_set_is_equal(dom1
, dom2
);
399 isl_union_set_dump(dom1
);
400 isl_union_set_dump(dom2
);
401 isl_die(isl_union_map_get_ctx(schedule
), isl_error_unknown
,
402 "domains not identical", r
= -1);
405 isl_union_set_free(dom1
);
406 isl_union_set_free(dom2
);
411 /* Check that the relative order specified by the input schedule is respected
412 * by the schedule extracted from the code, in case the original schedule
415 * In particular, check that there is no pair of statement instances
416 * such that the first should be scheduled _before_ the second,
417 * but is actually scheduled _after_ the second in the code.
419 static int check_order_sv(__isl_keep isl_union_map
*schedule
,
420 __isl_keep isl_union_map
*code_schedule
)
426 t1
= isl_union_map_lex_lt_union_map(isl_union_map_copy(schedule
),
427 isl_union_map_copy(schedule
));
428 t2
= isl_union_map_lex_gt_union_map(isl_union_map_copy(code_schedule
),
429 isl_union_map_copy(code_schedule
));
430 t1
= isl_union_map_intersect(t1
, t2
);
431 empty
= isl_union_map_is_empty(t1
);
432 isl_union_map_free(t1
);
437 isl_die(isl_union_map_get_ctx(schedule
), isl_error_unknown
,
438 "order not respected", return -1);
443 /* Check that the relative order specified by the input schedule is respected
444 * by the schedule extracted from the code, in case the original schedule
445 * is not single valued.
447 * In particular, check that the order imposed by the schedules on pairs
448 * of statement instances is the same.
450 static int check_order_not_sv(__isl_keep isl_union_map
*schedule
,
451 __isl_keep isl_union_map
*code_schedule
)
457 t1
= isl_union_map_lex_lt_union_map(isl_union_map_copy(schedule
),
458 isl_union_map_copy(schedule
));
459 t2
= isl_union_map_lex_lt_union_map(isl_union_map_copy(code_schedule
),
460 isl_union_map_copy(code_schedule
));
461 equal
= isl_union_map_is_equal(t1
, t2
);
462 isl_union_map_free(t1
);
463 isl_union_map_free(t2
);
468 isl_die(isl_union_map_get_ctx(schedule
), isl_error_unknown
,
469 "order not respected", return -1);
474 /* Check that the relative order specified by the input schedule is respected
475 * by the schedule extracted from the code.
477 * "sv" indicated whether the original schedule is single valued.
478 * If so, we use a cheaper test. Otherwise, we fall back on a more
481 static int check_order(__isl_keep isl_union_map
*schedule
,
482 __isl_keep isl_union_map
*code_schedule
, int sv
)
485 return check_order_sv(schedule
, code_schedule
);
487 return check_order_not_sv(schedule
, code_schedule
);
490 /* If the original schedule was single valued ("sv" is set),
491 * then the schedule extracted from the code should be single valued as well.
493 static int check_single_valued(__isl_keep isl_union_map
*code_schedule
, int sv
)
498 sv
= isl_union_map_is_single_valued(code_schedule
);
503 isl_die(isl_union_map_get_ctx(code_schedule
), isl_error_unknown
,
504 "schedule not single valued", return -1);
509 /* Read a schedule and a context from the first argument and
510 * C code from the second argument and check that the C code
511 * corresponds to the schedule on the context.
513 * In particular, check that
514 * - the domains are identical, i.e., the calls in the C code
515 * correspond to the domain elements of the schedule
516 * - no function is called twice with the same arguments, provided
517 * the schedule is single-valued
518 * - the calls are performed in an order that is compatible
521 * If the schedule is not single-valued then we would have to check
522 * that each function with a given set of arguments is called
523 * the same number of times as there are images in the schedule,
524 * but this is considerably more difficult.
526 int main(int argc
, char **argv
)
530 isl_union_map
*schedule
, *code_schedule
;
531 struct pet_scop
*scop
;
532 struct options
*options
;
537 options
= options_new_with_defaults();
539 ctx
= isl_ctx_alloc_with_options(&options_args
, options
);
540 pet_options_set_signed_overflow(ctx
, PET_OVERFLOW_IGNORE
);
541 argc
= options_parse(options
, argc
, argv
, ISL_ARG_ALL
);
543 file
= fopen(options
->schedule
, "r");
545 schedule
= isl_union_map_read_from_file(ctx
, file
);
546 context
= isl_set_read_from_file(ctx
, file
);
549 scop
= pet_scop_extract_from_C_source(ctx
, options
->code
, NULL
);
551 schedule
= isl_union_map_intersect_params(schedule
,
552 isl_set_copy(context
));
553 code_schedule
= extract_code_schedule(scop
);
554 code_schedule
= isl_union_map_intersect_params(code_schedule
, context
);
556 sv
= isl_union_map_is_single_valued(schedule
);
558 check_domain(schedule
, code_schedule
) ||
559 check_single_valued(code_schedule
, sv
) ||
560 check_order(schedule
, code_schedule
, sv
);
563 isl_union_map_free(schedule
);
564 isl_union_map_free(code_schedule
);