1 /* brig-function.cc -- declaration of brig_function class.
2 Copyright (C) 2016-2017 Free Software Foundation, Inc.
3 Contributed by Pekka Jaaskelainen <pekka.jaaskelainen@parmance.com>
4 for General Processor Tech.
6 This file is part of GCC.
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
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
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/>. */
25 #include "brig-function.h"
26 #include "stringpool.h"
27 #include "tree-iterator.h"
30 #include "gimple-expr.h"
31 #include "print-tree.h"
32 #include "hsa-brig-format.h"
33 #include "stor-layout.h"
34 #include "diagnostic-core.h"
35 #include "brig-code-entry-handler.h"
36 #include "brig-machine.h"
37 #include "brig-util.h"
39 #include "tree-pretty-print.h"
41 #include "profile-count.h"
45 #include "brig-to-generic.h"
46 #include "brig-builtins.h"
48 brig_function::brig_function (const BrigDirectiveExecutable
*exec
,
49 brig_to_generic
*parent
)
50 : m_brig_def (exec
), m_is_kernel (false), m_is_finished (false), m_name (""),
51 m_current_bind_expr (NULL_TREE
), m_func_decl (NULL_TREE
),
52 m_context_arg (NULL_TREE
), m_group_base_arg (NULL_TREE
),
53 m_private_base_arg (NULL_TREE
), m_ret_value (NULL_TREE
),
54 m_next_kernarg_offset (0), m_kernarg_max_align (0),
55 m_ret_value_brig_var (NULL
), m_has_barriers (false),
56 m_has_allocas (false), m_has_function_calls_with_barriers (false),
57 m_calls_analyzed (false), m_is_wg_function (false),
58 m_has_unexpanded_dp_builtins (false), m_generating_arg_block (false),
62 BRIG_2_TREE_HSAIL_TOTAL_REG_COUNT
* sizeof (BrigOperandRegister
*));
63 memset (&m_descriptor
, 0, sizeof (phsa_descriptor
));
66 brig_function::~brig_function ()
68 for (size_t i
= 0; i
< BRIG_2_TREE_HSAIL_TOTAL_REG_COUNT
; ++i
)
70 if (m_regs
[i
] != NULL
)
78 /* Returns a GENERIC label with the given name in the given function.
79 Creates it, if not yet found. */
82 brig_function::label (const std::string
&name
)
84 label_index::const_iterator i
= m_label_index
.find (name
);
85 if (i
== m_label_index
.end ())
88 = get_identifier_with_length (name
.c_str (), name
.size ());
90 tree label_decl
= build_decl (UNKNOWN_LOCATION
, LABEL_DECL
,
91 name_identifier
, void_type_node
);
93 DECL_CONTEXT (label_decl
) = m_func_decl
;
94 DECL_ARTIFICIAL (label_decl
) = 0;
96 m_label_index
[name
] = label_decl
;
103 /* Record an argument variable for later use. This includes both local
104 variables inside arg blocks and incoming function arguments. */
107 brig_function::add_arg_variable (const BrigDirectiveVariable
*brigVar
,
110 m_arg_variables
[brigVar
] = treeDecl
;
114 brig_function::arg_variable (const BrigDirectiveVariable
*var
) const
116 variable_index::const_iterator i
= m_arg_variables
.find (var
);
117 if (i
== m_arg_variables
.end ())
123 /* Appends a new kernel argument descriptor for the current kernel's
127 brig_function::append_kernel_arg (const BrigDirectiveVariable
*var
, size_t size
,
130 gcc_assert (m_func_decl
!= NULL_TREE
);
131 gcc_assert (m_is_kernel
);
133 size_t align_padding
= m_next_kernarg_offset
% alignment
== 0 ?
134 0 : (alignment
- m_next_kernarg_offset
% alignment
);
135 m_next_kernarg_offset
+= align_padding
;
136 m_kernarg_offsets
[var
] = m_next_kernarg_offset
;
137 m_next_kernarg_offset
+= size
;
140 = m_kernarg_max_align
< alignment
? alignment
: m_kernarg_max_align
;
144 brig_function::kernel_arg_offset (const BrigDirectiveVariable
*var
) const
146 var_offset_table::const_iterator i
= m_kernarg_offsets
.find (var
);
147 gcc_assert (i
!= m_kernarg_offsets
.end ());
151 /* Add work-item ID variables to the beginning of the kernel function
152 which can be used for address computation as kernel dispatch packet
153 instructions can be expanded to GENERIC nodes referring to them. */
156 brig_function::add_id_variables ()
158 tree bind_expr
= m_current_bind_expr
;
159 tree stmts
= BIND_EXPR_BODY (bind_expr
);
161 /* Initialize the WG limits and local ids. */
163 tree_stmt_iterator entry
= tsi_start (stmts
);
165 for (int i
= 0; i
< 3; ++i
)
167 char dim_char
= (char) ((int) 'x' + i
);
169 /* The local sizes are limited to 16b values, but let's still use 32b
170 to avoid unnecessary casts (the ID functions are 32b). */
172 = add_local_variable (std::string ("__local_") + dim_char
,
176 = call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_WORKITEMID
), 2,
177 uint32_type_node
, uint32_type_node
,
178 build_int_cst (uint32_type_node
, i
), ptr_type_node
,
181 tree id_init
= build2 (MODIFY_EXPR
, TREE_TYPE (m_local_id_vars
[i
]),
182 m_local_id_vars
[i
], workitemid_call
);
184 tsi_link_after (&entry
, id_init
, TSI_NEW_STMT
);
186 m_cur_wg_size_vars
[i
]
187 = add_local_variable (std::string ("__cur_wg_size_") + dim_char
,
192 (builtin_decl_explicit (BUILT_IN_HSAIL_CURRENTWORKGROUPSIZE
),
193 2, uint32_type_node
, uint32_type_node
,
194 build_int_cst (uint32_type_node
, i
), ptr_type_node
, m_context_arg
);
196 tree limit_init
= build2 (MODIFY_EXPR
, TREE_TYPE (m_cur_wg_size_vars
[i
]),
197 m_cur_wg_size_vars
[i
], cwgz_call
);
199 tsi_link_after (&entry
, limit_init
, TSI_NEW_STMT
);
202 = add_local_variable (std::string ("__workgroupid_") + dim_char
,
206 = call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_WORKGROUPID
),
207 2, uint32_type_node
, uint32_type_node
,
208 build_int_cst (uint32_type_node
, i
), ptr_type_node
,
211 tree wgid_init
= build2 (MODIFY_EXPR
, TREE_TYPE (m_wg_id_vars
[i
]),
212 m_wg_id_vars
[i
], wgid_call
);
214 tsi_link_after (&entry
, wgid_init
, TSI_NEW_STMT
);
217 = add_local_variable (std::string ("__workgroupsize_") + dim_char
,
221 = call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_WORKGROUPSIZE
),
222 2, uint32_type_node
, uint32_type_node
,
223 build_int_cst (uint32_type_node
, i
), ptr_type_node
,
226 tree wgsize_init
= build2 (MODIFY_EXPR
, TREE_TYPE (m_wg_size_vars
[i
]),
227 m_wg_size_vars
[i
], wgsize_call
);
229 tsi_link_after (&entry
, wgsize_init
, TSI_NEW_STMT
);
232 = add_local_variable (std::string ("__gridsize_") + dim_char
,
236 = call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_GRIDSIZE
), 2,
237 uint32_type_node
, uint32_type_node
,
238 build_int_cst (uint32_type_node
, i
), ptr_type_node
,
241 tree gridsize_init
= build2 (MODIFY_EXPR
, TREE_TYPE (m_grid_size_vars
[i
]),
242 m_grid_size_vars
[i
], gridsize_call
);
244 tsi_link_after (&entry
, gridsize_init
, TSI_NEW_STMT
);
247 m_kernel_entry
= entry
;
250 /* Creates a new local variable with the given NAME and given GENERIC
254 brig_function::add_local_variable (std::string name
, tree type
)
257 = get_identifier_with_length (name
.c_str (), name
.size ());
259 = build_decl (UNKNOWN_LOCATION
, VAR_DECL
, name_identifier
, type
);
261 DECL_NONLOCAL (variable
) = 0;
262 TREE_ADDRESSABLE (variable
) = 0;
263 TREE_STATIC (variable
) = 0;
264 TREE_USED (variable
) = 1;
265 DECL_ARTIFICIAL (variable
) = 0;
267 tree bind_expr
= DECL_SAVED_TREE (m_func_decl
);
269 DECL_CONTEXT (variable
) = m_func_decl
;
271 DECL_CHAIN (variable
) = BIND_EXPR_VARS (bind_expr
);
272 BIND_EXPR_VARS (bind_expr
) = variable
;
276 /* Returns a DECL_VAR for the given HSAIL operand register.
277 If it has not been created yet for the function being generated,
278 creates it as an unsigned int variable. */
281 brig_function::get_m_var_declfor_reg (const BrigOperandRegister
*reg
)
283 size_t offset
= reg
->regNum
;
284 switch (reg
->regKind
)
286 case BRIG_REGISTER_KIND_QUAD
:
288 += BRIG_2_TREE_HSAIL_D_REG_COUNT
+ BRIG_2_TREE_HSAIL_S_REG_COUNT
+
289 BRIG_2_TREE_HSAIL_C_REG_COUNT
;
291 case BRIG_REGISTER_KIND_DOUBLE
:
292 offset
+= BRIG_2_TREE_HSAIL_S_REG_COUNT
+ BRIG_2_TREE_HSAIL_C_REG_COUNT
;
294 case BRIG_REGISTER_KIND_SINGLE
:
295 offset
+= BRIG_2_TREE_HSAIL_C_REG_COUNT
;
296 case BRIG_REGISTER_KIND_CONTROL
:
303 reg_decl_index_entry
*regEntry
= m_regs
[offset
];
304 if (regEntry
== NULL
)
306 size_t reg_size
= gccbrig_reg_size (reg
);
309 type
= build_nonstandard_integer_type (reg_size
, true);
311 type
= boolean_type_node
;
313 /* Drop the const qualifier so we do not end up with a read only
314 register variable which cannot be written to later. */
315 tree nonconst_type
= build_type_variant (type
, false, false);
317 regEntry
= new reg_decl_index_entry
;
320 = add_local_variable (gccbrig_reg_name (reg
), nonconst_type
);
321 m_regs
[offset
] = regEntry
;
323 return regEntry
->m_var_decl
;
326 /* Builds a work-item do..while loop for a single DIM. HEADER_ENTRY is
327 a statement after which the iteration variables should be initialized and
328 the loop body starts. BRANCH_AFTER is the statement after which the loop
329 predicate check and the back edge goto will be appended. */
332 brig_function::add_wi_loop (int dim
, tree_stmt_iterator
*header_entry
,
333 tree_stmt_iterator
*branch_after
)
335 tree ivar
= m_local_id_vars
[dim
];
336 tree ivar_max
= m_cur_wg_size_vars
[dim
];
337 tree_stmt_iterator entry
= *header_entry
;
339 /* TODO: this is not a parallel loop as we share the "register variables"
340 across work-items. Should create a copy of them per WI instance. That
341 is, declare temporaries for new definitions inside the loop body, not at
344 tree ivar_init
= build2 (MODIFY_EXPR
, TREE_TYPE (ivar
), ivar
,
345 build_zero_cst (TREE_TYPE (ivar
)));
346 tsi_link_after (&entry
, ivar_init
, TSI_NEW_STMT
);
349 = label (std::string ("__wi_loop_") + (char) ((int) 'x' + dim
));
350 tree loop_body_label_stmt
= build_stmt (LABEL_EXPR
, loop_body_label
);
352 tsi_link_after (&entry
, loop_body_label_stmt
, TSI_NEW_STMT
);
354 if (m_has_unexpanded_dp_builtins
)
357 = builtin_decl_explicit (BUILT_IN_HSAIL_SETWORKITEMID
);
358 /* Set the local ID to the current wi-loop iteration variable value to
359 ensure the builtins see the correct values. */
361 = call_builtin (id_set_builtin
, 3,
362 void_type_node
, uint32_type_node
,
363 build_int_cst (uint32_type_node
, dim
), uint32_type_node
,
364 ivar
, ptr_type_node
, m_context_arg
);
365 tsi_link_after (&entry
, id_set_call
, TSI_NEW_STMT
);
368 /* Increment the WI iteration variable. */
369 tree incr
= build2 (PREINCREMENT_EXPR
, TREE_TYPE (ivar
), ivar
,
370 build_one_cst (TREE_TYPE (ivar
)));
372 tsi_link_after (branch_after
, incr
, TSI_NEW_STMT
);
374 /* Append the predicate check with the back edge goto. */
375 tree condition
= build2 (LT_EXPR
, TREE_TYPE (ivar
), ivar
, ivar_max
);
376 tree target_goto
= build1 (GOTO_EXPR
, void_type_node
, loop_body_label
);
378 = build3 (COND_EXPR
, void_type_node
, condition
, target_goto
, NULL_TREE
);
379 tsi_link_after (branch_after
, if_stmt
, TSI_NEW_STMT
);
382 /* Recursively analyzes the function and its callees for barrier usage. */
385 brig_function::analyze_calls ()
387 if (m_calls_analyzed
)
390 /* Set this early to not get stuck in case of recursive call graphs.
391 This is safe because if the function calls itself, either the function
392 has barrier calls which implies a call to a function with barrier calls,
393 or it doesn't in which case the result depends on the later called
395 m_calls_analyzed
= true;
397 for (size_t i
= 0; i
< m_called_functions
.size (); ++i
)
399 tree f
= m_called_functions
[i
];
400 brig_function
*called_f
= m_parent
->get_finished_function (f
);
401 if (called_f
== NULL
)
403 /* Unfinished function (only declaration within the set of BRIGs)
404 found. Cannot finish the CG analysis. Have to assume it does have
405 a barrier for safety. */
406 m_has_function_calls_with_barriers
= true;
407 m_has_unexpanded_dp_builtins
= true;
410 called_f
->analyze_calls ();
411 /* We can assume m_has_barriers has been correctly set during the
412 construction of the function decl. No need to reanalyze it. */
413 m_has_function_calls_with_barriers
|= called_f
->m_has_barriers
;
415 /* If the function or any of its called functions has dispatch
416 packet builtin calls that require the local id, we need to
417 set the local id to the context in the work item loop before
418 the functions are called. If we analyze the opposite, these
419 function calls can be omitted. */
420 m_has_unexpanded_dp_builtins
|= called_f
->m_has_unexpanded_dp_builtins
;
424 /* Tries to convert the current kernel to a work-group function that executes
425 all work-items using loops. Returns true in case the conversion was
429 brig_function::convert_to_wg_function ()
431 if (!m_calls_analyzed
)
434 if (m_has_barriers
|| m_has_function_calls_with_barriers
)
437 /* The most trivial case: No barriers at all in the kernel.
438 We can create one big work-item loop around the whole kernel. */
439 tree bind_expr
= m_current_bind_expr
;
440 tree stmts
= BIND_EXPR_BODY (bind_expr
);
442 for (int i
= 0; i
< 3; ++i
)
444 /* The previous loop has added a new label to the end of the function,
445 the next level loop should wrap around it also. */
446 tree_stmt_iterator function_exit
= tsi_last (stmts
);
447 add_wi_loop (i
, &m_kernel_entry
, &function_exit
);
450 m_is_wg_function
= true;
454 /* Emits a kernel description to a special ELF section so it can be
455 utilized by an HSA runtime implementation. The assembly block
456 must be emitted to a statement list of an function, which is given
457 as an argument. Returns the assembly block used to emit the section. */
460 brig_function::emit_metadata (tree stmt_list
)
462 /* Emit an ELF section via an assembly directive that generates a special
463 ELF section for each kernel that contains raw bytes of a descriptor
464 object. This is pretty disgusting, but life is never perfect ;) */
466 /* Use the original kernel name without the '_' prefix in the section name. */
467 std::string kern_name
= m_is_kernel
? m_name
.substr (1) : m_name
;
469 std::ostringstream strstr
;
471 << ".pushsection " << PHSA_DESC_SECTION_PREFIX
<< kern_name
473 << "\t.p2align 1, 1, 1" << std::endl
476 for (size_t i
= 0; i
< sizeof (phsa_descriptor
); ++i
)
478 strstr
<< "0x" << std::setw (2) << std::setfill ('0') << std::hex
479 << (unsigned) *((unsigned char *) &m_descriptor
+ i
);
480 if (i
+ 1 < sizeof (phsa_descriptor
))
484 strstr
<< std::endl
<< ".popsection" << std::endl
<< std::endl
;
487 = build_stmt (ASM_EXPR
,
488 build_string (strstr
.str ().size (), strstr
.str ().c_str ()),
489 NULL_TREE
, NULL_TREE
, NULL_TREE
, NULL_TREE
);
491 append_to_statement_list_force (metadata_asm
, &stmt_list
);
495 /* Emits the kernel launcher function. Also emits the metadata section
496 creation statements in it.
498 The launcher function calls the device-side runtime
499 that runs the kernel for all work-items. In C:
501 void KernelName (void* context, void* group_base_addr)
503 __hsail_launch_kernel (_KernelName, context, group_base_addr);
506 or, in case of a successful conversion to a work-group function:
508 void KernelName (void* context, void* group_base_addr)
510 __hsail_launch_wg_function (_KernelName, context, group_base_addr);
513 The user/host sees this function as the kernel to call from the
514 outside. The actual kernel generated from HSAIL was named _KernelName.
518 brig_function::emit_launcher_and_metadata ()
520 /* The original kernel name without the '_' prefix. */
521 std::string kern_name
= m_name
.substr (1);
524 = get_identifier_with_length (kern_name
.c_str (), kern_name
.size ());
527 = build_decl (UNKNOWN_LOCATION
, FUNCTION_DECL
, name_identifier
,
528 build_function_type_list (void_type_node
, ptr_type_node
,
529 ptr_type_node
, NULL_TREE
));
531 TREE_USED (launcher
) = 1;
532 DECL_ARTIFICIAL (launcher
) = 1;
534 tree context_arg
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
535 get_identifier ("__context"), ptr_type_node
);
537 DECL_ARGUMENTS (launcher
) = context_arg
;
538 DECL_ARG_TYPE (context_arg
) = ptr_type_node
;
539 DECL_CONTEXT (context_arg
) = launcher
;
540 TREE_USED (context_arg
) = 1;
541 DECL_ARTIFICIAL (context_arg
) = 1;
543 tree group_base_addr_arg
544 = build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
545 get_identifier ("__group_base_addr"), ptr_type_node
);
547 chainon (DECL_ARGUMENTS (launcher
), group_base_addr_arg
);
548 DECL_ARG_TYPE (group_base_addr_arg
) = ptr_type_node
;
549 DECL_CONTEXT (group_base_addr_arg
) = launcher
;
550 TREE_USED (group_base_addr_arg
) = 1;
551 DECL_ARTIFICIAL (group_base_addr_arg
) = 1;
554 = build_decl (UNKNOWN_LOCATION
, RESULT_DECL
, NULL_TREE
, void_type_node
);
556 DECL_RESULT (launcher
) = resdecl
;
557 DECL_CONTEXT (resdecl
) = launcher
;
559 DECL_INITIAL (launcher
) = make_node (BLOCK
);
560 TREE_USED (DECL_INITIAL (launcher
)) = 1;
562 tree stmt_list
= alloc_stmt_list ();
564 tree bind_expr
= build3 (BIND_EXPR
, void_type_node
, NULL
, stmt_list
, NULL
);
566 TREE_STATIC (launcher
) = 0;
567 TREE_PUBLIC (launcher
) = 1;
569 DECL_SAVED_TREE (launcher
) = bind_expr
;
571 if (DECL_STRUCT_FUNCTION (launcher
) == NULL
)
572 push_struct_function (launcher
);
574 push_cfun (DECL_STRUCT_FUNCTION (launcher
));
576 tree kernel_func_ptr
= build1 (ADDR_EXPR
, ptr_type_node
, m_func_decl
);
578 tree phsail_launch_kernel_call
;
580 /* Emit a launcher depending whether we converted the kernel function to
581 a work group function or not. */
582 if (m_is_wg_function
)
583 phsail_launch_kernel_call
584 = call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_LAUNCH_WG_FUNC
),
586 ptr_type_node
, kernel_func_ptr
, ptr_type_node
,
587 context_arg
, ptr_type_node
, group_base_addr_arg
);
589 phsail_launch_kernel_call
590 = call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_LAUNCH_KERNEL
),
592 ptr_type_node
, kernel_func_ptr
, ptr_type_node
,
593 context_arg
, ptr_type_node
, group_base_addr_arg
);
595 append_to_statement_list_force (phsail_launch_kernel_call
, &stmt_list
);
597 emit_metadata (stmt_list
);
603 brig_function::append_statement (tree stmt
)
605 gcc_assert (m_func_decl
!= NULL
);
607 tree bind_expr
= m_current_bind_expr
;
608 tree stmts
= BIND_EXPR_BODY (bind_expr
);
610 append_to_statement_list_force (stmt
, &stmts
);
614 /* Creates a new "alloca frame" for the current function by
615 injecting an alloca frame push in the beginning of the function
616 and an alloca frame pop before all function exit points. */
619 brig_function::create_alloca_frame ()
621 tree_stmt_iterator entry
;
623 /* Adds the alloca push only after the ids have been initialized
624 in case of a kernel function. */
626 entry
= m_kernel_entry
;
629 tree bind_expr
= m_current_bind_expr
;
630 tree stmts
= BIND_EXPR_BODY (bind_expr
);
631 entry
= tsi_start (stmts
);
634 tree push_frame_builtin
= builtin_decl_explicit (BUILT_IN_HSAIL_PUSH_FRAME
);
636 = call_builtin (push_frame_builtin
, 1, void_type_node
, ptr_type_node
,
639 tsi_link_before (&entry
, push_frame_call
, TSI_NEW_STMT
);
641 tree pop_frame_builtin
= builtin_decl_explicit (BUILT_IN_HSAIL_POP_FRAME
);
645 tree stmt
= tsi_stmt (entry
);
646 if (TREE_CODE (stmt
) == RETURN_EXPR
)
649 = call_builtin (pop_frame_builtin
, 1, void_type_node
,
650 ptr_type_node
, m_context_arg
);
652 tsi_link_before (&entry
, pop_frame_call
, TSI_SAME_STMT
);
656 while (!tsi_end_p (entry
));
659 /* Finishes the currently built function. After calling this, no new
660 statements should be appeneded to the function. */
662 brig_function::finish ()
664 append_return_stmt ();
666 /* Currently assume single alloca frame per WG. */
668 create_alloca_frame ();
672 brig_function::finish_kernel ()
674 /* Kernel functions should have a single exit point.
675 Let's create one. The return instructions should have
676 been converted to branches to this label. */
677 append_statement (build_stmt (LABEL_EXPR
, m_exit_label
));
678 /* Attempt to convert the kernel to a work-group function that
679 executes all work-items of the WG using a loop. */
680 convert_to_wg_function ();
682 append_return_stmt ();
684 /* Currently assume single alloca frame per WG. */
686 create_alloca_frame ();
690 brig_function::append_return_stmt ()
692 gcc_assert (m_current_bind_expr
!= NULL_TREE
);
693 tree stmts
= BIND_EXPR_BODY (m_current_bind_expr
);
695 if (STATEMENT_LIST_TAIL (stmts
) == NULL
)
696 return; /* Empty function. */
698 tree last_stmt
= tsi_stmt (tsi_last (stmts
));
700 if (TREE_CODE (last_stmt
) == RETURN_EXPR
)
703 if (m_ret_value
!= NULL_TREE
)
706 = build2 (MODIFY_EXPR
, TREE_TYPE (m_ret_value
), m_ret_value
,
710 = build1 (RETURN_EXPR
, TREE_TYPE (result_assign
), result_assign
);
711 append_to_statement_list_force (return_expr
, &stmts
);
715 tree return_stmt
= build_stmt (RETURN_EXPR
, NULL
);
716 append_to_statement_list_force (return_stmt
, &stmts
);
721 brig_function::has_function_scope_var (const BrigBase
* var
) const
723 return m_function_scope_vars
.find (var
) != m_function_scope_vars
.end ();