2 * Copyright 2012 Ecole Normale Superieure
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege,
7 * Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
14 #include "gpu_print.h"
18 /* Print declarations to "p" for arrays that are local to "prog"
19 * but that are used on the host and therefore require a declaration.
21 __isl_give isl_printer
*gpu_print_local_declarations(__isl_take isl_printer
*p
,
22 struct gpu_prog
*prog
)
27 return isl_printer_free(p
);
29 for (i
= 0; i
< prog
->n_array
; ++i
) {
32 if (!prog
->array
[i
].declare_local
)
34 size
= prog
->array
[i
].declared_size
;
35 p
= ppcg_print_declaration_with_size(p
,
36 prog
->scop
->pet
->arrays
[i
], size
);
42 /* Print an expression for the size of "array" in bytes.
44 __isl_give isl_printer
*gpu_array_info_print_size(__isl_take isl_printer
*prn
,
45 struct gpu_array_info
*array
)
49 for (i
= 0; i
< array
->n_index
; ++i
) {
52 prn
= isl_printer_print_str(prn
, "(");
53 bound
= isl_ast_expr_get_op_arg(array
->bound_expr
, 1 + i
);
54 prn
= isl_printer_print_ast_expr(prn
, bound
);
55 isl_ast_expr_free(bound
);
56 prn
= isl_printer_print_str(prn
, ") * ");
58 prn
= isl_printer_print_str(prn
, "sizeof(");
59 prn
= isl_printer_print_str(prn
, array
->type
);
60 prn
= isl_printer_print_str(prn
, ")");
65 /* Print the declaration of a non-linearized array argument.
67 static __isl_give isl_printer
*print_non_linearized_declaration_argument(
68 __isl_take isl_printer
*p
, struct gpu_array_info
*array
)
70 p
= isl_printer_print_str(p
, array
->type
);
71 p
= isl_printer_print_str(p
, " ");
73 p
= isl_printer_print_ast_expr(p
, array
->bound_expr
);
78 /* Print the declaration of an array argument.
79 * "memory_space" allows to specify a memory space prefix.
81 __isl_give isl_printer
*gpu_array_info_print_declaration_argument(
82 __isl_take isl_printer
*p
, struct gpu_array_info
*array
,
83 const char *memory_space
)
85 if (gpu_array_is_read_only_scalar(array
)) {
86 p
= isl_printer_print_str(p
, array
->type
);
87 p
= isl_printer_print_str(p
, " ");
88 p
= isl_printer_print_str(p
, array
->name
);
93 p
= isl_printer_print_str(p
, memory_space
);
94 p
= isl_printer_print_str(p
, " ");
97 if (array
->n_index
!= 0 && !array
->linearize
)
98 return print_non_linearized_declaration_argument(p
, array
);
100 p
= isl_printer_print_str(p
, array
->type
);
101 p
= isl_printer_print_str(p
, " ");
102 p
= isl_printer_print_str(p
, "*");
103 p
= isl_printer_print_str(p
, array
->name
);
108 /* Print the call of an array argument.
110 __isl_give isl_printer
*gpu_array_info_print_call_argument(
111 __isl_take isl_printer
*p
, struct gpu_array_info
*array
)
113 if (gpu_array_is_read_only_scalar(array
))
114 return isl_printer_print_str(p
, array
->name
);
116 p
= isl_printer_print_str(p
, "dev_");
117 p
= isl_printer_print_str(p
, array
->name
);
122 /* Print an access to the element in the private/shared memory copy
123 * described by "stmt". The index of the copy is recorded in
124 * stmt->local_index as an access to the array.
126 static __isl_give isl_printer
*stmt_print_local_index(__isl_take isl_printer
*p
,
127 struct ppcg_kernel_stmt
*stmt
)
129 return isl_printer_print_ast_expr(p
, stmt
->u
.c
.local_index
);
132 /* Print an access to the element in the global memory copy
133 * described by "stmt". The index of the copy is recorded in
134 * stmt->index as an access to the array.
136 static __isl_give isl_printer
*stmt_print_global_index(
137 __isl_take isl_printer
*p
, struct ppcg_kernel_stmt
*stmt
)
140 struct gpu_array_info
*array
= stmt
->u
.c
.array
;
141 struct gpu_local_array_info
*local
= stmt
->u
.c
.local_array
;
144 if (gpu_array_is_scalar(array
)) {
145 if (!gpu_array_is_read_only_scalar(array
))
146 p
= isl_printer_print_str(p
, "*");
147 p
= isl_printer_print_str(p
, array
->name
);
151 index
= isl_ast_expr_copy(stmt
->u
.c
.index
);
153 p
= isl_printer_print_ast_expr(p
, index
);
154 isl_ast_expr_free(index
);
159 /* Print a copy statement.
161 * A read copy statement is printed as
165 * while a write copy statement is printed as
169 __isl_give isl_printer
*ppcg_kernel_print_copy(__isl_take isl_printer
*p
,
170 struct ppcg_kernel_stmt
*stmt
)
172 p
= isl_printer_start_line(p
);
173 if (stmt
->u
.c
.read
) {
174 p
= stmt_print_local_index(p
, stmt
);
175 p
= isl_printer_print_str(p
, " = ");
176 p
= stmt_print_global_index(p
, stmt
);
178 p
= stmt_print_global_index(p
, stmt
);
179 p
= isl_printer_print_str(p
, " = ");
180 p
= stmt_print_local_index(p
, stmt
);
182 p
= isl_printer_print_str(p
, ";");
183 p
= isl_printer_end_line(p
);
188 __isl_give isl_printer
*ppcg_kernel_print_domain(__isl_take isl_printer
*p
,
189 struct ppcg_kernel_stmt
*stmt
)
191 return pet_stmt_print_body(stmt
->u
.d
.stmt
->stmt
, p
, stmt
->u
.d
.ref2expr
);
194 /* This function is called for each node in a GPU AST.
195 * In case of a user node, print the macro definitions required
196 * for printing the AST expressions in the annotation, if any.
197 * For other nodes, return true such that descendants are also
200 * In particular, for a kernel launch, print the macro definitions
201 * needed for the grid size.
202 * For a copy statement, print the macro definitions needed
203 * for the two index expressions.
204 * For an original user statement, print the macro definitions
205 * needed for the substitutions.
207 static isl_bool
at_node(__isl_keep isl_ast_node
*node
, void *user
)
212 struct ppcg_kernel
*kernel
;
213 struct ppcg_kernel_stmt
*stmt
;
214 isl_printer
**p
= user
;
216 if (isl_ast_node_get_type(node
) != isl_ast_node_user
)
217 return isl_bool_true
;
219 id
= isl_ast_node_get_annotation(node
);
221 return isl_bool_false
;
223 name
= isl_id_get_name(id
);
225 return isl_bool_error
;
226 is_kernel
= !strcmp(name
, "kernel");
227 kernel
= is_kernel
? isl_id_get_user(id
) : NULL
;
228 stmt
= is_kernel
? NULL
: isl_id_get_user(id
);
231 if ((is_kernel
&& !kernel
) || (!is_kernel
&& !stmt
))
232 return isl_bool_error
;
235 *p
= ppcg_ast_expr_print_macros(kernel
->grid_size_expr
, *p
);
236 } else if (stmt
->type
== ppcg_kernel_copy
) {
237 *p
= ppcg_ast_expr_print_macros(stmt
->u
.c
.index
, *p
);
238 *p
= ppcg_ast_expr_print_macros(stmt
->u
.c
.local_index
, *p
);
239 } else if (stmt
->type
== ppcg_kernel_domain
) {
240 *p
= ppcg_print_body_macros(*p
, stmt
->u
.d
.ref2expr
);
243 return isl_bool_error
;
245 return isl_bool_false
;
248 /* Print the required macros for the GPU AST "node" to "p",
249 * including those needed for the user statements inside the AST.
251 __isl_give isl_printer
*gpu_print_macros(__isl_take isl_printer
*p
,
252 __isl_keep isl_ast_node
*node
)
254 if (isl_ast_node_foreach_descendant_top_down(node
, &at_node
, &p
) < 0)
255 return isl_printer_free(p
);
256 p
= ppcg_print_macros(p
, node
);
260 /* Was the definition of "type" printed before?
261 * That is, does its name appear in the list of printed types "types"?
263 static int already_printed(struct gpu_types
*types
,
264 struct pet_type
*type
)
268 for (i
= 0; i
< types
->n
; ++i
)
269 if (!strcmp(types
->name
[i
], type
->name
))
275 /* Print the definitions of all types prog->scop that have not been
276 * printed before (according to "types") on "p".
277 * Extend the list of printed types "types" with the newly printed types.
279 __isl_give isl_printer
*gpu_print_types(__isl_take isl_printer
*p
,
280 struct gpu_types
*types
, struct gpu_prog
*prog
)
286 n
= prog
->scop
->pet
->n_type
;
291 ctx
= isl_printer_get_ctx(p
);
292 name
= isl_realloc_array(ctx
, types
->name
, char *, types
->n
+ n
);
294 return isl_printer_free(p
);
297 for (i
= 0; i
< n
; ++i
) {
298 struct pet_type
*type
= prog
->scop
->pet
->types
[i
];
300 if (already_printed(types
, type
))
303 p
= isl_printer_start_line(p
);
304 p
= isl_printer_print_str(p
, type
->definition
);
305 p
= isl_printer_print_str(p
, ";");
306 p
= isl_printer_end_line(p
);
308 types
->name
[types
->n
++] = strdup(type
->name
);