]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/brig/brigfrontend/brig-branch-inst-handler.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / brig / brigfrontend / brig-branch-inst-handler.cc
CommitLineData
5fd1486c 1/* brig-branch-inst-handler.cc -- brig branch instruction handling
85ec4feb 2 Copyright (C) 2016-2018 Free Software Foundation, Inc.
5fd1486c
PJ
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 "brig-code-entry-handler.h"
23
24#include "errors.h"
25#include "brig-util.h"
26#include "tree-pretty-print.h"
27#include "print-tree.h"
28#include "vec.h"
29#include "fold-const.h"
30
31size_t
32brig_branch_inst_handler::operator () (const BrigBase *base)
33{
34 const BrigInstBase *brig_inst
35 = (const BrigInstBase *) &((const BrigInstBasic *) base)->base;
36
37 if (brig_inst->opcode == BRIG_OPCODE_CALL)
38 {
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;
e1e299f3
HL
45 /* Ten elem initially, more reserved if needed. */
46 vec_alloc (in_args, 10);
5fd1486c
PJ
47
48 size_t operand_count = operand_entries->byteCount / 4;
49 gcc_assert (operand_count < 4);
50
51 for (size_t i = 0; i < operand_count; ++i)
52 {
53 uint32_t operand_offset
54 = ((const uint32_t *) &operand_entries->bytes)[i];
55 const BrigBase *operand_data
56 = m_parent.get_brig_operand_entry (operand_offset);
57 if (i == 1)
58 {
59 gcc_assert (operand_data->kind == BRIG_KIND_OPERAND_CODE_REF);
60 func_ref = build_tree_operand (*brig_inst, *operand_data);
61 continue;
62 }
63 gcc_assert (operand_data->kind == BRIG_KIND_OPERAND_CODE_LIST);
64 const BrigOperandCodeList *codelist
65 = (const BrigOperandCodeList *) operand_data;
66 const BrigData *data
67 = m_parent.get_brig_data_entry (codelist->elements);
68
69 size_t bytes = data->byteCount;
70 const BrigOperandOffset32_t *operand_ptr
71 = (const BrigOperandOffset32_t *) data->bytes;
72
14108eda 73 bool out_args_p = i == 0;
5fd1486c
PJ
74
75 while (bytes > 0)
76 {
77 BrigOperandOffset32_t offset = *operand_ptr;
78 const BrigBase *code_element
79 = m_parent.get_brig_code_entry (offset);
80 gcc_assert (code_element->kind == BRIG_KIND_DIRECTIVE_VARIABLE);
81 const BrigDirectiveVariable *brig_var
82 = (const BrigDirectiveVariable *) code_element;
83 tree var = m_parent.m_cf->arg_variable (brig_var);
84
85 if (brig_var->type & BRIG_TYPE_ARRAY)
86 {
87 /* Array return values are passed as the first argument. */
14108eda 88 out_args_p = false;
5fd1486c
PJ
89 /* Pass pointer to the element zero and use its element zero
90 as the base address. */
91 tree etype = TREE_TYPE (TREE_TYPE (var));
92 tree ptype = build_pointer_type (etype);
93 tree element_zero
94 = build4 (ARRAY_REF, etype, var, integer_zero_node,
95 NULL_TREE, NULL_TREE);
96 var = build1 (ADDR_EXPR, ptype, element_zero);
97 }
98
99 gcc_assert (var != NULL_TREE);
14108eda 100 vec_safe_push (out_args_p ? out_args : in_args, var);
5fd1486c
PJ
101 ++operand_ptr;
102 bytes -= 4;
103 }
104 }
105
106 gcc_assert (func_ref != NULL_TREE);
107 gcc_assert (out_args->length () == 0 || out_args->length () == 1);
108
109 tree ret_val_type = void_type_node;
110 tree ret_val = NULL_TREE;
111 if (out_args->length () == 1)
112 {
113 ret_val = (*out_args)[0];
114 ret_val_type = TREE_TYPE (ret_val);
115 }
116
117 /* Pass the hidden kernel arguments along to the called functions as
118 they might call builtins that need them or access group/private
119 memory. */
120
d4b7f2ee
PJ
121 tree group_local_offset
122 = add_temp_var ("group_local_offset",
123 build_int_cst
124 (uint32_type_node,
125 m_parent.m_cf->m_local_group_variables.size()));
126
127 /* TODO: ensure the callee's frame is aligned! */
128
e1e299f3 129 vec_safe_reserve (in_args, 4);
5fd1486c
PJ
130 vec_safe_push (in_args, m_parent.m_cf->m_context_arg);
131 vec_safe_push (in_args, m_parent.m_cf->m_group_base_arg);
d4b7f2ee 132 vec_safe_push (in_args, group_local_offset);
5fd1486c
PJ
133 vec_safe_push (in_args, m_parent.m_cf->m_private_base_arg);
134
135 tree call = build_call_vec (ret_val_type, build_fold_addr_expr (func_ref),
136 in_args);
137 TREE_NOTHROW (func_ref) = 1;
138 TREE_NOTHROW (call) = 1;
139
140 if (ret_val != NULL_TREE)
141 {
142 TREE_ADDRESSABLE (ret_val) = 1;
143 tree result_assign
144 = build2 (MODIFY_EXPR, TREE_TYPE (ret_val), ret_val, call);
145 m_parent.m_cf->append_statement (result_assign);
146 }
147 else
148 {
149 m_parent.m_cf->append_statement (call);
150 }
151
5fd1486c
PJ
152 m_parent.m_cf->m_called_functions.push_back (func_ref);
153
154 return base->byteCount;
155 }
156
157 tree instr_type = gccbrig_tree_type_for_hsa_type (brig_inst->type);
158 tree_stl_vec operands = build_operands (*brig_inst);
159
160 if (brig_inst->opcode == BRIG_OPCODE_BR)
161 {
162 tree goto_stmt = build1 (GOTO_EXPR, instr_type, operands[0]);
163 m_parent.m_cf->append_statement (goto_stmt);
164 }
165 else if (brig_inst->opcode == BRIG_OPCODE_SBR)
166 {
167 tree select = operands[0];
168 tree cases = operands[1];
169
9e851845
JJ
170 tree switch_expr = build2 (SWITCH_EXPR, TREE_TYPE (select), select,
171 NULL_TREE);
5fd1486c
PJ
172
173 tree default_case
174 = build_case_label (NULL_TREE, NULL_TREE,
175 create_artificial_label (UNKNOWN_LOCATION));
176 append_to_statement_list (default_case, &SWITCH_BODY (switch_expr));
177
178 tree default_jump
179 = build1 (GOTO_EXPR, void_type_node, TREE_VEC_ELT (cases, 0));
180 append_to_statement_list (default_jump, &SWITCH_BODY (switch_expr));
181
182 for (int c = 0; c < TREE_VEC_LENGTH (cases); ++c)
183 {
184 tree case_label
185 = build_case_label (build_int_cst (integer_type_node, c), NULL_TREE,
186 create_artificial_label (UNKNOWN_LOCATION));
187
188 append_to_statement_list (case_label, &SWITCH_BODY (switch_expr));
189
190 tree jump
191 = build1 (GOTO_EXPR, void_type_node, TREE_VEC_ELT (cases, c));
192 append_to_statement_list (jump, &SWITCH_BODY (switch_expr));
193 }
194 m_parent.m_cf->append_statement (switch_expr);
195 }
196 else if (brig_inst->opcode == BRIG_OPCODE_CBR)
197 {
198 tree condition = operands[0];
199 tree target_goto = build1 (GOTO_EXPR, void_type_node, operands[1]);
200 /* Represents the if..else as (condition)?(goto foo):(goto bar). */
201 tree if_stmt
202 = build3 (COND_EXPR, void_type_node, condition, target_goto, NULL_TREE);
203 m_parent.m_cf->append_statement (if_stmt);
204 }
205 else if (brig_inst->opcode == BRIG_OPCODE_WAVEBARRIER)
206 {
207 /* WAVEBARRIER is a NOP when WAVESIZE = 1. */
208 }
209 else if (brig_inst->opcode == BRIG_OPCODE_BARRIER)
210 {
211 m_parent.m_cf->m_has_barriers = true;
212 tree_stl_vec call_operands;
213 /* FIXME. We should add attributes (are there suitable ones in gcc?) that
214 ensure the barrier won't be duplicated or moved out of loops etc.
215 Like the 'noduplicate' of LLVM. Same goes for fbarriers. */
216 m_parent.m_cf->append_statement
217 (expand_or_call_builtin (brig_inst->opcode, BRIG_TYPE_NONE, NULL_TREE,
218 call_operands));
219 }
220 else if (brig_inst->opcode >= BRIG_OPCODE_ARRIVEFBAR
221 && brig_inst->opcode <= BRIG_OPCODE_WAITFBAR)
222 {
223 m_parent.m_cf->m_has_barriers = true;
224 m_parent.m_cf->append_statement
225 (expand_or_call_builtin (brig_inst->opcode, BRIG_TYPE_NONE,
226 uint32_type_node, operands));
227 }
228 else
229 gcc_unreachable ();
230 return base->byteCount;
231}