1 /*
2  * Copyright 2014      Ecole Normale Superieure. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *    1. Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *
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.
15  *
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.
27  *
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.
32  */
33 
34 #include <isl/ctx.h>
35 #include <isl/printer.h>
36 #include <isl/id.h>
37 #include <isl/space.h>
38 #include <isl/union_set.h>
39 #include <isl/union_map.h>
40 
41 #include "aff.h"
42 #include "summary.h"
43 
44 /* A pet_function_summary objects represents an argument of a function.
45  *
46  * If "type" is pet_arg_int, then the argument has an integer type and
47  * can be used to describe the accesses performed by the pet_arg_array
48  * arguments.  In this case, "id" refers to the formal argument.
49  *
50  * If "type" is pet_arg_array, then we keep track of the accesses
51  * through this argument in the access relations in "access".
52  * The domains of these access relations refer to the integer arguments
53  * of the function.  That is, the input dimensions correspond
54  * to the arguments of type pet_arg_int.
55  *
56  * If "type" is pet_arg_other, then we do not keep track of any
57  * further information.
58  */
59 struct pet_function_summary_arg {
60 	enum pet_arg_type type;
61 
62 	union {
63 		isl_id *id;
64 		isl_union_map *access[pet_expr_access_end];
65 	};
66 };
67 
68 /* A pet_function_summary object keeps track of the accesses performed
69  * by a function in terms of the function arguments.
70  *
71  * "n" is the number of arguments.
72  * "arg" contains a description of the "n" arguments.
73  */
74 struct pet_function_summary {
75 	int ref;
76 	isl_ctx *ctx;
77 
78 	unsigned n;
79 
80 	struct pet_function_summary_arg arg[];
81 };
82 
83 /* Construct and return a new pet_function_summary object with
84  * "n_arg" arguments, initialized to pet_arg_other.
85  */
pet_function_summary_alloc(isl_ctx * ctx,unsigned n_arg)86 __isl_give pet_function_summary *pet_function_summary_alloc(isl_ctx *ctx,
87 	unsigned n_arg)
88 {
89 	pet_function_summary *summary;
90 	int i;
91 
92 	summary = isl_calloc(ctx, struct pet_function_summary,
93 			    sizeof(struct pet_function_summary) +
94 			    n_arg * sizeof(struct pet_function_summary_arg));
95 	if (!summary)
96 		return summary;
97 
98 	summary->ctx = ctx;
99 	isl_ctx_ref(ctx);
100 	summary->ref = 1;
101 	summary->n = n_arg;
102 	for (i = 0; i < n_arg; ++i)
103 		summary->arg[i].type = pet_arg_other;
104 
105 	return summary;
106 }
107 
108 /* Return an extra reference to "summary".
109  */
pet_function_summary_copy(__isl_keep pet_function_summary * summary)110 __isl_give pet_function_summary *pet_function_summary_copy(
111 	__isl_keep pet_function_summary *summary)
112 {
113 	if (!summary)
114 		return NULL;
115 
116 	summary->ref++;
117 	return summary;
118 }
119 
120 /* Return the isl_ctx in which "summary" was created.
121  */
pet_function_summary_get_ctx(__isl_keep pet_function_summary * summary)122 isl_ctx *pet_function_summary_get_ctx(__isl_keep pet_function_summary *summary)
123 {
124 	return summary ? summary->ctx : NULL;
125 }
126 
127 /* Free the data stored in "arg".
128  */
free_arg(struct pet_function_summary_arg * arg)129 static void free_arg(struct pet_function_summary_arg *arg)
130 {
131 	enum pet_expr_access_type type;
132 
133 	if (arg->type == pet_arg_int)
134 		isl_id_free(arg->id);
135 	if (arg->type != pet_arg_array)
136 		return;
137 	for (type = pet_expr_access_begin; type < pet_expr_access_end; ++type)
138 		arg->access[type] = isl_union_map_free(arg->access[type]);
139 }
140 
141 /* Free a reference to "summary".
142  */
pet_function_summary_free(__isl_take pet_function_summary * summary)143 __isl_null pet_function_summary *pet_function_summary_free(
144 	__isl_take pet_function_summary *summary)
145 {
146 	int i;
147 
148 	if (!summary)
149 		return NULL;
150 	if (--summary->ref > 0)
151 		return NULL;
152 
153 	for (i = 0; i < summary->n; ++i)
154 		free_arg(&summary->arg[i]);
155 
156 	isl_ctx_deref(summary->ctx);
157 	free(summary);
158 	return NULL;
159 }
160 
161 /* Return the number of arguments of the function summarized by "summary".
162  */
pet_function_summary_get_n_arg(__isl_keep pet_function_summary * summary)163 int pet_function_summary_get_n_arg(__isl_keep pet_function_summary *summary)
164 {
165 	if (!summary)
166 		return -1;
167 
168 	return summary->n;
169 }
170 
171 /* Mark the argument at position "pos" of "summary" as an integer argument
172  * with the given identifier.
173  */
pet_function_summary_set_int(__isl_take pet_function_summary * summary,int pos,__isl_take isl_id * id)174 __isl_give pet_function_summary *pet_function_summary_set_int(
175 	__isl_take pet_function_summary *summary, int pos,
176 	__isl_take isl_id *id)
177 {
178 	if (!summary || !id)
179 		goto error;
180 
181 	if (pos < 0 || pos >= summary->n)
182 		isl_die(summary->ctx, isl_error_invalid,
183 			"position out of bounds", goto error);
184 
185 	free_arg(&summary->arg[pos]);
186 
187 	summary->arg[pos].type = pet_arg_int;
188 	summary->arg[pos].id = id;
189 
190 	return summary;
191 error:
192 	isl_id_free(id);
193 	return pet_function_summary_free(summary);
194 }
195 
196 /* Mark the argument at position "pos" of "summary" as an array argument
197  * with the given sets of accessed elements.
198  * The integer arguments of "summary" may appear as parameters
199  * in these sets of accessed elements.
200  * These parameters are turned into input dimensions of
201  * the corresponding access relations, which are then associated
202  * to the array argument.
203  * The order of the input dimensions is the same as the order
204  * in which the integer arguments appear in the sequence of arguments.
205  */
pet_function_summary_set_array(__isl_take pet_function_summary * summary,int pos,__isl_take isl_union_set * may_read,__isl_take isl_union_set * may_write,__isl_take isl_union_set * must_write)206 __isl_give pet_function_summary *pet_function_summary_set_array(
207 	__isl_take pet_function_summary *summary, int pos,
208 	__isl_take isl_union_set *may_read, __isl_take isl_union_set *may_write,
209 	__isl_take isl_union_set *must_write)
210 {
211 	int i, n;
212 	isl_space *space;
213 	enum pet_expr_access_type type;
214 
215 	if (!summary || !may_read || !may_write || !must_write)
216 		goto error;
217 
218 	if (pos < 0 || pos >= summary->n)
219 		isl_die(summary->ctx, isl_error_invalid,
220 			"position out of bounds", goto error);
221 
222 	n = 0;
223 	for (i = 0; i < summary->n; ++i)
224 		if (pet_function_summary_arg_is_int(summary, i))
225 			n++;
226 
227 	space = isl_space_params_alloc(summary->ctx, n);
228 
229 	n = 0;
230 	for (i = 0; i < summary->n; ++i)
231 		if (pet_function_summary_arg_is_int(summary, i))
232 			space = isl_space_set_dim_id(space, isl_dim_param, n++,
233 					    isl_id_copy(summary->arg[i].id));
234 
235 	free_arg(&summary->arg[pos]);
236 
237 	summary->arg[pos].type = pet_arg_array;
238 	summary->arg[pos].access[pet_expr_access_may_read] =
239 		isl_union_map_from_range(may_read);
240 	summary->arg[pos].access[pet_expr_access_may_write] =
241 		isl_union_map_from_range(may_write);
242 	summary->arg[pos].access[pet_expr_access_must_write] =
243 		isl_union_map_from_range(must_write);
244 
245 	for (type = pet_expr_access_begin; type < pet_expr_access_end; ++type) {
246 		isl_union_map *umap;
247 		umap = summary->arg[pos].access[type];
248 		umap = isl_union_map_align_params(umap, isl_space_copy(space));
249 		umap = pet_union_map_move_dims(umap, isl_dim_in, 0,
250 						isl_dim_param, 0, n);
251 		summary->arg[pos].access[type] = umap;
252 		if (!umap)
253 			break;
254 	}
255 
256 	isl_space_free(space);
257 
258 	if (type < pet_expr_access_end)
259 		return pet_function_summary_free(summary);
260 
261 	return summary;
262 error:
263 	isl_union_set_free(may_read);
264 	isl_union_set_free(may_write);
265 	isl_union_set_free(must_write);
266 	return pet_function_summary_free(summary);
267 }
268 
269 /* Has the argument of "summary" at position "pos" been marked
270  * as an integer argument?
271  */
pet_function_summary_arg_is_int(__isl_keep pet_function_summary * summary,int pos)272 int pet_function_summary_arg_is_int(__isl_keep pet_function_summary *summary,
273 	int pos)
274 {
275 	if (!summary)
276 		return -1;
277 
278 	if (pos < 0 || pos >= summary->n)
279 		isl_die(summary->ctx, isl_error_invalid,
280 			"position out of bounds", return -1);
281 
282 	return summary->arg[pos].type == pet_arg_int;
283 }
284 
285 /* Has the argument of "summary" at position "pos" been marked
286  * as an array argument?
287  */
pet_function_summary_arg_is_array(__isl_keep pet_function_summary * summary,int pos)288 int pet_function_summary_arg_is_array(__isl_keep pet_function_summary *summary,
289 	int pos)
290 {
291 	if (!summary)
292 		return -1;
293 
294 	if (pos < 0 || pos >= summary->n)
295 		isl_die(summary->ctx, isl_error_invalid,
296 			"position out of bounds", return -1);
297 
298 	return summary->arg[pos].type == pet_arg_array;
299 }
300 
301 /* Return the access relation of type "type" associated to
302  * the argument of "summary" at position "pos", which is assumed
303  * to be an array argument.
304  */
pet_function_summary_arg_get_access(__isl_keep pet_function_summary * summary,int pos,enum pet_expr_access_type type)305 __isl_give isl_union_map *pet_function_summary_arg_get_access(
306 	__isl_keep pet_function_summary *summary, int pos,
307 	enum pet_expr_access_type type)
308 {
309 	if (!summary)
310 		return NULL;
311 	if (pos < 0 || pos >= summary->n)
312 		isl_die(summary->ctx, isl_error_invalid,
313 			"position out of bounds", return NULL);
314 	if (summary->arg[pos].type != pet_arg_array)
315 		isl_die(summary->ctx, isl_error_invalid,
316 			"not an array argument", return NULL);
317 
318 	return isl_union_map_copy(summary->arg[pos].access[type]);
319 }
320 
321 /* Print "summary" to "p" in YAML format.
322  */
pet_function_summary_print(__isl_keep pet_function_summary * summary,__isl_take isl_printer * p)323 __isl_give isl_printer *pet_function_summary_print(
324 	__isl_keep pet_function_summary *summary, __isl_take isl_printer *p)
325 {
326 	int i;
327 
328 	if (!summary || !p)
329 		return isl_printer_free(p);
330 	p = isl_printer_yaml_start_sequence(p);
331 	for (i = 0; i < summary->n; ++i) {
332 		switch (summary->arg[i].type) {
333 		case pet_arg_int:
334 			p = isl_printer_yaml_start_mapping(p);
335 			p = isl_printer_print_str(p, "id");
336 			p = isl_printer_yaml_next(p);
337 			p = isl_printer_print_id(p, summary->arg[i].id);
338 			p = isl_printer_yaml_next(p);
339 			p = isl_printer_yaml_end_mapping(p);
340 			break;
341 		case pet_arg_other:
342 			p = isl_printer_print_str(p, "other");
343 			break;
344 		case pet_arg_array:
345 			p = isl_printer_yaml_start_mapping(p);
346 			p = isl_printer_print_str(p, "may_read");
347 			p = isl_printer_yaml_next(p);
348 			p = isl_printer_print_union_map(p,
349 			    summary->arg[i].access[pet_expr_access_may_read]);
350 			p = isl_printer_yaml_next(p);
351 			p = isl_printer_print_str(p, "may_write");
352 			p = isl_printer_yaml_next(p);
353 			p = isl_printer_print_union_map(p,
354 			    summary->arg[i].access[pet_expr_access_may_write]);
355 			p = isl_printer_yaml_next(p);
356 			p = isl_printer_print_str(p, "must_write");
357 			p = isl_printer_yaml_next(p);
358 			p = isl_printer_print_union_map(p,
359 			    summary->arg[i].access[pet_expr_access_must_write]);
360 			p = isl_printer_yaml_next(p);
361 			p = isl_printer_yaml_end_mapping(p);
362 			break;
363 		}
364 	}
365 	p = isl_printer_yaml_end_sequence(p);
366 
367 	return p;
368 }
369 
370 /* Dump "summary" to stderr.
371  */
pet_function_summary_dump(__isl_keep pet_function_summary * summary)372 void pet_function_summary_dump(__isl_keep pet_function_summary *summary)
373 {
374 	isl_printer *p;
375 
376 	if (!summary)
377 		return;
378 
379 	p = isl_printer_to_file(pet_function_summary_get_ctx(summary), stderr);
380 	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK);
381 	p = pet_function_summary_print(summary, p);
382 
383 	isl_printer_free(p);
384 }
385