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