1 /* brig-branch-inst-handler.cc -- brig branch instruction handling
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/>. */
22 #include "brig-code-entry-handler.h"
25 #include "brig-util.h"
26 #include "tree-pretty-print.h"
27 #include "print-tree.h"
29 #include "fold-const.h"
32 brig_branch_inst_handler::operator () (const BrigBase
*base
)
34 const BrigInstBase
*brig_inst
35 = (const BrigInstBase
*) &((const BrigInstBasic
*) base
)->base
;
37 if (brig_inst
->opcode
== BRIG_OPCODE_CALL
)
39 const BrigData
*operand_entries
40 = m_parent
.get_brig_data_entry (brig_inst
->operands
);
41 tree func_ref
= NULL_TREE
;
42 vec
<tree
, va_gc
> *out_args
;
43 vec_alloc (out_args
, 1);
44 vec
<tree
, va_gc
> *in_args
;
45 vec_alloc (in_args
, 4);
47 size_t operand_count
= operand_entries
->byteCount
/ 4;
48 gcc_assert (operand_count
< 4);
50 for (size_t i
= 0; i
< operand_count
; ++i
)
52 uint32_t operand_offset
53 = ((const uint32_t *) &operand_entries
->bytes
)[i
];
54 const BrigBase
*operand_data
55 = m_parent
.get_brig_operand_entry (operand_offset
);
58 gcc_assert (operand_data
->kind
== BRIG_KIND_OPERAND_CODE_REF
);
59 func_ref
= build_tree_operand (*brig_inst
, *operand_data
);
62 gcc_assert (operand_data
->kind
== BRIG_KIND_OPERAND_CODE_LIST
);
63 const BrigOperandCodeList
*codelist
64 = (const BrigOperandCodeList
*) operand_data
;
66 = m_parent
.get_brig_data_entry (codelist
->elements
);
68 size_t bytes
= data
->byteCount
;
69 const BrigOperandOffset32_t
*operand_ptr
70 = (const BrigOperandOffset32_t
*) data
->bytes
;
72 vec
<tree
, va_gc
> *args
= i
== 0 ? out_args
: in_args
;
76 BrigOperandOffset32_t offset
= *operand_ptr
;
77 const BrigBase
*code_element
78 = m_parent
.get_brig_code_entry (offset
);
79 gcc_assert (code_element
->kind
== BRIG_KIND_DIRECTIVE_VARIABLE
);
80 const BrigDirectiveVariable
*brig_var
81 = (const BrigDirectiveVariable
*) code_element
;
82 tree var
= m_parent
.m_cf
->arg_variable (brig_var
);
84 if (brig_var
->type
& BRIG_TYPE_ARRAY
)
86 /* Array return values are passed as the first argument. */
88 /* Pass pointer to the element zero and use its element zero
89 as the base address. */
90 tree etype
= TREE_TYPE (TREE_TYPE (var
));
91 tree ptype
= build_pointer_type (etype
);
93 = build4 (ARRAY_REF
, etype
, var
, integer_zero_node
,
94 NULL_TREE
, NULL_TREE
);
95 var
= build1 (ADDR_EXPR
, ptype
, element_zero
);
98 gcc_assert (var
!= NULL_TREE
);
99 vec_safe_push (args
, var
);
105 gcc_assert (func_ref
!= NULL_TREE
);
106 gcc_assert (out_args
->length () == 0 || out_args
->length () == 1);
108 tree ret_val_type
= void_type_node
;
109 tree ret_val
= NULL_TREE
;
110 if (out_args
->length () == 1)
112 ret_val
= (*out_args
)[0];
113 ret_val_type
= TREE_TYPE (ret_val
);
116 /* Pass the hidden kernel arguments along to the called functions as
117 they might call builtins that need them or access group/private
120 vec_safe_push (in_args
, m_parent
.m_cf
->m_context_arg
);
121 vec_safe_push (in_args
, m_parent
.m_cf
->m_group_base_arg
);
122 vec_safe_push (in_args
, m_parent
.m_cf
->m_private_base_arg
);
124 tree call
= build_call_vec (ret_val_type
, build_fold_addr_expr (func_ref
),
126 TREE_NOTHROW (func_ref
) = 1;
127 TREE_NOTHROW (call
) = 1;
129 if (ret_val
!= NULL_TREE
)
131 TREE_ADDRESSABLE (ret_val
) = 1;
133 = build2 (MODIFY_EXPR
, TREE_TYPE (ret_val
), ret_val
, call
);
134 m_parent
.m_cf
->append_statement (result_assign
);
138 m_parent
.m_cf
->append_statement (call
);
141 m_parent
.m_cf
->m_has_unexpanded_dp_builtins
= false;
142 m_parent
.m_cf
->m_called_functions
.push_back (func_ref
);
144 return base
->byteCount
;
147 tree instr_type
= gccbrig_tree_type_for_hsa_type (brig_inst
->type
);
148 tree_stl_vec operands
= build_operands (*brig_inst
);
150 if (brig_inst
->opcode
== BRIG_OPCODE_BR
)
152 tree goto_stmt
= build1 (GOTO_EXPR
, instr_type
, operands
[0]);
153 m_parent
.m_cf
->append_statement (goto_stmt
);
155 else if (brig_inst
->opcode
== BRIG_OPCODE_SBR
)
157 tree select
= operands
[0];
158 tree cases
= operands
[1];
160 tree switch_expr
= build3 (SWITCH_EXPR
, TREE_TYPE (select
), select
,
161 NULL_TREE
, NULL_TREE
);
164 = build_case_label (NULL_TREE
, NULL_TREE
,
165 create_artificial_label (UNKNOWN_LOCATION
));
166 append_to_statement_list (default_case
, &SWITCH_BODY (switch_expr
));
169 = build1 (GOTO_EXPR
, void_type_node
, TREE_VEC_ELT (cases
, 0));
170 append_to_statement_list (default_jump
, &SWITCH_BODY (switch_expr
));
172 for (int c
= 0; c
< TREE_VEC_LENGTH (cases
); ++c
)
175 = build_case_label (build_int_cst (integer_type_node
, c
), NULL_TREE
,
176 create_artificial_label (UNKNOWN_LOCATION
));
178 append_to_statement_list (case_label
, &SWITCH_BODY (switch_expr
));
181 = build1 (GOTO_EXPR
, void_type_node
, TREE_VEC_ELT (cases
, c
));
182 append_to_statement_list (jump
, &SWITCH_BODY (switch_expr
));
184 m_parent
.m_cf
->append_statement (switch_expr
);
186 else if (brig_inst
->opcode
== BRIG_OPCODE_CBR
)
188 tree condition
= operands
[0];
189 tree target_goto
= build1 (GOTO_EXPR
, void_type_node
, operands
[1]);
190 /* Represents the if..else as (condition)?(goto foo):(goto bar). */
192 = build3 (COND_EXPR
, void_type_node
, condition
, target_goto
, NULL_TREE
);
193 m_parent
.m_cf
->append_statement (if_stmt
);
195 else if (brig_inst
->opcode
== BRIG_OPCODE_WAVEBARRIER
)
197 /* WAVEBARRIER is a NOP when WAVESIZE = 1. */
199 else if (brig_inst
->opcode
== BRIG_OPCODE_BARRIER
)
201 m_parent
.m_cf
->m_has_barriers
= true;
202 tree_stl_vec call_operands
;
203 /* FIXME. We should add attributes (are there suitable ones in gcc?) that
204 ensure the barrier won't be duplicated or moved out of loops etc.
205 Like the 'noduplicate' of LLVM. Same goes for fbarriers. */
206 m_parent
.m_cf
->append_statement
207 (expand_or_call_builtin (brig_inst
->opcode
, BRIG_TYPE_NONE
, NULL_TREE
,
210 else if (brig_inst
->opcode
>= BRIG_OPCODE_ARRIVEFBAR
211 && brig_inst
->opcode
<= BRIG_OPCODE_WAITFBAR
)
213 m_parent
.m_cf
->m_has_barriers
= true;
214 m_parent
.m_cf
->append_statement
215 (expand_or_call_builtin (brig_inst
->opcode
, BRIG_TYPE_NONE
,
216 uint32_type_node
, operands
));
220 return base
->byteCount
;