| /* | 
 |  * Copyright 2012-2013 Ecole Normale Superieure | 
 |  * | 
 |  * Use of this software is governed by the MIT license | 
 |  * | 
 |  * Written by Sven Verdoolaege, | 
 |  * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France | 
 |  */ | 
 |  | 
 | #include <isl/aff.h> | 
 | #include <isl/ast_build.h> | 
 | #include <isl/id.h> | 
 |  | 
 | #include "print.h" | 
 | #include "util.h" | 
 |  | 
 | __isl_give isl_printer *ppcg_start_block(__isl_take isl_printer *p) | 
 | { | 
 | 	p = isl_printer_start_line(p); | 
 | 	p = isl_printer_print_str(p, "{"); | 
 | 	p = isl_printer_end_line(p); | 
 | 	p = isl_printer_indent(p, 2); | 
 | 	return p; | 
 | } | 
 |  | 
 | __isl_give isl_printer *ppcg_end_block(__isl_take isl_printer *p) | 
 | { | 
 | 	p = isl_printer_indent(p, -2); | 
 | 	p = isl_printer_start_line(p); | 
 | 	p = isl_printer_print_str(p, "}"); | 
 | 	p = isl_printer_end_line(p); | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Names of notes that keep track of whether min/max | 
 |  * macro definitions have already been printed. | 
 |  */ | 
 | static const char *ppcg_max_printed = "ppcg_max_printed"; | 
 | static const char *ppcg_min_printed = "ppcg_min_printed"; | 
 |  | 
 | /* Has the macro definition corresponding to "note_name" been printed | 
 |  * to "p" before? | 
 |  * That is, does "p" have an associated "note_name" note? | 
 |  */ | 
 | static isl_bool printed_before(__isl_keep isl_printer *p, const char *note_name) | 
 | { | 
 | 	isl_ctx *ctx; | 
 | 	isl_id *id; | 
 | 	isl_bool printed; | 
 |  | 
 | 	if (!p) | 
 | 		return isl_bool_error; | 
 |  | 
 | 	ctx = isl_printer_get_ctx(p); | 
 | 	id = isl_id_alloc(ctx, note_name, NULL); | 
 | 	printed = isl_printer_has_note(p, id); | 
 | 	isl_id_free(id); | 
 |  | 
 | 	return printed; | 
 | } | 
 |  | 
 | /* Keep track of the fact that the macro definition corresponding | 
 |  * to "note_name" has been printed to "p" by attaching a note with | 
 |  * that name.  The value of the note is of no importance, but it | 
 |  * has to be a valid isl_id, so the note identifier is reused | 
 |  * as the note. | 
 |  */ | 
 | static __isl_give isl_printer *mark_printed(__isl_take isl_printer *p, | 
 | 	const char *note_name) | 
 | { | 
 | 	isl_ctx *ctx; | 
 | 	isl_id *id; | 
 |  | 
 | 	if (!p) | 
 | 		return NULL; | 
 |  | 
 | 	ctx = isl_printer_get_ctx(p); | 
 | 	id = isl_id_alloc(ctx, note_name, NULL); | 
 | 	return isl_printer_set_note(p, id, isl_id_copy(id)); | 
 | } | 
 |  | 
 | /* Print a macro definition "def" for the macro "name" to "p", | 
 |  * unless such a macro definition has been printed to "p" before. | 
 |  * "note_name" is used as the name of the note that keeps track | 
 |  * of whether this printing has happened. | 
 |  */ | 
 | static __isl_give isl_printer *print_ppcg_macro(__isl_take isl_printer *p, | 
 | 	const char *name, const char *def, const char *note_name) | 
 | { | 
 | 	isl_bool printed; | 
 |  | 
 | 	printed = printed_before(p, note_name); | 
 | 	if (printed < 0) | 
 | 		return isl_printer_free(p); | 
 | 	if (printed) | 
 | 		return p; | 
 |  | 
 | 	p = isl_printer_start_line(p); | 
 | 	p = isl_printer_print_str(p, "#define "); | 
 | 	p = isl_printer_print_str(p, name); | 
 | 	p = isl_printer_print_str(p, def); | 
 | 	p = isl_printer_end_line(p); | 
 |  | 
 | 	p = mark_printed(p, note_name); | 
 |  | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Structure for keeping track of definitions of some macros. | 
 |  */ | 
 | struct ppcg_macros { | 
 | 	const char *min; | 
 | 	const char *max; | 
 | }; | 
 |  | 
 | /* Free the memory allocated by a struct ppcg_macros. | 
 |  */ | 
 | static void ppcg_macros_free(void *user) | 
 | { | 
 | 	free(user); | 
 | } | 
 |  | 
 | /* Default macro definitions (when GNU extensions are allowed). | 
 |  */ | 
 | struct ppcg_macros ppcg_macros_default = { | 
 | 	.min = "(x,y)    " | 
 | 		"({ __typeof__(x) _x = (x); __typeof__(y) _y = (y); " | 
 | 		"_x < _y ? _x : _y; })", | 
 | 	.max = "(x,y)    " | 
 | 		"({ __typeof__(x) _x = (x); __typeof__(y) _y = (y); " | 
 | 		"_x > _y ? _x : _y; })", | 
 | }; | 
 |  | 
 | /* Name used for the note that keeps track of macro definitions. | 
 |  */ | 
 | static const char *ppcg_macros = "ppcg_macros"; | 
 |  | 
 | /* Set the macro definitions for isl_ast_op_min and isl_ast_op_max | 
 |  * to "min" and "max" and store them in "p". | 
 |  * | 
 |  * In particular, create a ppcg_macros object and attach it | 
 |  * as a note to the printer. | 
 |  */ | 
 | __isl_give isl_printer *ppcg_set_macros(__isl_take isl_printer *p, | 
 | 	const char *min, const char *max) | 
 | { | 
 | 	isl_ctx *ctx; | 
 | 	isl_id *id, *macros_id; | 
 | 	struct ppcg_macros *macros; | 
 |  | 
 | 	if (!p) | 
 | 		return NULL; | 
 |  | 
 | 	ctx = isl_printer_get_ctx(p); | 
 | 	macros = isl_alloc_type(ctx, struct ppcg_macros); | 
 | 	if (!macros) | 
 | 		return isl_printer_free(p); | 
 | 	macros->min = min; | 
 | 	macros->max = max; | 
 | 	id = isl_id_alloc(ctx, ppcg_macros, NULL); | 
 | 	macros_id = isl_id_alloc(ctx, NULL, macros); | 
 | 	if (!macros_id) | 
 | 		ppcg_macros_free(macros); | 
 | 	else | 
 | 		macros_id = isl_id_set_free_user(macros_id, &ppcg_macros_free); | 
 |  | 
 | 	p = isl_printer_set_note(p, id, macros_id); | 
 |  | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Return the ppcg_macros object that holds the currently active | 
 |  * macro definitions in "p". | 
 |  * If "p" has a note with macro definitions, then return those. | 
 |  * Otherwise, return the default macro definitions. | 
 |  */ | 
 | static struct ppcg_macros *get_macros(__isl_keep isl_printer *p) | 
 | { | 
 | 	isl_id *id; | 
 | 	isl_bool has_macros; | 
 | 	struct ppcg_macros *macros; | 
 |  | 
 | 	id = isl_id_alloc(isl_printer_get_ctx(p), ppcg_macros, NULL); | 
 | 	has_macros = isl_printer_has_note(p, id); | 
 | 	if (has_macros < 0 || !has_macros) { | 
 | 		isl_id_free(id); | 
 | 		if (has_macros < 0) | 
 | 			return NULL; | 
 | 		return &ppcg_macros_default; | 
 | 	} | 
 | 	id = isl_printer_get_note(p, id); | 
 | 	macros = isl_id_get_user(id); | 
 | 	isl_id_free(id); | 
 |  | 
 | 	return macros; | 
 | } | 
 |  | 
 | /* Print the currently active macro definition for ppcg_max. | 
 |  */ | 
 | static __isl_give isl_printer *print_max(__isl_take isl_printer *p) | 
 | { | 
 | 	struct ppcg_macros *macros; | 
 |  | 
 | 	macros = get_macros(p); | 
 | 	if (!macros) | 
 | 		return isl_printer_free(p); | 
 | 	return print_ppcg_macro(p, ppcg_max, macros->max, ppcg_max_printed); | 
 | } | 
 |  | 
 | /* Print the currently active macro definition for ppcg_min. | 
 |  */ | 
 | static __isl_give isl_printer *print_min(__isl_take isl_printer *p) | 
 | { | 
 | 	struct ppcg_macros *macros; | 
 |  | 
 | 	macros = get_macros(p); | 
 | 	if (!macros) | 
 | 		return isl_printer_free(p); | 
 | 	return print_ppcg_macro(p, ppcg_min, macros->min, ppcg_min_printed); | 
 | } | 
 |  | 
 | /* Print a macro definition for "type" to "p". | 
 |  * If GNU extensions are allowed, then print a specialized definition | 
 |  * for isl_ast_op_min and isl_ast_op_max. | 
 |  * Otherwise, use the default isl definition. | 
 |  */ | 
 | __isl_give isl_printer *ppcg_print_macro(enum isl_ast_op_type type, | 
 | 	__isl_take isl_printer *p) | 
 | { | 
 | 	isl_ctx *ctx; | 
 | 	struct ppcg_options *options; | 
 |  | 
 | 	if (!p) | 
 | 		return NULL; | 
 |  | 
 | 	ctx = isl_printer_get_ctx(p); | 
 | 	options = isl_ctx_peek_options(ctx, &ppcg_options_args); | 
 | 	if (!options || !options->allow_gnu_extensions) | 
 | 		return isl_ast_op_type_print_macro(type, p); | 
 |  | 
 | 	switch (type) { | 
 | 	case isl_ast_op_max: | 
 | 		return print_max(p); | 
 | 	case isl_ast_op_min: | 
 | 		return print_min(p); | 
 | 	default: | 
 | 		return isl_ast_op_type_print_macro(type, p); | 
 | 	} | 
 | } | 
 |  | 
 | /* isl_ast_expr_foreach_ast_op_type or isl_ast_node_foreach_ast_op_type | 
 |  * callback that prints a macro definition for "type". | 
 |  */ | 
 | static isl_stat print_macro(enum isl_ast_op_type type, void *user) | 
 | { | 
 | 	isl_printer **p = user; | 
 |  | 
 | 	*p = ppcg_print_macro(type, *p); | 
 | 	if (!*p) | 
 | 		return isl_stat_error; | 
 |  | 
 | 	return isl_stat_ok; | 
 | } | 
 |  | 
 | /* Print the required macros for "expr". | 
 |  */ | 
 | __isl_give isl_printer *ppcg_ast_expr_print_macros( | 
 | 	__isl_keep isl_ast_expr *expr, __isl_take isl_printer *p) | 
 | { | 
 | 	if (isl_ast_expr_foreach_ast_op_type(expr, &print_macro, &p) < 0) | 
 | 		return isl_printer_free(p); | 
 | 	return p; | 
 | } | 
 |  | 
 | /* isl_id_to_ast_expr_foreach callback that prints the required | 
 |  * macro definitions for "val". | 
 |  */ | 
 | static isl_stat print_expr_macros(__isl_take isl_id *key, | 
 | 	__isl_take isl_ast_expr *val, void *user) | 
 | { | 
 | 	isl_printer **p = user; | 
 |  | 
 | 	*p = ppcg_ast_expr_print_macros(val, *p); | 
 | 	isl_id_free(key); | 
 | 	isl_ast_expr_free(val); | 
 |  | 
 | 	if (!*p) | 
 | 		return isl_stat_error; | 
 | 	return isl_stat_ok; | 
 | } | 
 |  | 
 | /* Print the required macro definitions for the body of a statement in which | 
 |  * the access expressions are replaced by the isl_ast_expr objects | 
 |  * in "ref2expr". | 
 |  */ | 
 | __isl_give isl_printer *ppcg_print_body_macros(__isl_take isl_printer *p, | 
 | 	__isl_keep isl_id_to_ast_expr *ref2expr) | 
 | { | 
 | 	if (isl_id_to_ast_expr_foreach(ref2expr, &print_expr_macros, &p) < 0) | 
 | 		return isl_printer_free(p); | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Print the required macros for "node". | 
 |  */ | 
 | __isl_give isl_printer *ppcg_print_macros(__isl_take isl_printer *p, | 
 | 	__isl_keep isl_ast_node *node) | 
 | { | 
 | 	if (isl_ast_node_foreach_ast_op_type(node, &print_macro, &p) < 0) | 
 | 		return isl_printer_free(p); | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Names used for the macros that may appear in a printed isl AST. | 
 |  */ | 
 | const char *ppcg_min = "ppcg_min"; | 
 | const char *ppcg_max = "ppcg_max"; | 
 | const char *ppcg_fdiv_q = "ppcg_fdiv_q"; | 
 |  | 
 | /* Set the names of the macros that may appear in a printed isl AST. | 
 |  */ | 
 | __isl_give isl_printer *ppcg_set_macro_names(__isl_take isl_printer *p) | 
 | { | 
 | 	p = isl_ast_op_type_set_print_name(p, isl_ast_op_min, ppcg_min); | 
 | 	p = isl_ast_op_type_set_print_name(p, isl_ast_op_max, ppcg_max); | 
 | 	p = isl_ast_op_type_set_print_name(p, isl_ast_op_fdiv_q, ppcg_fdiv_q); | 
 |  | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Given a multi affine expression "mpa" without domain, modify it to have | 
 |  * the schedule space of "build" as domain. | 
 |  * | 
 |  * If the schedule space of "build" is a parameter space, then nothing | 
 |  * needs to be done. | 
 |  * Otherwise, "mpa" is first given a 0D domain and then it is combined | 
 |  * with a mapping from the schedule space of "build" to the same 0D domain. | 
 |  */ | 
 | __isl_give isl_multi_pw_aff *ppcg_attach_multi_pw_aff( | 
 | 	__isl_take isl_multi_pw_aff *mpa, __isl_keep isl_ast_build *build) | 
 | { | 
 | 	isl_bool params; | 
 | 	isl_space *space; | 
 | 	isl_multi_aff *ma; | 
 |  | 
 | 	space = isl_ast_build_get_schedule_space(build); | 
 | 	params = isl_space_is_params(space); | 
 | 	if (params < 0 || params) { | 
 | 		isl_space_free(space); | 
 | 		if (params < 0) | 
 | 			return isl_multi_pw_aff_free(mpa); | 
 | 		return mpa; | 
 | 	} | 
 | 	space = isl_space_from_domain(space); | 
 | 	ma = isl_multi_aff_zero(space); | 
 | 	mpa = isl_multi_pw_aff_from_range(mpa); | 
 | 	mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma); | 
 |  | 
 | 	return mpa; | 
 | } | 
 |  | 
 | /* Build an access AST expression from "size" using "build". | 
 |  * "size" does not have a domain, but "build" may have a proper schedule space. | 
 |  * First modify "size" to have that schedule space as domain. | 
 |  */ | 
 | __isl_give isl_ast_expr *ppcg_build_size_expr(__isl_take isl_multi_pw_aff *size, | 
 | 	__isl_keep isl_ast_build *build) | 
 | { | 
 | 	size = ppcg_attach_multi_pw_aff(size, build); | 
 | 	return isl_ast_build_access_from_multi_pw_aff(build, size); | 
 | } | 
 |  | 
 | /* Print a declaration for an array with element type "base_type" and | 
 |  * size "size" to "p". | 
 |  */ | 
 | __isl_give isl_printer *ppcg_print_declaration_with_size( | 
 | 	__isl_take isl_printer *p, const char *base_type, | 
 | 	__isl_keep isl_ast_expr *size) | 
 | { | 
 | 	if (!base_type || !size) | 
 | 		return isl_printer_free(p); | 
 |  | 
 | 	p = ppcg_ast_expr_print_macros(size, p); | 
 | 	p = isl_printer_start_line(p); | 
 | 	p = isl_printer_print_str(p, base_type); | 
 | 	p = isl_printer_print_str(p, " "); | 
 | 	p = isl_printer_print_ast_expr(p, size); | 
 | 	p = isl_printer_print_str(p, ";"); | 
 | 	p = isl_printer_end_line(p); | 
 |  | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Print a declaration for array "array" to "p", using "build" | 
 |  * to simplify any size expressions. | 
 |  * | 
 |  * The size is computed from the extent of the array and is | 
 |  * subsequently converted to an "access expression" by "build". | 
 |  */ | 
 | __isl_give isl_printer *ppcg_print_declaration(__isl_take isl_printer *p, | 
 | 	struct pet_array *array, __isl_keep isl_ast_build *build) | 
 | { | 
 | 	isl_multi_pw_aff *size; | 
 | 	isl_ast_expr *expr; | 
 |  | 
 | 	if (!array) | 
 | 		return isl_printer_free(p); | 
 |  | 
 | 	size = ppcg_size_from_extent(isl_set_copy(array->extent)); | 
 | 	expr = isl_ast_build_access_from_multi_pw_aff(build, size); | 
 | 	p = ppcg_print_declaration_with_size(p, array->element_type, expr); | 
 | 	isl_ast_expr_free(expr); | 
 |  | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Print declarations for the arrays in "scop" that are declared | 
 |  * and that are exposed (if exposed == 1) or not exposed (if exposed == 0). | 
 |  */ | 
 | static __isl_give isl_printer *print_declarations(__isl_take isl_printer *p, | 
 | 	struct ppcg_scop *scop, int exposed) | 
 | { | 
 | 	int i; | 
 | 	isl_ast_build *build; | 
 |  | 
 | 	if (!scop) | 
 | 		return isl_printer_free(p); | 
 |  | 
 | 	build = isl_ast_build_from_context(isl_set_copy(scop->context)); | 
 | 	for (i = 0; i < scop->pet->n_array; ++i) { | 
 | 		struct pet_array *array = scop->pet->arrays[i]; | 
 |  | 
 | 		if (!array->declared) | 
 | 			continue; | 
 | 		if (array->exposed != exposed) | 
 | 			continue; | 
 |  | 
 | 		p = ppcg_print_declaration(p, array, build); | 
 | 	} | 
 | 	isl_ast_build_free(build); | 
 |  | 
 | 	return p; | 
 | } | 
 |  | 
 | /* Print declarations for the arrays in "scop" that are declared | 
 |  * and exposed to the code after the scop. | 
 |  */ | 
 | __isl_give isl_printer *ppcg_print_exposed_declarations( | 
 | 	__isl_take isl_printer *p, struct ppcg_scop *scop) | 
 | { | 
 | 	return print_declarations(p, scop, 1); | 
 | } | 
 |  | 
 | /* Print declarations for the arrays in "scop" that are declared, | 
 |  * but not exposed to the code after the scop. | 
 |  */ | 
 | __isl_give isl_printer *ppcg_print_hidden_declarations( | 
 | 	__isl_take isl_printer *p, struct ppcg_scop *scop) | 
 | { | 
 | 	return print_declarations(p, scop, 0); | 
 | } |