1 | /* |
2 | * Copyright 2012,2014 Ecole Normale Superieure |
3 | * |
4 | * Use of this software is governed by the MIT license |
5 | * |
6 | * Written by Sven Verdoolaege, |
7 | * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France |
8 | */ |
9 | |
10 | /* This program prints an AST that scans the domain elements of |
11 | * the domain of a given schedule in the order specified by |
12 | * the schedule tree or by their image(s) in the schedule map. |
13 | * |
14 | * The input consists of either a schedule tree or |
15 | * a sequence of three sets/relations. |
16 | * - a schedule map |
17 | * - a context |
18 | * - a relation describing AST generation options |
19 | */ |
20 | |
21 | #include <assert.h> |
22 | #include <stdlib.h> |
23 | #include <isl/ast.h> |
24 | #include <isl/ast_build.h> |
25 | #include <isl/options.h> |
26 | #include <isl/space.h> |
27 | #include <isl/set.h> |
28 | #include <isl/union_set.h> |
29 | #include <isl/union_map.h> |
30 | #include <isl/stream.h> |
31 | #include <isl/schedule_node.h> |
32 | |
33 | struct options { |
34 | struct isl_options *isl; |
35 | unsigned atomic; |
36 | unsigned separate; |
37 | }; |
38 | |
39 | ISL_ARGS_START(struct options, options_args) |
40 | ISL_ARG_CHILD(struct options, isl, "isl" , &isl_options_args, "isl options" ) |
41 | ISL_ARG_BOOL(struct options, atomic, 0, "atomic" , 0, |
42 | "globally set the atomic option" ) |
43 | ISL_ARG_BOOL(struct options, separate, 0, "separate" , 0, |
44 | "globally set the separate option" ) |
45 | ISL_ARGS_END |
46 | |
47 | ISL_ARG_DEF(cg_options, struct options, options_args) |
48 | ISL_ARG_CTX_DEF(cg_options, struct options, options_args) |
49 | |
50 | /* Return a universal, 1-dimensional set with the given name. |
51 | */ |
52 | static __isl_give isl_union_set *universe(isl_ctx *ctx, const char *name) |
53 | { |
54 | isl_space *space; |
55 | |
56 | space = isl_space_set_alloc(ctx, nparam: 0, dim: 1); |
57 | space = isl_space_set_tuple_name(space, type: isl_dim_set, s: name); |
58 | return isl_union_set_from_set(set: isl_set_universe(space)); |
59 | } |
60 | |
61 | /* Set the "name" option for the entire schedule domain. |
62 | */ |
63 | static __isl_give isl_union_map *set_universe(__isl_take isl_union_map *opt, |
64 | __isl_keep isl_union_map *schedule, const char *name) |
65 | { |
66 | isl_ctx *ctx; |
67 | isl_union_set *domain, *target; |
68 | isl_union_map *option; |
69 | |
70 | ctx = isl_union_map_get_ctx(umap: opt); |
71 | |
72 | domain = isl_union_map_range(umap: isl_union_map_copy(umap: schedule)); |
73 | domain = isl_union_set_universe(uset: domain); |
74 | target = universe(ctx, name); |
75 | option = isl_union_map_from_domain_and_range(domain, range: target); |
76 | opt = isl_union_map_union(umap1: opt, umap2: option); |
77 | |
78 | return opt; |
79 | } |
80 | |
81 | /* Update the build options based on the user-specified options. |
82 | * |
83 | * If the --separate or --atomic options were specified, then |
84 | * we clear any separate or atomic options that may already exist in "opt". |
85 | */ |
86 | static __isl_give isl_ast_build *set_options(__isl_take isl_ast_build *build, |
87 | __isl_take isl_union_map *opt, struct options *options, |
88 | __isl_keep isl_union_map *schedule) |
89 | { |
90 | if (options->separate || options->atomic) { |
91 | isl_ctx *ctx; |
92 | isl_union_set *target; |
93 | |
94 | ctx = isl_union_map_get_ctx(umap: schedule); |
95 | |
96 | target = universe(ctx, name: "separate" ); |
97 | opt = isl_union_map_subtract_range(umap: opt, dom: target); |
98 | target = universe(ctx, name: "atomic" ); |
99 | opt = isl_union_map_subtract_range(umap: opt, dom: target); |
100 | } |
101 | |
102 | if (options->separate) |
103 | opt = set_universe(opt, schedule, name: "separate" ); |
104 | if (options->atomic) |
105 | opt = set_universe(opt, schedule, name: "atomic" ); |
106 | |
107 | build = isl_ast_build_set_options(build, options: opt); |
108 | |
109 | return build; |
110 | } |
111 | |
112 | /* Construct an AST in case the schedule is specified by a union map. |
113 | * |
114 | * We read the context and the options from "s" and construct the AST. |
115 | */ |
116 | static __isl_give isl_ast_node *construct_ast_from_union_map( |
117 | __isl_take isl_union_map *schedule, __isl_keep isl_stream *s) |
118 | { |
119 | isl_set *context; |
120 | isl_union_map *options_map; |
121 | isl_ast_build *build; |
122 | isl_ast_node *tree; |
123 | struct options *options; |
124 | |
125 | options = isl_ctx_peek_cg_options(ctx: isl_stream_get_ctx(s)); |
126 | |
127 | context = isl_stream_read_set(s); |
128 | options_map = isl_stream_read_union_map(s); |
129 | |
130 | build = isl_ast_build_from_context(set: context); |
131 | build = set_options(build, opt: options_map, options, schedule); |
132 | tree = isl_ast_build_node_from_schedule_map(build, schedule); |
133 | isl_ast_build_free(build); |
134 | |
135 | return tree; |
136 | } |
137 | |
138 | /* If "node" is a band node, then replace the AST build options |
139 | * by "options". |
140 | */ |
141 | static __isl_give isl_schedule_node *node_set_options( |
142 | __isl_take isl_schedule_node *node, void *user) |
143 | { |
144 | enum isl_ast_loop_type *type = user; |
145 | int i; |
146 | isl_size n; |
147 | |
148 | if (isl_schedule_node_get_type(node) != isl_schedule_node_band) |
149 | return node; |
150 | |
151 | n = isl_schedule_node_band_n_member(node); |
152 | if (n < 0) |
153 | return isl_schedule_node_free(node); |
154 | for (i = 0; i < n; ++i) |
155 | node = isl_schedule_node_band_member_set_ast_loop_type(node, |
156 | pos: i, type: *type); |
157 | return node; |
158 | } |
159 | |
160 | /* Replace the AST build options on all band nodes if requested |
161 | * by the user. |
162 | */ |
163 | static __isl_give isl_schedule *schedule_set_options( |
164 | __isl_take isl_schedule *schedule, struct options *options) |
165 | { |
166 | enum isl_ast_loop_type type; |
167 | |
168 | if (!options->separate && !options->atomic) |
169 | return schedule; |
170 | |
171 | type = options->separate ? isl_ast_loop_separate : isl_ast_loop_atomic; |
172 | schedule = isl_schedule_map_schedule_node_bottom_up(schedule, |
173 | fn: &node_set_options, user: &type); |
174 | |
175 | return schedule; |
176 | } |
177 | |
178 | /* Construct an AST in case the schedule is specified by a schedule tree. |
179 | */ |
180 | static __isl_give isl_ast_node *construct_ast_from_schedule( |
181 | __isl_take isl_schedule *schedule) |
182 | { |
183 | isl_ast_build *build; |
184 | isl_ast_node *tree; |
185 | struct options *options; |
186 | |
187 | options = isl_ctx_peek_cg_options(ctx: isl_schedule_get_ctx(sched: schedule)); |
188 | |
189 | build = isl_ast_build_alloc(ctx: isl_schedule_get_ctx(sched: schedule)); |
190 | schedule = schedule_set_options(schedule, options); |
191 | tree = isl_ast_build_node_from_schedule(build, schedule); |
192 | isl_ast_build_free(build); |
193 | |
194 | return tree; |
195 | } |
196 | |
197 | /* Read an object from stdin. |
198 | * If it is a (union) map, then assume an input specified by |
199 | * schedule map, context and options and construct an AST from |
200 | * those elements |
201 | * If it is a schedule object, then construct the AST from the schedule. |
202 | */ |
203 | int main(int argc, char **argv) |
204 | { |
205 | isl_ctx *ctx; |
206 | isl_stream *s; |
207 | isl_ast_node *tree = NULL; |
208 | struct options *options; |
209 | isl_printer *p; |
210 | struct isl_obj obj; |
211 | int r = EXIT_SUCCESS; |
212 | |
213 | options = cg_options_new_with_defaults(); |
214 | assert(options); |
215 | ctx = isl_ctx_alloc_with_options(args: &options_args, opt: options); |
216 | isl_options_set_ast_build_detect_min_max(ctx, val: 1); |
217 | isl_options_set_ast_print_outermost_block(ctx, val: 0); |
218 | argc = cg_options_parse(opt: options, argc, argv, ISL_ARG_ALL); |
219 | |
220 | s = isl_stream_new_file(ctx, stdin); |
221 | obj = isl_stream_read_obj(s); |
222 | if (obj.v == NULL) { |
223 | r = EXIT_FAILURE; |
224 | } else if (obj.type == isl_obj_map) { |
225 | isl_union_map *umap; |
226 | |
227 | umap = isl_union_map_from_map(map: obj.v); |
228 | tree = construct_ast_from_union_map(schedule: umap, s); |
229 | } else if (obj.type == isl_obj_union_map) { |
230 | tree = construct_ast_from_union_map(schedule: obj.v, s); |
231 | } else if (obj.type == isl_obj_schedule) { |
232 | tree = construct_ast_from_schedule(schedule: obj.v); |
233 | } else { |
234 | obj.type->free(obj.v); |
235 | isl_die(ctx, isl_error_invalid, "unknown input" , |
236 | r = EXIT_FAILURE); |
237 | } |
238 | isl_stream_free(s); |
239 | |
240 | p = isl_printer_to_file(ctx, stdout); |
241 | p = isl_printer_set_output_format(p, ISL_FORMAT_C); |
242 | p = isl_printer_print_ast_node(p, node: tree); |
243 | isl_printer_free(printer: p); |
244 | |
245 | isl_ast_node_free(node: tree); |
246 | |
247 | isl_ctx_free(ctx); |
248 | return r; |
249 | } |
250 | |