include/isa/adg.h: directly include required header
[ppn.git] / c2pdg.cc
blob7510edfdac1b10129b81836223a175190942eb2a
1 #include <assert.h>
2 #include <stdio.h>
3 #include <string.h>
5 #include <isl/ctx.h>
6 #include <isl/id.h>
7 #include <isl/val.h>
8 #include <isl/space.h>
9 #include <isl/local_space.h>
10 #include <isl/aff.h>
11 #include <isl/set.h>
12 #include <isl/map.h>
13 #include <isl/ilp.h>
14 #include <isl/constraint.h>
15 #include <isl/schedule.h>
16 #include <isl/schedule_node.h>
17 #include <isl/union_set.h>
18 #include <isl/union_map.h>
19 #include <pet.h>
21 #include <isa/pdg.h>
22 #include "c2pdg_options.h"
24 const char dot_yaml[] = ".yaml";
26 static __isl_give isl_map *isl_map_equal_dims(__isl_take isl_space *dim,
27 enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
29 isl_map *map = isl_map_universe(dim);
30 return isl_map_equate(map, type1, pos1, type2, pos2);
33 static __isl_give isl_map *isl_map_opposite_dims(__isl_take isl_space *dim,
34 enum isl_dim_type type1, int pos1, enum isl_dim_type type2, int pos2)
36 isl_map *map = isl_map_universe(dim);
37 return isl_map_oppose(map, type1, pos1, type2, pos2);
40 static pdg::call_or_access *convert_expr(pdg::PDG *pdg,
41 pdg::statement *stat, struct pet_expr *expr,
42 std::map<isl_id *, pdg::array *> &id2array, __isl_keep isl_map *trans);
44 /* Convert the access pet_expr to a pdg::access and return it.
45 * We assume that the pet_expr accesses data in a single space
46 * (in particular, we do not support accesses to different fields
47 * of a struct) and that it is either a write or a read (and not both).
48 * The pdg::access is also added to the list of accesses in "stat".
49 * The pointer to the pdg::array is taken from "id2array" based
50 * on the tuple id on the access relation.
52 * The domain of the access relation is transformed using "trans".
53 * If the access has any arguments then the domain of the access relation
54 * is a wrapped mapping from the iteration space to the space of
55 * argument values. We only need to change the domain of this wrapped
56 * mapping, so we extend the input transformation with an identity mapping
57 * on the space of argument values.
59 static pdg::access *extract_access(pdg::PDG *pdg, pdg::statement *stat,
60 struct pet_expr *expr, std::map<isl_id *, pdg::array *> &id2array,
61 __isl_keep isl_map *trans)
63 pdg::access *access = new pdg::access;
64 isl_id *id = NULL;
65 isl_space *dim;
66 isl_map *map;
67 isl_union_map *umap;
68 unsigned n_index;
69 int n;
71 n = pet_expr_get_n_arg(expr);
72 for (int i = 0; i < n; ++i) {
73 pdg::call_or_access *coa;
74 pet_expr *arg;
75 arg = pet_expr_get_arg(expr, i);
76 coa = convert_expr(pdg, stat, arg, id2array, trans);
77 pet_expr_free(arg);
78 access->nested.push_back(coa);
81 if (pet_expr_access_is_write(expr)) {
82 access->type = pdg::access::write;
83 umap = pet_expr_access_get_dependent_may_write(expr);
84 } else {
85 access->type = pdg::access::read;
86 umap = pet_expr_access_get_dependent_may_read(expr);
89 assert(isl_union_map_n_map(umap) == 1);
91 map = isl_map_from_union_map(umap);
92 trans = isl_map_copy(trans);
94 dim = isl_space_domain(isl_map_get_space(map));
95 if (!isl_space_is_wrapping(dim))
96 isl_space_free(dim);
97 else {
98 isl_map *id;
99 dim = isl_space_unwrap(dim);
100 dim = isl_space_range(dim);
101 dim = isl_space_map_from_set(dim);
102 id = isl_map_identity(dim);
103 trans = isl_map_product(trans, id);
106 map = isl_map_apply_domain(map, trans);
107 if (isl_map_has_tuple_id(map, isl_dim_out))
108 id = isl_map_get_tuple_id(map, isl_dim_out);
109 n_index = isl_map_dim(map, isl_dim_out);
110 for (int i = n_index - 1; i >= 0; --i)
111 if (!isl_map_involves_dims(map, isl_dim_out, i, 1))
112 map = isl_map_project_out(map, isl_dim_out, i, 1);
113 else
114 break;
115 if (id)
116 map = isl_map_set_tuple_id(map, isl_dim_out, id);
117 access->map = new pdg::IslMap(map);
119 if (!pet_expr_is_affine(expr)) {
120 id = pet_expr_access_get_id(expr);
121 access->array = id2array[id];
122 isl_id_free(id);
125 stat->accesses.push_back(access);
127 return access;
130 /* Convert the integer pet_expr to a pdg::access and return this pdg::access.
131 * The pdg::access is also added to the list of accesses in "stat".
133 * The domain of the access relation derived from the integer value
134 * is equal to the range space of "trans".
136 static pdg::access *extract_access_from_int(pdg::PDG *pdg, pdg::statement *stat,
137 struct pet_expr *expr, __isl_keep isl_map *trans)
139 pdg::access *access = new pdg::access;
140 isl_val *v;
141 isl_aff *aff;
142 isl_pw_aff *pa;
143 isl_space *space;
145 access->type = pdg::access::read;
147 v = pet_expr_int_get_val(expr);
148 space = isl_space_range(isl_map_get_space(trans));
149 aff = isl_aff_val_on_domain(isl_local_space_from_space(space), v);
150 pa = isl_pw_aff_from_aff(aff);
152 access->map = new pdg::IslMap(isl_map_from_pw_aff(pa));
154 stat->accesses.push_back(access);
156 return access;
159 static pdg::call_or_access *convert_expr(pdg::PDG *pdg,
160 pdg::statement *stat, struct pet_expr *expr,
161 std::map<isl_id *, pdg::array *> &id2array, __isl_keep isl_map *trans)
163 pdg::call_or_access *coa = new pdg::call_or_access;
164 enum pet_expr_type type;
166 type = pet_expr_get_type(expr);
167 if (type == pet_expr_access) {
168 coa->type = pdg::call_or_access::t_access;
169 coa->access = extract_access(pdg, stat, expr, id2array, trans);
170 } else if (type == pet_expr_int) {
171 coa->type = pdg::call_or_access::t_access;
172 coa->access = extract_access_from_int(pdg, stat, expr, trans);
173 } else {
174 int n;
176 coa->type = pdg::call_or_access::t_call;
177 coa->call = new pdg::function_call;
179 if (type == pet_expr_call)
180 coa->call->name = new str(pet_expr_call_get_name(expr));
181 else if (type == pet_expr_double) {
182 char *s = pet_expr_double_get_str(expr);
183 coa->call->name = new str(s);
184 free(s);
185 } else if (type == pet_expr_op &&
186 pet_expr_op_get_type(expr) == pet_op_cond)
187 coa->call->name = new str("#test");
188 else
189 coa->call->name =
190 new str(pet_op_str(pet_expr_op_get_type(expr)));
192 n = pet_expr_get_n_arg(expr);
193 for (int i = 0; i < n; ++i) {
194 pdg::call_or_access *child;
195 pet_expr *arg;
196 arg = pet_expr_get_arg(expr, i);
197 child = convert_expr(pdg, stat, arg, id2array, trans);
198 pet_expr_free(arg);
199 coa->call->arguments.push_back(child);
203 return coa;
206 static pdg::function_call *extract_top_function(pdg::PDG *pdg,
207 pdg::statement *stat, struct pet_expr *expr,
208 std::map<isl_id *, pdg::array *> &id2array, __isl_keep isl_map *trans)
210 pdg::function_call *call;
211 pdg::call_or_access *coa = convert_expr(pdg, stat, expr, id2array, trans);
213 if (coa->type == pdg::call_or_access::t_access) {
214 call = new pdg::function_call;
215 call->arguments.push_back(coa);
216 call->name = new str(string(""));
217 } else {
218 call = coa->call;
219 delete coa;
222 return call;
225 /* Extract a function call for the top-level function called from "tree".
226 * We currently assume the tree is an expression statement and
227 * extract the function call from the expression.
229 static pdg::function_call *extract_top_function(pdg::PDG *pdg,
230 pdg::statement *stat, __isl_keep pet_tree *tree,
231 std::map<isl_id *, pdg::array *> &id2array, __isl_keep isl_map *trans)
233 pdg::function_call *call;
234 pet_expr *expr;
236 assert(pet_tree_get_type(tree) == pet_tree_expr);
237 expr = pet_tree_expr_get_expr(tree);
238 call = extract_top_function(pdg, stat, expr, id2array, trans);
239 pet_expr_free(expr);
241 return call;
244 /* For each of the filters ("arguments") of "stmt", check if the user
245 * has specified any bounds on the values of the corresponding array
246 * elements. If so, apply those bounds to the filter in the iteration
247 * domain "dom".
248 * Return the (possibly) restricted iteration domain.
250 static __isl_give isl_set *apply_filter_bounds(__isl_take isl_set *dom,
251 struct pet_stmt *stmt, std::map<isl_id *, pdg::array *> &id2array)
253 isl_map *map;
255 if (!isl_set_is_wrapping(dom))
256 return dom;
258 map = isl_set_unwrap(dom);
260 for (int i = 0; i < stmt->n_arg; ++i) {
261 isl_id *id;
262 pdg::array *array;
263 pet_expr *expr = stmt->args[i];
264 isl_set *bound;
266 if (pet_expr_get_type(expr) != pet_expr_access)
267 continue;
269 id = pet_expr_access_get_id(expr);
270 array = id2array[id];
271 isl_id_free(id);
273 if (!array->value_bounds)
274 continue;
275 bound = array->value_bounds->get_isl_set();
276 bound = isl_set_insert_dims(bound, isl_dim_set, 0, i);
277 bound = isl_set_add_dims(bound, isl_dim_set,
278 stmt->n_arg - (i + 1));
279 map = isl_map_intersect_range(map, bound);
282 return isl_map_wrap(map);
285 /* Given a filter access function encoded in "coa" corresponding to
286 * filter "pos" in "domain", extend the function to a filter access
287 * relation by exploiting the implications in "scop".
288 * In particular, if a statement depends on all previous iterations
289 * of some (other) statement (not) having executed, then it is marked
290 * by pet as only depending on the latest iteration of that statement.
291 * The implicit dependence on all previous iterations is encoded
292 * in the implications in "scop".
294 * If the given filter has a fixed filter value that matches the satisfied
295 * field of one of the implications and if that implication also references
296 * the same virtual array, then the corresponding extension is applied
297 * to the original filter access function to extend it to the complete
298 * filter access relation.
299 * Otherwise, we leave the filter access function untouched.
301 static void apply_implications(pdg::call_or_access *coa, struct pet_scop *scop,
302 __isl_keep isl_set *domain, int pos)
304 isl_map *map;
305 isl_map *ext_domain;
306 isl_val *v;
307 isl_id *map_id;
308 int is_int, satisfied;
310 if (scop->n_implication == 0)
311 return;
313 ext_domain = isl_set_unwrap(isl_set_copy(domain));
314 v = isl_map_plain_get_val_if_fixed(ext_domain, isl_dim_out, pos);
315 is_int = isl_val_is_int(v);
316 if (is_int)
317 satisfied = isl_val_get_num_si(v);
318 isl_val_free(v);
319 isl_map_free(ext_domain);
320 if (!is_int)
321 return;
323 assert(coa->type == pdg::call_or_access::t_access);
324 map = coa->access->map->map;
325 map_id = isl_map_get_tuple_id(map, isl_dim_out);
327 for (int i = 0; i < scop->n_implication; ++i) {
328 struct pet_implication *pi;
329 isl_id *pi_id;
331 pi = scop->implications[i];
333 if (pi->satisfied != satisfied)
334 continue;
335 pi_id = isl_map_get_tuple_id(pi->extension, isl_dim_in);
336 isl_id_free(pi_id);
337 if (pi_id != map_id)
338 continue;
340 map = isl_map_apply_range(map, isl_map_copy(pi->extension));
341 break;
344 coa->access->map->map = map;
346 isl_id_free(map_id);
349 /* Does "expr" perform a (possibly compound) assignment?
351 static int is_assignment(__isl_keep pet_expr *expr)
353 pet_expr *arg;
354 int is_access;
356 if (pet_expr_get_type(expr) != pet_expr_op)
357 return 0;
358 if (pet_expr_op_get_type(expr) > pet_op_assign)
359 return 0;
360 arg = pet_expr_get_arg(expr, 0);
361 is_access = pet_expr_get_type(arg) == pet_expr_access;
362 pet_expr_free(arg);
364 return is_access;
367 /* Does "expr" perform an increment or decrement operation?
369 static int is_inc_dec(__isl_keep pet_expr *expr)
371 pet_expr *arg;
372 int is_access;
374 if (pet_expr_get_type(expr) != pet_expr_op)
375 return 0;
376 if (!pet_op_is_inc_dec(pet_expr_op_get_type(expr)))
377 return 0;
378 arg = pet_expr_get_arg(expr, 0);
379 is_access = pet_expr_get_type(arg) == pet_expr_access;
380 pet_expr_free(arg);
382 return is_access;
385 /* Is "tree" an expression statement that satisfies "fn"?
387 static int is_expr_tree(__isl_keep pet_tree *tree,
388 int (*fn)(__isl_keep pet_expr *expr))
390 pet_expr *expr;
391 int res;
393 if (pet_tree_get_type(tree) != pet_tree_expr)
394 return 0;
395 expr = pet_tree_expr_get_expr(tree);
396 res = fn(expr);
397 pet_expr_free(expr);
399 return res;
402 /* Does "tree" perform a (possibly compound) assignment?
404 static int is_assignment(__isl_keep pet_tree *tree)
406 return is_expr_tree(tree, &is_assignment);
409 /* Does "tree" perform an increment or decrement operation?
411 static int is_inc_dec(__isl_keep pet_tree *tree)
413 return is_expr_tree(tree, &is_inc_dec);
416 /* Find the position of the filter node among the children of "node"
417 * that contains elements in "space".
418 * It is assumed that there is exactly one such node.
420 static int get_filter_pos(__isl_keep isl_schedule_node *node,
421 __isl_keep isl_space *space)
423 int i, n;
425 n = isl_schedule_node_n_children(node);
426 for (i = 0; i < n; ++i) {
427 isl_schedule_node *child;
428 isl_union_set *filter;
429 isl_set *set;
430 int empty;
432 child = isl_schedule_node_get_child(node, i);
433 filter = isl_schedule_node_filter_get_filter(child);
434 set = isl_union_set_extract_set(filter, isl_space_copy(space));
435 empty = isl_set_is_empty(set);
436 isl_set_free(set);
437 isl_union_set_free(filter);
438 isl_schedule_node_free(child);
440 assert(empty >= 0);
441 if (!empty)
442 return i;
444 assert(0);
447 /* Create and return a pdg::node correspondingto stmt.
448 * Since isa uses the "prefix" field in a pdg::node to represent the
449 * original schedule, we try to extract such a prefix from the schedule.
450 * If one of the original for loops had a decrement, then the corresponding
451 * part of the schedule will be of the form [i] -> [-i]. Since such
452 * an inverse cannot be represented by "prefix", we invert the corresponding
453 * dimension of the iteration domain instead, taking care to also
454 * change the domains of all access relations accordingly.
456 * If 'stmt" has any arguments, then stmt->domain is a wrapped map
457 * and the transformation on the iteration domain only applies
458 * to the domain of that map. We therefore need to combine that
459 * transformation with an identity mapping on the range before
460 * applying it to the domain.
461 * Any arguments found are also converted into filters on the node
462 * domain. The original filter access functions are extended to
463 * filter access relations using the implications in "scop".
465 static pdg::node *extract_node(pdg::PDG *pdg, struct pet_scop *scop,
466 struct pet_stmt *stmt, std::map<isl_id *, pdg::array *> &id2array)
468 pdg::node *node = new pdg::node;
469 pdg::statement *stat;
470 int nr;
471 isl_space *space, *space_dom;
472 isl_set *dom;
473 isl_map *trans, *trans_dom;
474 isl_schedule_node *snode;
475 isl_union_set *universe;
476 enum isl_schedule_node_type type;
477 int i;
479 space = isl_set_get_space(stmt->domain);
480 if (isl_space_is_wrapping(space))
481 space = isl_space_domain(isl_space_unwrap(space));
482 space_dom = isl_space_copy(space);
483 trans = isl_map_universe(isl_space_map_from_set(space));
485 snode = isl_schedule_get_root(scop->schedule);
486 space = isl_space_copy(space_dom);
487 universe = isl_union_set_from_set(isl_set_universe(space));
488 i = 0;
489 while (snode) {
490 type = isl_schedule_node_get_type(snode);
491 assert(type != isl_schedule_node_error);
492 if (type == isl_schedule_node_leaf)
493 break;
494 if (type == isl_schedule_node_band) {
495 isl_union_map *umap;
496 isl_map *map, *test;
497 assert(isl_schedule_node_band_n_member(snode) == 1);
498 umap =
499 isl_schedule_node_band_get_partial_schedule_union_map(
500 snode);
501 umap = isl_union_map_intersect_domain(umap,
502 isl_union_set_copy(universe));
503 map = isl_map_from_union_map(umap);
504 space = isl_map_get_space(map);
505 test = isl_map_equal_dims(space, isl_dim_in, i,
506 isl_dim_out, 0);
507 if (isl_map_is_subset(map, test)) {
508 trans = isl_map_equate(trans, isl_dim_in, i,
509 isl_dim_out, i);
510 } else {
511 isl_map_free(test);
512 space = isl_map_get_space(map);
513 test = isl_map_opposite_dims(space,
514 isl_dim_in, i, isl_dim_out, 0);
515 assert(isl_map_is_subset(map, test));
516 trans = isl_map_oppose(trans, isl_dim_in, i,
517 isl_dim_out, i);
519 isl_map_free(test);
520 i++;
521 node->prefix.push_back(-1);
522 isl_map_free(map);
524 if (type == isl_schedule_node_sequence ||
525 type == isl_schedule_node_set) {
526 int pos;
528 pos = get_filter_pos(snode, space_dom);
529 node->prefix.push_back(pos);
530 snode = isl_schedule_node_child(snode, pos);
531 } else
532 snode = isl_schedule_node_child(snode, 0);
534 assert(snode);
535 isl_schedule_node_free(snode);
536 isl_union_set_free(universe);
538 dom = isl_set_copy(stmt->domain);
539 trans_dom = isl_map_copy(trans);
540 if (isl_set_is_wrapping(dom)) {
541 isl_space *space = isl_set_get_space(dom);
542 isl_map *id;
543 space = isl_space_range(isl_space_unwrap(space));
544 id = isl_map_identity(isl_space_map_from_set(space));
545 trans_dom = isl_map_product(trans_dom, id);
547 dom = isl_set_apply(dom, trans_dom);
548 dom = apply_filter_bounds(dom, stmt, id2array);
549 node->source = new pdg::IslSet(dom);
550 node->name = new str(isl_space_get_tuple_name(space_dom, isl_dim_set));
551 isl_space_free(space_dom);
553 stat = new pdg::statement;
554 node->statement = stat;
556 stat->line = pet_loc_get_line(stmt->loc);
558 for (int i = 0; i < stmt->n_arg; ++i) {
559 pdg::call_or_access *coa;
560 coa = convert_expr(pdg, stat, stmt->args[i], id2array, trans);
561 apply_implications(coa, scop, node->source->set, i);
562 node->filters.push_back(coa);
565 if (is_assignment(stmt->body)) {
566 pdg::access *access;
567 pet_expr *expr, *arg;
568 expr = pet_tree_expr_get_expr(stmt->body);
569 if (pet_expr_op_get_type(expr) != pet_op_assign) {
570 arg = pet_expr_get_arg(expr, 0);
571 access = extract_access(pdg, stat,
572 arg, id2array, trans);
573 pet_expr_free(arg);
574 access->type = pdg::access::read;
576 arg = pet_expr_get_arg(expr, 1);
577 stat->top_function = extract_top_function(pdg, stat,
578 arg, id2array, trans);
579 pet_expr_free(arg);
580 arg = pet_expr_get_arg(expr, 0);
581 access = extract_access(pdg, stat, arg, id2array, trans);
582 pet_expr_free(arg);
583 stat->top_outputs.push_back(access);
584 pet_expr_free(expr);
585 } else if (is_inc_dec(stmt->body)) {
586 pdg::access *access;
587 pet_expr *expr, *arg;
588 expr = pet_tree_expr_get_expr(stmt->body);
589 arg = pet_expr_get_arg(expr, 0);
590 access = extract_access(pdg, stat, arg, id2array, trans);
591 access->type = pdg::access::read;
592 stat->top_function = new pdg::function_call;
593 stat->top_function->name =
594 new str(pet_op_str(pet_expr_op_get_type(expr)));
595 access = extract_access(pdg, stat, arg, id2array, trans);
596 stat->top_outputs.push_back(access);
597 pet_expr_free(arg);
598 pet_expr_free(expr);
599 } else
600 stat->top_function = extract_top_function(pdg, stat,
601 stmt->body, id2array, trans);
603 nr = 0;
604 for (int i = 0; i < stat->accesses.size(); ++i)
605 if (stat->accesses[i]->type == pdg::access::read)
606 stat->accesses[i]->nr = nr++;
607 for (int i = 0; i < stat->accesses.size(); ++i)
608 if (stat->accesses[i]->type != pdg::access::read)
609 stat->accesses[i]->nr = nr++;
611 isl_map_free(trans);
613 return node;
616 /* Create and return a pdg::array corresponding to pa and add it
617 * to id2array.
619 static pdg::array *extract_array(pdg::PDG *pdg, struct pet_array *pa,
620 std::map<isl_id *, pdg::array *> &id2array)
622 isl_id *id = isl_set_get_tuple_id(pa->extent);
623 pdg::array *array = new pdg::array;
624 int dim = isl_set_dim(pa->extent, isl_dim_set);
626 array->name = new str(isl_id_get_name(id));
627 array->element_type = new str(pa->element_type);
628 for (int j = 0; j < dim; ++j) {
629 isl_space *dim;
630 isl_aff *obj;
631 isl_val *v;
633 dim = isl_set_get_space(pa->extent);
634 obj = isl_aff_zero_on_domain(isl_local_space_from_space(dim));
635 obj = isl_aff_add_coefficient_si(obj, isl_dim_in, j, 1);
636 v = isl_set_max_val(pa->extent, obj);
637 isl_aff_free(obj);
638 if (isl_val_is_int(v))
639 array->dims.push_back(isl_val_get_num_si(v) + 1);
640 else
641 array->dims.push_back(-1);
642 isl_val_free(v);
644 if (pa->value_bounds)
645 array->value_bounds =
646 new pdg::IslSet(isl_set_copy(pa->value_bounds));
647 array->uniquely_defined = pa->uniquely_defined;
649 id2array[id] = array;
651 isl_id_free(id);
653 return array;
656 /* Assign a default value to parameter "p", which corresponds
657 * to the parameter at position "i" in scop->context.
659 * If the parameter appears in scop->context_value and if
660 * it has a fixed value, then use that value.
661 * Otherwise find the minimual value of "p" in scop->context.
662 * It there is no minimal value, then we currently leave p->value unset.
664 static void set_default_parameter_value(pdg::parameter *p,
665 __isl_keep isl_id *id, struct pet_scop *scop, int i)
667 isl_space *space;
668 isl_aff *obj;
669 isl_val *v;
670 int pos;
672 pos = isl_set_find_dim_by_id(scop->context_value, isl_dim_param, id);
673 if (pos >= 0) {
674 v = isl_set_plain_get_val_if_fixed(scop->context_value,
675 isl_dim_param, pos);
676 if (isl_val_is_int(v)) {
677 p->value = new integer(isl_val_get_num_si(v));
678 isl_val_free(v);
679 return;
681 isl_val_free(v);
684 space = isl_set_get_space(scop->context);
685 obj = isl_aff_zero_on_domain(isl_local_space_from_space(space));
686 obj = isl_aff_add_coefficient_si(obj, isl_dim_param, i, 1);
687 v = isl_set_min_val(scop->context, obj);
688 isl_aff_free(obj);
689 if (isl_val_is_int(v))
690 p->value = new integer(isl_val_get_num_si(v));
692 isl_val_free(v);
695 extern "C" {
696 static isl_bool kill_array(__isl_keep isl_schedule_node *node,
697 void *user);
700 /* Internal data structure for kill_array.
701 * "id2kill_stmt" maps the tuple id of the instance set of a kill statement
702 * to the corresponding pet_stmt.
703 * "id2array" maps the array identifier to the corresponding constructed
704 * pdg::array.
706 struct kill_array_data {
707 std::map<isl_id *, struct pet_stmt *> &id2kill_stmt;
708 std::map<isl_id *, pdg::array *> &id2array;
711 /* Mark the array "accessed" by "expr" as killed.
712 * The expression is assumed to represent a kill of an entire array.
714 static int kill_array(__isl_keep pet_expr *expr, void *user)
716 kill_array_data *data = (kill_array_data *) user;
717 isl_id *id;
718 pdg::array *array;
720 id = pet_expr_access_get_id(expr);
721 array = data->id2array[id];
722 isl_id_free(id);
724 if (!array)
725 return -1;
726 array->killed = 1;
728 return 0;
731 /* Mark all arrays "accessed" by the statement with instance set "set"
732 * as killed.
734 static isl_stat kill_stmt_arrays(__isl_take isl_set *set, void *user)
736 kill_array_data *data = (kill_array_data *) user;
737 isl_id *id;
738 struct pet_stmt *stmt;
740 id = isl_set_get_tuple_id(set);
741 stmt = data->id2kill_stmt[id];
742 isl_id_free(id);
743 isl_set_free(set);
745 if (!stmt)
746 return isl_stat_error;
748 if (pet_tree_foreach_access_expr(stmt->body, &kill_array, data) < 0)
749 return isl_stat_error;
751 return isl_stat_ok;
754 /* Given a filter node "node", mark all arrays accessed by the statements
755 * corresponding to the instance set in the filter as killed.
756 * "id2kill_stmt" maps the tuple id of the instance set of a kill statement
757 * to the corresponding pet_stmt.
758 * "id2array" maps the array identifier to the corresponding constructed
759 * pdg::array.
761 static isl_stat kill_arrays(__isl_keep isl_schedule_node *node,
762 std::map<isl_id *, struct pet_stmt *> &id2kill_stmt,
763 std::map<isl_id *, pdg::array *> &id2array)
765 kill_array_data data = { id2kill_stmt, id2array };
766 isl_union_set *filter;
767 isl_stat ok;
769 filter = isl_schedule_node_filter_get_filter(node);
770 ok = isl_union_set_foreach_set(filter, &kill_stmt_arrays, &data);
771 isl_union_set_free(filter);
773 return ok;
776 /* Look for pieces of the schedule "schedule" that are executed after
777 * all other pieces and that consist of only instances in "kills".
778 * If any such pieces can be found, then mark all arrays accessed
779 * by the corresponding statements as killed.
780 * "id2kill_stmt" maps the tuple id of the instance set of a kill statement
781 * to the corresponding pet_stmt.
782 * "id2array" maps the array identifier to the corresponding constructed
783 * pdg::array.
785 static void kill_final(__isl_keep isl_schedule *schedule,
786 __isl_keep isl_union_set *kills,
787 std::map<isl_id *, struct pet_stmt *> &id2kill_stmt,
788 std::map<isl_id *, pdg::array *> &id2array)
790 int n;
791 isl_schedule_node *node;
793 node = isl_schedule_get_root(schedule);
794 node = isl_schedule_node_child(node, 0);
795 if (isl_schedule_node_get_type(node) == isl_schedule_node_context)
796 node = isl_schedule_node_child(node, 0);
797 if (isl_schedule_node_get_type(node) != isl_schedule_node_sequence) {
798 isl_schedule_node_free(node);
799 return;
802 n = isl_schedule_node_n_children(node);
803 node = isl_schedule_node_child(node, n - 1);
804 while (node) {
805 isl_union_set *filter;
806 int is_all_kill;
808 filter = isl_schedule_node_filter_get_filter(node);
809 is_all_kill = isl_union_set_is_subset(filter, kills);
810 isl_union_set_free(filter);
811 if (!is_all_kill)
812 break;
813 kill_arrays(node, id2kill_stmt, id2array);
814 if (!isl_schedule_node_has_previous_sibling(node))
815 break;
816 node = isl_schedule_node_previous_sibling(node);
819 isl_schedule_node_free(node);
822 int main(int argc, char **argv)
824 isl_ctx *ctx;
825 isl_union_set *kills;
826 struct options *options = options_new_with_defaults();
827 struct pet_scop *scop;
828 pdg::PDG *pdg;
829 int len;
830 char *output_name;
831 FILE *output;
832 int nparam;
833 char *slash;
834 std::map<isl_id *, pdg::array *> id2array;
835 std::map<isl_id *, struct pet_stmt *> id2kill_stmt;
837 ctx = isl_ctx_alloc_with_options(&options_args, options);
838 if (!ctx) {
839 fprintf(stderr, "Unable to allocate ctx\n");
840 return -1;
843 pdg = new pdg::PDG(ctx);
844 pdg->add_history_line("c2pdg", argc, argv);
845 pdg->placement = new str(string("original"));
847 pet_options_set_autodetect(ctx, 1);
848 argc = options_parse(options, argc, argv, ISL_ARG_ALL);
850 len = strlen(options->input);
851 if (len > 2 && !strcmp(options->input + len - 2, ".c"))
852 len -= 2;
853 output_name = isl_alloc_array(ctx, char, len + sizeof(dot_yaml));
854 assert(output_name);
855 memcpy(output_name, options->input, len);
856 memcpy(output_name + len, dot_yaml, sizeof(dot_yaml));
857 output = fopen(output_name, "w");
858 assert(output);
860 scop = pet_scop_extract_from_C_source(ctx, options->input,
861 options->function);
862 scop = pet_scop_align_params(scop);
863 assert(scop);
865 output_name[len] = '\0';
866 slash = strrchr(output_name, '/');
867 if (!slash)
868 slash = output_name;
869 pdg->name = new str(output_name);
871 nparam = isl_set_dim(scop->context, isl_dim_param);
872 for (int i = 0; i < nparam; ++i) {
873 isl_id *id = isl_set_get_dim_id(scop->context, isl_dim_param, i);
874 pdg::parameter *p = new pdg::parameter;
876 p->name = new str(isl_id_get_name(id));
877 set_default_parameter_value(p, id, scop, i);
879 pdg->params.push_back(p);
880 isl_id_free(id);
883 pdg->context = new pdg::IslSet(isl_set_copy(scop->context));
885 for (int i = 0; i < scop->n_array; ++i) {
886 pdg::array *array;
887 array = extract_array(pdg, scop->arrays[i], id2array);
888 pdg->arrays.push_back(array);
891 kills = isl_union_set_empty(isl_set_get_space(scop->context));
892 for (int i = 0, nodenr = 0; i < scop->n_stmt; ++i) {
893 pdg::node *node;
894 if (isl_set_is_empty(scop->stmts[i]->domain))
895 continue;
896 if (pet_stmt_is_kill(scop->stmts[i])) {
897 isl_set *domain = isl_set_copy(scop->stmts[i]->domain);
898 isl_id *id = isl_set_get_tuple_id(domain);
899 id2kill_stmt[id] = scop->stmts[i];
900 isl_id_free(id);
901 kills = isl_union_set_add_set(kills, domain);
902 continue;
904 node = extract_node(pdg, scop, scop->stmts[i], id2array);
905 node->nr = nodenr++;
906 pdg->nodes.push_back(node);
908 kill_final(scop->schedule, kills, id2kill_stmt, id2array);
909 isl_union_set_free(kills);
911 pdg->Dump(output);
912 pdg->free();
913 delete pdg;
915 pet_scop_free(scop);
917 fclose(output);
918 free(output_name);
920 isl_ctx_free(ctx);
921 return 0;