update pet to version 0.11.2
[ppn.git] / pdg2c.cc
blob56b5c8ac31b729fc556f89102428580ad8c24d90
1 /* Convert a PDG extracted using c2pdg and possibly transformed back to C code.
2 */
3 #include <stdio.h>
4 #include <stdlib.h>
6 #include <isl/ctx.h>
7 #include <isl/id.h>
8 #include <isl/space.h>
9 #include <isl/aff.h>
10 #include <isl/map.h>
11 #include <isl/union_map.h>
12 #include <isl/ast.h>
13 #include <isl/ast_build.h>
14 #include <isl/id_to_ast_expr.h>
15 #include <isl/printer.h>
16 #include <pet.h>
18 #include <isa/pdg.h>
19 #include "pdg2c_options.h"
21 using pdg::PDG;
23 /* Find the element in scop->stmts that has the given "name".
25 static struct pet_stmt *find_stmt(struct pet_scop *scop, const char *name)
27 int i;
29 for (i = 0; i < scop->n_stmt; ++i) {
30 struct pet_stmt *stmt = scop->stmts[i];
31 const char *name_i;
33 name_i = isl_set_get_tuple_name(stmt->domain);
34 if (!strcmp(name, name_i))
35 return stmt;
38 return NULL;
41 extern "C" {
42 static __isl_give void free_isl_id_to_ast_expr(void *user);
43 static __isl_give isl_multi_pw_aff *pullback_index(
44 __isl_take isl_multi_pw_aff *mpa, __isl_keep isl_id *id, void *user);
45 static __isl_give isl_ast_node *at_each_domain(__isl_take isl_ast_node *node,
46 __isl_keep isl_ast_build *build, void *user);
47 static __isl_give isl_printer *transform(__isl_take isl_printer *p,
48 struct pet_scop *scop, void *user);
49 static __isl_give isl_printer *print_user(__isl_take isl_printer *p,
50 __isl_take isl_ast_print_options *print_options,
51 __isl_keep isl_ast_node *node, void *user);
54 static __isl_give void free_isl_id_to_ast_expr(void *user)
56 isl_id_to_ast_expr_free((isl_id_to_ast_expr *) user);
59 /* Find the element in scop->stmts that the same name
60 * as the function call by the given user node.
61 * These names are determined by the names of the domains
62 * of the schedule constructed in transform().
64 static pet_stmt *extract_pet_stmt(__isl_keep isl_ast_node *node,
65 struct pet_scop *scop)
67 isl_ast_expr *expr, *arg;
68 isl_id *id;
69 pet_stmt *stmt;
71 expr = isl_ast_node_user_get_expr(node);
72 arg = isl_ast_expr_get_op_arg(expr, 0);
73 isl_ast_expr_free(expr);
74 id = isl_ast_expr_get_id(arg);
75 isl_ast_expr_free(arg);
76 stmt = find_stmt(scop, isl_id_get_name(id));
77 isl_id_free(id);
79 return stmt;
82 /* Index transformation callback for pet_stmt_build_ast_exprs.
84 * "index" expresses the array indices in terms of statement iterators
85 * "iterator_map" expresses the statement iterators in terms of
86 * AST loop iterators.
88 * The result expresses the array indices in terms of
89 * AST loop iterators.
91 static __isl_give isl_multi_pw_aff *pullback_index(
92 __isl_take isl_multi_pw_aff *index, __isl_keep isl_id *id, void *user)
94 isl_pw_multi_aff *iterator_map = (isl_pw_multi_aff *) user;
96 iterator_map = isl_pw_multi_aff_copy(iterator_map);
97 return isl_multi_pw_aff_pullback_pw_multi_aff(index, iterator_map);
100 /* Transform the accesses in the statement associated to the domain
101 * called by "node" to refer to the AST loop iterators, construct
102 * corresponding AST expressions using "build" and attach them
103 * to the node.
105 static __isl_give isl_ast_node *at_each_domain(__isl_take isl_ast_node *node,
106 __isl_keep isl_ast_build *build, void *user)
108 const char *name;
109 pet_stmt *stmt;
110 isl_ctx *ctx;
111 isl_id *id;
112 isl_map *map;
113 isl_pw_multi_aff *iterator_map;
114 isl_id_to_ast_expr *ref2expr;
115 struct pet_scop *scop = (struct pet_scop *) user;
117 ctx = isl_ast_node_get_ctx(node);
119 stmt = extract_pet_stmt(node, scop);
120 if (!stmt)
121 isl_die(ctx, isl_error_internal, "cannot find statement",
122 isl_ast_node_free(node); node = NULL);
124 map = isl_map_from_union_map(isl_ast_build_get_schedule(build));
125 map = isl_map_reverse(map);
126 iterator_map = isl_pw_multi_aff_from_map(map);
127 ref2expr = pet_stmt_build_ast_exprs(stmt, build,
128 &pullback_index, iterator_map, NULL, NULL);
129 isl_pw_multi_aff_free(iterator_map);
131 id = isl_id_alloc(ctx, NULL, ref2expr);
132 id = isl_id_set_free_user(id, &free_isl_id_to_ast_expr);
134 return isl_ast_node_set_annotation(node, id);
137 /* Print the statement corresponding to "node" to "p".
138 * We look for the statement in the pet_scop passed through "user".
139 * The AST expressions for all references in the statement
140 * have been attached to the node by at_each_domain().
142 static __isl_give isl_printer *print_user(__isl_take isl_printer *p,
143 __isl_take isl_ast_print_options *print_options,
144 __isl_keep isl_ast_node *node, void *user)
146 isl_id_to_ast_expr *ref2expr;
147 isl_id *id;
148 struct pet_stmt *stmt;
149 struct pet_scop *scop = (struct pet_scop *) user;
151 stmt = extract_pet_stmt(node, scop);
153 id = isl_ast_node_get_annotation(node);
154 ref2expr = (isl_id_to_ast_expr *) isl_id_get_user(id);
155 isl_id_free(id);
157 p = pet_stmt_print_body(stmt, p, ref2expr);
159 isl_ast_print_options_free(print_options);
161 return p;
164 /* Transform "scop" based on the schedule stored in "pdg" and
165 * print the result to "p".
167 static __isl_give isl_printer *transform(__isl_take isl_printer *p,
168 struct pet_scop *scop, void *user)
170 PDG *pdg = (PDG *) user;
171 isl_ctx *ctx;
172 isl_ast_build *build;
173 isl_ast_node *tree;
174 isl_ast_print_options *print_options;
175 isl_union_map *sched;
177 ctx = isl_printer_get_ctx(p);
178 build = isl_ast_build_from_context(pdg->get_context_isl_set());
179 build = isl_ast_build_set_at_each_domain(build, &at_each_domain, scop);
180 sched = isl_union_map_empty(isl_space_params_alloc(ctx, 0));
182 for (int i = 0; i < pdg->nodes.size(); ++i) {
183 const char *name;
184 isl_id *id;
185 isl_set *source;
186 isl_map *map;
188 if (!pdg->nodes[i]->schedule)
189 isl_die(ctx, isl_error_internal, "Missing schedule",
190 isl_union_map_free(sched); sched = NULL);
191 if (!pdg->nodes[i]->name)
192 isl_die(ctx, isl_error_internal, "Missing node name",
193 isl_union_map_free(sched); sched = NULL);
194 if (!sched)
195 break;
197 name = pdg->nodes[i]->name->s.c_str();
199 source = pdg->nodes[i]->source->get_isl_set(ctx);
201 map = pdg->nodes[i]->schedule->get_isl_map(ctx);
202 map = isl_map_intersect_domain(map, source);
203 id = isl_id_alloc(ctx, name, NULL);
204 map = isl_map_set_tuple_id(map, isl_dim_in, id);
206 sched = isl_union_map_add_map(sched, map);
209 tree = isl_ast_build_ast_from_schedule(build, sched);
210 isl_ast_build_free(build);
212 p = isl_ast_node_print_macros(tree, p);
214 print_options = isl_ast_print_options_alloc(ctx);
215 print_options = isl_ast_print_options_set_print_user(print_options,
216 &print_user, scop);
217 p = isl_ast_node_print(tree, p, print_options);
219 isl_ast_node_free(tree);
221 pet_scop_free(scop);
222 return p;
225 /* Given a C source code file and a PDG that is assumed to correspond
226 * to the first and only scop in this source code, print out the transformed
227 * C code based on the schedule of the PDG.
228 * The original PDG is assumed to have been extracted using c2pdg from
229 * the same source file.
231 int main(int argc, char **argv)
233 isl_ctx *ctx;
234 PDG *pdg;
235 FILE *input = stdin;
236 FILE *output = stdout;
237 struct options *options = options_new_with_defaults();
239 ctx = isl_ctx_alloc_with_options(&options_args, options);
240 if (!ctx) {
241 fprintf(stderr, "Unable to allocate ctx\n");
242 return EXIT_FAILURE;
245 pet_options_set_autodetect(ctx, 1);
246 argc = options_parse(options, argc, argv, ISL_ARG_ALL);
248 if (options->input_pdg && strcmp(options->input_pdg, "-")) {
249 input = fopen(options->input_pdg, "r");
250 assert(input);
252 if (options->output && strcmp(options->output, "-")) {
253 output = fopen(options->output, "w");
254 assert(output);
256 pdg = PDG::Load(input, ctx);
257 assert(pdg);
259 if (pet_transform_C_source(ctx, options->input_C, output,
260 &transform, pdg) < 0)
261 return EXIT_FAILURE;
263 pdg->free();
264 delete pdg;
266 if (output != stdout)
267 fclose(output);
269 isl_ctx_free(ctx);
270 return EXIT_SUCCESS;