comparison gcc/brig/brigfrontend/brig-function-handler.cc @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
comparison
equal deleted inserted replaced
68:561a7518be6b 111:04ced10e8804
1 /* brig-code-entry-handler.cc -- brig function directive handling
2 Copyright (C) 2016-2017 Free Software Foundation, Inc.
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
4 for General Processor Tech.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 #include <sstream>
23 #include <iomanip>
24
25 #include "brig-code-entry-handler.h"
26
27 #include "brig-machine.h"
28 #include "stringpool.h"
29 #include "tree-iterator.h"
30 #include "gimple-expr.h"
31 #include "function.h"
32 #include "phsa.h"
33
34 #include "tree-pretty-print.h"
35 #include "print-tree.h"
36
37 extern int gccbrig_verbose;
38
39 size_t
40 brig_directive_function_handler::operator () (const BrigBase *base)
41 {
42 if (!m_parent.m_analyzing)
43 m_parent.finish_function ();
44
45 size_t bytes_consumed = base->byteCount;
46
47 const BrigDirectiveExecutable *exec = (const BrigDirectiveExecutable *) base;
48
49 if (gccbrig_verbose)
50 {
51 printf ("brig: function name %s\n",
52 m_parent.get_string (exec->name).c_str());
53 printf ("brig: inargs %d outargs %d name offset %d\n", exec->inArgCount,
54 exec->outArgCount, exec->name);
55 }
56
57 const bool is_definition
58 = exec->modifier & BRIG_EXECUTABLE_DEFINITION;
59
60 const bool is_kernel = base->kind == BRIG_KIND_DIRECTIVE_KERNEL;
61
62 /* There doesn't seem to be actual use cases for kernel declarations
63 as they cannot be called by the program. Ignore them until there's
64 a reason not to. */
65 if (is_kernel && !is_definition)
66 return bytes_consumed;
67
68 std::string func_name = m_parent.get_mangled_name (exec);
69 if (is_kernel)
70 /* The generated kernel function is not the one that should be
71 called by the host. */
72 func_name = std::string ("_") + func_name;
73
74 m_parent.m_cf = new brig_function (exec, &m_parent);
75 m_parent.m_cf->m_name = func_name;
76 m_parent.m_cf->m_is_kernel = is_kernel;
77
78 /* During the analyze step, the above information is all we need per
79 function. */
80 if (m_parent.m_analyzing)
81 return bytes_consumed;
82
83 tree fndecl;
84 tree ret_value = NULL_TREE;
85
86 tree stmt_list = alloc_stmt_list ();
87
88 /* Add a function scope BIND_EXPR using which we can push local variables that
89 represent HSAIL registers. */
90 tree bind_expr = build3 (BIND_EXPR, void_type_node, NULL, stmt_list, NULL);
91
92 if (is_kernel)
93 {
94 tree name_identifier
95 = get_identifier_with_length (func_name.c_str (), func_name.size ());
96
97 /* The generated kernel functions take the following arguments:
98
99 1) a char* which is a starting address of the argument segment where
100 the call's arguments are stored by the launcher.
101 2) a void* parameter that points to a phsail-finalizer context object
102 which passes the hsa kernel packet etc.
103 3) a void* parameter that contains the first flat address of the group
104 region allocated to the current work-group. */
105
106 tree char_ptr_type_node = build_pointer_type (char_type_node);
107 fndecl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, name_identifier,
108 build_function_type_list (void_type_node,
109 char_ptr_type_node,
110 ptr_type_node,
111 ptr_type_node, NULL_TREE));
112
113 SET_DECL_ASSEMBLER_NAME (fndecl, name_identifier);
114
115 tree resdecl
116 = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, void_type_node);
117
118 tree typelist = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
119 tree argtype = TREE_VALUE (typelist);
120 TYPE_ADDR_SPACE (argtype)
121 = gccbrig_get_target_addr_space_id (BRIG_SEGMENT_KERNARG);
122
123 tree arg_arg = build_decl (UNKNOWN_LOCATION, PARM_DECL,
124 get_identifier ("__args"), char_ptr_type_node);
125 DECL_ARGUMENTS (fndecl) = arg_arg;
126 DECL_ARG_TYPE (arg_arg) = char_ptr_type_node;
127 DECL_CONTEXT (arg_arg) = fndecl;
128 DECL_ARTIFICIAL (arg_arg) = 1;
129 TREE_READONLY (arg_arg) = 1;
130 TREE_USED (arg_arg) = 1;
131
132 DECL_RESULT (fndecl) = resdecl;
133 DECL_CONTEXT (resdecl) = fndecl;
134 DECL_EXTERNAL (fndecl) = 0;
135 }
136 else
137 {
138 /* Build a regular function fingerprint to enable targets to optimize
139 the calling convention as they see fit. */
140 tree name_identifier
141 = get_identifier_with_length (func_name.c_str (), func_name.size ());
142
143 m_parent.m_cf->m_arg_variables.clear ();
144
145 brig_directive_variable_handler arg_handler (m_parent);
146
147 vec<tree, va_gc> *args;
148 vec_alloc (args, 4);
149
150 tree arg_decls = NULL_TREE;
151
152 tree ret_type = void_type_node;
153 if (exec->outArgCount == 1)
154 {
155 /* The return value variable should be the first entry after the
156 function directive. */
157 const BrigBase *retval
158 = (const BrigBase *) ((const char *) base + base->byteCount);
159 gcc_assert (retval->kind == BRIG_KIND_DIRECTIVE_VARIABLE);
160
161 const BrigDirectiveVariable *brigVar
162 = (const BrigDirectiveVariable *) retval;
163
164 brig_directive_variable_handler varhandler (m_parent);
165
166 if (brigVar->type & BRIG_TYPE_ARRAY)
167 {
168 /* Push array output arguments to the beginning of the
169 function argument list instead of regular function
170 return values. */
171
172 tree arg_var = varhandler.build_variable (brigVar, PARM_DECL);
173 vec_safe_push (args, TREE_TYPE (arg_var));
174
175 m_parent.m_cf->add_arg_variable (brigVar, arg_var);
176
177 if (arg_decls == NULL_TREE)
178 arg_decls = arg_var;
179 else
180 chainon (arg_decls, arg_var);
181
182 m_parent.m_cf->add_arg_variable (brigVar, arg_var);
183
184 ret_value = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
185 void_type_node);
186 }
187 else
188 {
189 ret_value = varhandler.build_variable (brigVar, RESULT_DECL);
190 m_parent.m_cf->m_ret_value = ret_value;
191 ret_type = TREE_TYPE (ret_value);
192 m_parent.m_cf->m_ret_value_brig_var = brigVar;
193 }
194 bytes_consumed += retval->byteCount;
195 }
196 else
197 ret_value = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE,
198 void_type_node);
199
200 TREE_ADDRESSABLE (ret_value) = 1;
201
202 if (exec->inArgCount > 0)
203 {
204 uint32_t arg_offset = exec->firstInArg;
205 for (size_t arg = 0; arg < exec->inArgCount; ++arg)
206 {
207
208 const BrigDirectiveVariable *brigVar
209 = (const BrigDirectiveVariable *) m_parent.get_brig_code_entry
210 (arg_offset);
211
212 gcc_assert (brigVar->base.kind == BRIG_KIND_DIRECTIVE_VARIABLE);
213
214 /* Delegate to the brig_directive_variable_handler. */
215 brig_directive_variable_handler varhandler (m_parent);
216 tree arg_var = varhandler.build_variable (brigVar, PARM_DECL);
217 arg_offset += brigVar->base.byteCount;
218 vec_safe_push (args, TREE_TYPE (arg_var));
219
220 m_parent.m_cf->add_arg_variable (brigVar, arg_var);
221
222 if (arg_decls == NULL_TREE)
223 arg_decls = arg_var;
224 else
225 chainon (arg_decls, arg_var);
226 }
227 }
228
229 vec_safe_push (args, ptr_type_node);
230 vec_safe_push (args, ptr_type_node);
231
232 fndecl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, name_identifier,
233 build_function_type_vec (ret_type, args));
234
235 DECL_RESULT (fndecl) = ret_value;
236 DECL_CONTEXT (ret_value) = fndecl;
237 DECL_EXTERNAL (fndecl) = 0;
238 DECL_ARGUMENTS (fndecl) = arg_decls;
239 }
240
241 /* All functions need the hidden __context argument passed on
242 because they might call WI-specific functions which need
243 the context info. */
244 tree context_arg = build_decl (UNKNOWN_LOCATION, PARM_DECL,
245 get_identifier ("__context"), ptr_type_node);
246 if (DECL_ARGUMENTS (fndecl) == NULL_TREE)
247 DECL_ARGUMENTS (fndecl) = context_arg;
248 else
249 chainon (DECL_ARGUMENTS (fndecl), context_arg);
250 DECL_CONTEXT (context_arg) = fndecl;
251 DECL_ARG_TYPE (context_arg) = ptr_type_node;
252 DECL_ARTIFICIAL (context_arg) = 1;
253 TREE_READONLY (context_arg) = 1;
254 TREE_USED (context_arg) = 1;
255
256 /* They can also access group memory, so we need to pass the
257 group pointer along too. */
258 tree group_base_arg
259 = build_decl (UNKNOWN_LOCATION, PARM_DECL,
260 get_identifier ("__group_base_addr"), ptr_type_node);
261 chainon (DECL_ARGUMENTS (fndecl), group_base_arg);
262 DECL_ARG_TYPE (group_base_arg) = ptr_type_node;
263 DECL_CONTEXT (group_base_arg) = fndecl;
264 DECL_ARTIFICIAL (group_base_arg) = 1;
265 TREE_READONLY (group_base_arg) = 1;
266 TREE_USED (group_base_arg) = 1;
267 m_parent.m_cf->m_group_base_arg = group_base_arg;
268
269 /* To implement call stack and (non-kernel) function scope group variables,
270 we need to pass an offset which describes how far are we from
271 group_base_ptr.
272 That must be substracted from any function local group variable offsets to
273 get the address related to the bottom of the group memory chunk. */
274 tree group_local_offset_arg
275 = build_decl (UNKNOWN_LOCATION, PARM_DECL,
276 get_identifier ("__group_local_offset"), uint32_type_node);
277 chainon (DECL_ARGUMENTS (fndecl), group_local_offset_arg);
278 DECL_ARG_TYPE (group_local_offset_arg) = uint32_type_node;
279 DECL_CONTEXT (group_local_offset_arg) = fndecl;
280 DECL_ARTIFICIAL (group_local_offset_arg) = 1;
281 TREE_READONLY (group_local_offset_arg) = 1;
282 TREE_USED (group_local_offset_arg) = 1;
283 m_parent.m_cf->m_group_local_offset_arg = group_local_offset_arg;
284
285 /* Same for private. */
286 tree private_base_arg
287 = build_decl (UNKNOWN_LOCATION, PARM_DECL,
288 get_identifier ("__private_base_addr"), ptr_type_node);
289 chainon (DECL_ARGUMENTS (fndecl), private_base_arg);
290 DECL_ARG_TYPE (private_base_arg) = ptr_type_node;
291 DECL_CONTEXT (private_base_arg) = fndecl;
292 DECL_ARTIFICIAL (private_base_arg) = 1;
293 TREE_READONLY (private_base_arg) = 1;
294 TREE_USED (private_base_arg) = 1;
295
296 DECL_SAVED_TREE (fndecl) = bind_expr;
297
298 /* Try to preserve the functions across IPA. */
299 DECL_PRESERVE_P (fndecl) = 1;
300 TREE_SIDE_EFFECTS (fndecl) = 1;
301
302 TREE_ADDRESSABLE (fndecl) = 1;
303
304 if (base->kind == BRIG_KIND_DIRECTIVE_FUNCTION)
305 {
306 TREE_STATIC (fndecl) = 1;
307 TREE_PUBLIC (fndecl) = 1;
308 }
309 else if (base->kind == BRIG_KIND_DIRECTIVE_KERNEL)
310 {
311 TREE_STATIC (fndecl) = 1;
312 TREE_PUBLIC (fndecl) = 1;
313 }
314 else if (base->kind == BRIG_KIND_DIRECTIVE_SIGNATURE)
315 {
316 TREE_STATIC (fndecl) = 0;
317 TREE_PUBLIC (fndecl) = 1;
318 DECL_EXTERNAL (fndecl) = 1;
319 }
320 else if (base->kind == BRIG_KIND_DIRECTIVE_INDIRECT_FUNCTION)
321 {
322 TREE_STATIC (fndecl) = 0;
323 TREE_PUBLIC (fndecl) = 1;
324 }
325 else
326 gcc_unreachable ();
327
328 TREE_USED (fndecl) = 1;
329 DECL_ARTIFICIAL (fndecl) = 0;
330
331 tree initial_block = make_node (BLOCK);
332 DECL_INITIAL (fndecl) = initial_block;
333 TREE_USED (DECL_INITIAL (fndecl)) = 1;
334
335 if (ret_value != NULL_TREE && TREE_TYPE (ret_value) != void_type_node)
336 {
337 DECL_CONTEXT (ret_value) = fndecl;
338 DECL_CHAIN (ret_value) = BIND_EXPR_VARS (bind_expr);
339 BIND_EXPR_VARS (bind_expr) = ret_value;
340 }
341
342 tree arg;
343 for (arg = DECL_ARGUMENTS (fndecl); arg != NULL_TREE; arg = TREE_CHAIN (arg))
344 {
345 DECL_CONTEXT (arg) = fndecl;
346 DECL_ARG_TYPE (arg) = TREE_TYPE (arg);
347 }
348
349 m_parent.add_function_decl (func_name, fndecl);
350 m_parent.append_global (fndecl);
351
352 if (!is_definition)
353 return bytes_consumed;
354
355 m_parent.start_function (fndecl);
356
357 m_parent.m_cf->m_func_decl = fndecl;
358 m_parent.m_cf->m_current_bind_expr = bind_expr;
359 m_parent.m_cf->m_context_arg = context_arg;
360 m_parent.m_cf->m_private_base_arg = private_base_arg;
361
362 if (ret_value != NULL_TREE && TREE_TYPE (ret_value) != void_type_node)
363 {
364 /* We cannot assign to <<retval>> directly in gcc trunk. We need to
365 create a local temporary variable which can be stored to and when
366 returning from the function, we'll copy it to the actual <<retval>>
367 in return statement's argument. */
368 tree temp_var = m_parent.m_cf->m_ret_temp
369 = m_parent.m_cf->add_local_variable ("_retvalue_temp",
370 TREE_TYPE (ret_value));
371 TREE_ADDRESSABLE (temp_var) = 1;
372 }
373
374 if (is_kernel)
375 {
376 m_parent.m_cf->add_id_variables ();
377
378 /* Create a single entry point in the function. */
379 m_parent.m_cf->m_entry_label_stmt
380 = build_stmt (LABEL_EXPR, m_parent.m_cf->label ("__kernel_entry"));
381 m_parent.m_cf->append_statement (m_parent.m_cf->m_entry_label_stmt);
382
383 tree bind_expr = m_parent.m_cf->m_current_bind_expr;
384 tree stmts = BIND_EXPR_BODY (bind_expr);
385
386 m_parent.m_cf->m_kernel_entry = tsi_last (stmts);
387
388 /* Let's not append the exit label yet, but only after the
389 function has been built. We need to build it so it can
390 be referred to because returns are converted to gotos to this
391 label. */
392 m_parent.m_cf->m_exit_label = m_parent.m_cf->label ("__kernel_exit");
393 }
394
395 return bytes_consumed;
396 }