1 /*
2  * Copyright 2012-2013 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 #include <isl/aff.h>
11 #include <isl/ast_build.h>
12 #include <isl/id.h>
13 
14 #include "print.h"
15 #include "util.h"
16 
ppcg_start_block(__isl_take isl_printer * p)17 __isl_give isl_printer *ppcg_start_block(__isl_take isl_printer *p)
18 {
19 	p = isl_printer_start_line(p);
20 	p = isl_printer_print_str(p, "{");
21 	p = isl_printer_end_line(p);
22 	p = isl_printer_indent(p, 2);
23 	return p;
24 }
25 
ppcg_end_block(__isl_take isl_printer * p)26 __isl_give isl_printer *ppcg_end_block(__isl_take isl_printer *p)
27 {
28 	p = isl_printer_indent(p, -2);
29 	p = isl_printer_start_line(p);
30 	p = isl_printer_print_str(p, "}");
31 	p = isl_printer_end_line(p);
32 	return p;
33 }
34 
35 /* Names of notes that keep track of whether min/max
36  * macro definitions have already been printed.
37  */
38 static const char *ppcg_max_printed = "ppcg_max_printed";
39 static const char *ppcg_min_printed = "ppcg_min_printed";
40 
41 /* Has the macro definition corresponding to "note_name" been printed
42  * to "p" before?
43  * That is, does "p" have an associated "note_name" note?
44  */
printed_before(__isl_keep isl_printer * p,const char * note_name)45 static isl_bool printed_before(__isl_keep isl_printer *p, const char *note_name)
46 {
47 	isl_ctx *ctx;
48 	isl_id *id;
49 	isl_bool printed;
50 
51 	if (!p)
52 		return isl_bool_error;
53 
54 	ctx = isl_printer_get_ctx(p);
55 	id = isl_id_alloc(ctx, note_name, NULL);
56 	printed = isl_printer_has_note(p, id);
57 	isl_id_free(id);
58 
59 	return printed;
60 }
61 
62 /* Keep track of the fact that the macro definition corresponding
63  * to "note_name" has been printed to "p" by attaching a note with
64  * that name.  The value of the note is of no importance, but it
65  * has to be a valid isl_id, so the note identifier is reused
66  * as the note.
67  */
mark_printed(__isl_take isl_printer * p,const char * note_name)68 static __isl_give isl_printer *mark_printed(__isl_take isl_printer *p,
69 	const char *note_name)
70 {
71 	isl_ctx *ctx;
72 	isl_id *id;
73 
74 	if (!p)
75 		return NULL;
76 
77 	ctx = isl_printer_get_ctx(p);
78 	id = isl_id_alloc(ctx, note_name, NULL);
79 	return isl_printer_set_note(p, id, isl_id_copy(id));
80 }
81 
82 /* Print a macro definition "def" for the macro "name" to "p",
83  * unless such a macro definition has been printed to "p" before.
84  * "note_name" is used as the name of the note that keeps track
85  * of whether this printing has happened.
86  */
print_ppcg_macro(__isl_take isl_printer * p,const char * name,const char * def,const char * note_name)87 static __isl_give isl_printer *print_ppcg_macro(__isl_take isl_printer *p,
88 	const char *name, const char *def, const char *note_name)
89 {
90 	isl_bool printed;
91 
92 	printed = printed_before(p, note_name);
93 	if (printed < 0)
94 		return isl_printer_free(p);
95 	if (printed)
96 		return p;
97 
98 	p = isl_printer_start_line(p);
99 	p = isl_printer_print_str(p, "#define ");
100 	p = isl_printer_print_str(p, name);
101 	p = isl_printer_print_str(p, def);
102 	p = isl_printer_end_line(p);
103 
104 	p = mark_printed(p, note_name);
105 
106 	return p;
107 }
108 
109 /* Structure for keeping track of definitions of some macros.
110  */
111 struct ppcg_macros {
112 	const char *min;
113 	const char *max;
114 };
115 
116 /* Free the memory allocated by a struct ppcg_macros.
117  */
ppcg_macros_free(void * user)118 static void ppcg_macros_free(void *user)
119 {
120 	free(user);
121 }
122 
123 /* Default macro definitions (when GNU extensions are allowed).
124  */
125 struct ppcg_macros ppcg_macros_default = {
126 	.min = "(x,y)    "
127 		"({ __typeof__(x) _x = (x); __typeof__(y) _y = (y); "
128 		"_x < _y ? _x : _y; })",
129 	.max = "(x,y)    "
130 		"({ __typeof__(x) _x = (x); __typeof__(y) _y = (y); "
131 		"_x > _y ? _x : _y; })",
132 };
133 
134 /* Name used for the note that keeps track of macro definitions.
135  */
136 static const char *ppcg_macros = "ppcg_macros";
137 
138 /* Set the macro definitions for isl_ast_op_min and isl_ast_op_max
139  * to "min" and "max" and store them in "p".
140  *
141  * In particular, create a ppcg_macros object and attach it
142  * as a note to the printer.
143  */
ppcg_set_macros(__isl_take isl_printer * p,const char * min,const char * max)144 __isl_give isl_printer *ppcg_set_macros(__isl_take isl_printer *p,
145 	const char *min, const char *max)
146 {
147 	isl_ctx *ctx;
148 	isl_id *id, *macros_id;
149 	struct ppcg_macros *macros;
150 
151 	if (!p)
152 		return NULL;
153 
154 	ctx = isl_printer_get_ctx(p);
155 	macros = isl_alloc_type(ctx, struct ppcg_macros);
156 	if (!macros)
157 		return isl_printer_free(p);
158 	macros->min = min;
159 	macros->max = max;
160 	id = isl_id_alloc(ctx, ppcg_macros, NULL);
161 	macros_id = isl_id_alloc(ctx, NULL, macros);
162 	if (!macros_id)
163 		ppcg_macros_free(macros);
164 	else
165 		macros_id = isl_id_set_free_user(macros_id, &ppcg_macros_free);
166 
167 	p = isl_printer_set_note(p, id, macros_id);
168 
169 	return p;
170 }
171 
172 /* Return the ppcg_macros object that holds the currently active
173  * macro definitions in "p".
174  * If "p" has a note with macro definitions, then return those.
175  * Otherwise, return the default macro definitions.
176  */
get_macros(__isl_keep isl_printer * p)177 static struct ppcg_macros *get_macros(__isl_keep isl_printer *p)
178 {
179 	isl_id *id;
180 	isl_bool has_macros;
181 	struct ppcg_macros *macros;
182 
183 	id = isl_id_alloc(isl_printer_get_ctx(p), ppcg_macros, NULL);
184 	has_macros = isl_printer_has_note(p, id);
185 	if (has_macros < 0 || !has_macros) {
186 		isl_id_free(id);
187 		if (has_macros < 0)
188 			return NULL;
189 		return &ppcg_macros_default;
190 	}
191 	id = isl_printer_get_note(p, id);
192 	macros = isl_id_get_user(id);
193 	isl_id_free(id);
194 
195 	return macros;
196 }
197 
198 /* Print the currently active macro definition for ppcg_max.
199  */
print_max(__isl_take isl_printer * p)200 static __isl_give isl_printer *print_max(__isl_take isl_printer *p)
201 {
202 	struct ppcg_macros *macros;
203 
204 	macros = get_macros(p);
205 	if (!macros)
206 		return isl_printer_free(p);
207 	return print_ppcg_macro(p, ppcg_max, macros->max, ppcg_max_printed);
208 }
209 
210 /* Print the currently active macro definition for ppcg_min.
211  */
print_min(__isl_take isl_printer * p)212 static __isl_give isl_printer *print_min(__isl_take isl_printer *p)
213 {
214 	struct ppcg_macros *macros;
215 
216 	macros = get_macros(p);
217 	if (!macros)
218 		return isl_printer_free(p);
219 	return print_ppcg_macro(p, ppcg_min, macros->min, ppcg_min_printed);
220 }
221 
222 /* Print a macro definition for "type" to "p".
223  * If GNU extensions are allowed, then print a specialized definition
224  * for isl_ast_op_min and isl_ast_op_max.
225  * Otherwise, use the default isl definition.
226  */
ppcg_print_macro(enum isl_ast_op_type type,__isl_take isl_printer * p)227 __isl_give isl_printer *ppcg_print_macro(enum isl_ast_op_type type,
228 	__isl_take isl_printer *p)
229 {
230 	isl_ctx *ctx;
231 	struct ppcg_options *options;
232 
233 	if (!p)
234 		return NULL;
235 
236 	ctx = isl_printer_get_ctx(p);
237 	options = isl_ctx_peek_options(ctx, &ppcg_options_args);
238 	if (!options || !options->allow_gnu_extensions)
239 		return isl_ast_op_type_print_macro(type, p);
240 
241 	switch (type) {
242 	case isl_ast_op_max:
243 		return print_max(p);
244 	case isl_ast_op_min:
245 		return print_min(p);
246 	default:
247 		return isl_ast_op_type_print_macro(type, p);
248 	}
249 }
250 
251 /* isl_ast_expr_foreach_ast_op_type or isl_ast_node_foreach_ast_op_type
252  * callback that prints a macro definition for "type".
253  */
print_macro(enum isl_ast_op_type type,void * user)254 static isl_stat print_macro(enum isl_ast_op_type type, void *user)
255 {
256 	isl_printer **p = user;
257 
258 	*p = ppcg_print_macro(type, *p);
259 	if (!*p)
260 		return isl_stat_error;
261 
262 	return isl_stat_ok;
263 }
264 
265 /* Print the required macros for "expr".
266  */
ppcg_ast_expr_print_macros(__isl_keep isl_ast_expr * expr,__isl_take isl_printer * p)267 __isl_give isl_printer *ppcg_ast_expr_print_macros(
268 	__isl_keep isl_ast_expr *expr, __isl_take isl_printer *p)
269 {
270 	if (isl_ast_expr_foreach_ast_op_type(expr, &print_macro, &p) < 0)
271 		return isl_printer_free(p);
272 	return p;
273 }
274 
275 /* isl_id_to_ast_expr_foreach callback that prints the required
276  * macro definitions for "val".
277  */
print_expr_macros(__isl_take isl_id * key,__isl_take isl_ast_expr * val,void * user)278 static isl_stat print_expr_macros(__isl_take isl_id *key,
279 	__isl_take isl_ast_expr *val, void *user)
280 {
281 	isl_printer **p = user;
282 
283 	*p = ppcg_ast_expr_print_macros(val, *p);
284 	isl_id_free(key);
285 	isl_ast_expr_free(val);
286 
287 	if (!*p)
288 		return isl_stat_error;
289 	return isl_stat_ok;
290 }
291 
292 /* Print the required macro definitions for the body of a statement in which
293  * the access expressions are replaced by the isl_ast_expr objects
294  * in "ref2expr".
295  */
ppcg_print_body_macros(__isl_take isl_printer * p,__isl_keep isl_id_to_ast_expr * ref2expr)296 __isl_give isl_printer *ppcg_print_body_macros(__isl_take isl_printer *p,
297 	__isl_keep isl_id_to_ast_expr *ref2expr)
298 {
299 	if (isl_id_to_ast_expr_foreach(ref2expr, &print_expr_macros, &p) < 0)
300 		return isl_printer_free(p);
301 	return p;
302 }
303 
304 /* Print the required macros for "node".
305  */
ppcg_print_macros(__isl_take isl_printer * p,__isl_keep isl_ast_node * node)306 __isl_give isl_printer *ppcg_print_macros(__isl_take isl_printer *p,
307 	__isl_keep isl_ast_node *node)
308 {
309 	if (isl_ast_node_foreach_ast_op_type(node, &print_macro, &p) < 0)
310 		return isl_printer_free(p);
311 	return p;
312 }
313 
314 /* Names used for the macros that may appear in a printed isl AST.
315  */
316 const char *ppcg_min = "ppcg_min";
317 const char *ppcg_max = "ppcg_max";
318 const char *ppcg_fdiv_q = "ppcg_fdiv_q";
319 
320 /* Set the names of the macros that may appear in a printed isl AST.
321  */
ppcg_set_macro_names(__isl_take isl_printer * p)322 __isl_give isl_printer *ppcg_set_macro_names(__isl_take isl_printer *p)
323 {
324 	p = isl_ast_op_type_set_print_name(p, isl_ast_op_min, ppcg_min);
325 	p = isl_ast_op_type_set_print_name(p, isl_ast_op_max, ppcg_max);
326 	p = isl_ast_op_type_set_print_name(p, isl_ast_op_fdiv_q, ppcg_fdiv_q);
327 
328 	return p;
329 }
330 
331 /* Given a multi affine expression "mpa" without domain, modify it to have
332  * the schedule space of "build" as domain.
333  *
334  * If the schedule space of "build" is a parameter space, then nothing
335  * needs to be done.
336  * Otherwise, "mpa" is first given a 0D domain and then it is combined
337  * with a mapping from the schedule space of "build" to the same 0D domain.
338  */
ppcg_attach_multi_pw_aff(__isl_take isl_multi_pw_aff * mpa,__isl_keep isl_ast_build * build)339 __isl_give isl_multi_pw_aff *ppcg_attach_multi_pw_aff(
340 	__isl_take isl_multi_pw_aff *mpa, __isl_keep isl_ast_build *build)
341 {
342 	isl_bool params;
343 	isl_space *space;
344 	isl_multi_aff *ma;
345 
346 	space = isl_ast_build_get_schedule_space(build);
347 	params = isl_space_is_params(space);
348 	if (params < 0 || params) {
349 		isl_space_free(space);
350 		if (params < 0)
351 			return isl_multi_pw_aff_free(mpa);
352 		return mpa;
353 	}
354 	space = isl_space_from_domain(space);
355 	ma = isl_multi_aff_zero(space);
356 	mpa = isl_multi_pw_aff_from_range(mpa);
357 	mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma);
358 
359 	return mpa;
360 }
361 
362 /* Build an access AST expression from "size" using "build".
363  * "size" does not have a domain, but "build" may have a proper schedule space.
364  * First modify "size" to have that schedule space as domain.
365  */
ppcg_build_size_expr(__isl_take isl_multi_pw_aff * size,__isl_keep isl_ast_build * build)366 __isl_give isl_ast_expr *ppcg_build_size_expr(__isl_take isl_multi_pw_aff *size,
367 	__isl_keep isl_ast_build *build)
368 {
369 	size = ppcg_attach_multi_pw_aff(size, build);
370 	return isl_ast_build_access_from_multi_pw_aff(build, size);
371 }
372 
373 /* Print a declaration for an array with element type "base_type" and
374  * size "size" to "p".
375  */
ppcg_print_declaration_with_size(__isl_take isl_printer * p,const char * base_type,__isl_keep isl_ast_expr * size)376 __isl_give isl_printer *ppcg_print_declaration_with_size(
377 	__isl_take isl_printer *p, const char *base_type,
378 	__isl_keep isl_ast_expr *size)
379 {
380 	if (!base_type || !size)
381 		return isl_printer_free(p);
382 
383 	p = ppcg_ast_expr_print_macros(size, p);
384 	p = isl_printer_start_line(p);
385 	p = isl_printer_print_str(p, base_type);
386 	p = isl_printer_print_str(p, " ");
387 	p = isl_printer_print_ast_expr(p, size);
388 	p = isl_printer_print_str(p, ";");
389 	p = isl_printer_end_line(p);
390 
391 	return p;
392 }
393 
394 /* Print a declaration for array "array" to "p", using "build"
395  * to simplify any size expressions.
396  *
397  * The size is computed from the extent of the array and is
398  * subsequently converted to an "access expression" by "build".
399  */
ppcg_print_declaration(__isl_take isl_printer * p,struct pet_array * array,__isl_keep isl_ast_build * build)400 __isl_give isl_printer *ppcg_print_declaration(__isl_take isl_printer *p,
401 	struct pet_array *array, __isl_keep isl_ast_build *build)
402 {
403 	isl_multi_pw_aff *size;
404 	isl_ast_expr *expr;
405 
406 	if (!array)
407 		return isl_printer_free(p);
408 
409 	size = ppcg_size_from_extent(isl_set_copy(array->extent));
410 	expr = isl_ast_build_access_from_multi_pw_aff(build, size);
411 	p = ppcg_print_declaration_with_size(p, array->element_type, expr);
412 	isl_ast_expr_free(expr);
413 
414 	return p;
415 }
416 
417 /* Print declarations for the arrays in "scop" that are declared
418  * and that are exposed (if exposed == 1) or not exposed (if exposed == 0).
419  */
print_declarations(__isl_take isl_printer * p,struct ppcg_scop * scop,int exposed)420 static __isl_give isl_printer *print_declarations(__isl_take isl_printer *p,
421 	struct ppcg_scop *scop, int exposed)
422 {
423 	int i;
424 	isl_ast_build *build;
425 
426 	if (!scop)
427 		return isl_printer_free(p);
428 
429 	build = isl_ast_build_from_context(isl_set_copy(scop->context));
430 	for (i = 0; i < scop->pet->n_array; ++i) {
431 		struct pet_array *array = scop->pet->arrays[i];
432 
433 		if (!array->declared)
434 			continue;
435 		if (array->exposed != exposed)
436 			continue;
437 
438 		p = ppcg_print_declaration(p, array, build);
439 	}
440 	isl_ast_build_free(build);
441 
442 	return p;
443 }
444 
445 /* Print declarations for the arrays in "scop" that are declared
446  * and exposed to the code after the scop.
447  */
ppcg_print_exposed_declarations(__isl_take isl_printer * p,struct ppcg_scop * scop)448 __isl_give isl_printer *ppcg_print_exposed_declarations(
449 	__isl_take isl_printer *p, struct ppcg_scop *scop)
450 {
451 	return print_declarations(p, scop, 1);
452 }
453 
454 /* Print declarations for the arrays in "scop" that are declared,
455  * but not exposed to the code after the scop.
456  */
ppcg_print_hidden_declarations(__isl_take isl_printer * p,struct ppcg_scop * scop)457 __isl_give isl_printer *ppcg_print_hidden_declarations(
458 	__isl_take isl_printer *p, struct ppcg_scop *scop)
459 {
460 	return print_declarations(p, scop, 0);
461 }
462