xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/brig/brigfrontend/brig-variable-handler.cc (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /* brig-variable-handler.cc -- brig variable directive handling
2    Copyright (C) 2016-2020 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 "brig-code-entry-handler.h"
23 
24 #include "stringpool.h"
25 #include "errors.h"
26 #include "brig-machine.h"
27 #include "brig-util.h"
28 #include "print-tree.h"
29 #include "diagnostic-core.h"
30 #include "brig-to-generic.h"
31 
32 tree
build_variable(const BrigDirectiveVariable * brigVar,tree_code var_decltype)33 brig_directive_variable_handler::build_variable
34   (const BrigDirectiveVariable *brigVar, tree_code var_decltype)
35 {
36   std::string var_name = m_parent.get_mangled_name (brigVar);
37 
38   bool is_definition = brigVar->modifier & BRIG_VARIABLE_DEFINITION;
39 
40   tree name_identifier = get_identifier (var_name.c_str ());
41 
42   tree var_decl;
43   tree t;
44   if (brigVar->type & BRIG_TYPE_ARRAY)
45     {
46       tree element_type
47 	= gccbrig_tree_type_for_hsa_type (brigVar->type & ~BRIG_TYPE_ARRAY);
48       uint64_t element_count = gccbrig_to_uint64_t (brigVar->dim);
49       if (is_definition && element_count == 0)
50 	fatal_error (UNKNOWN_LOCATION, "Array definition with zero elements.");
51       if (var_decltype == PARM_DECL)
52 	t = build_pointer_type (element_type);
53       else
54 	t = build_array_type_nelts (element_type, element_count);
55     }
56   else
57     {
58       t = gccbrig_tree_type_for_hsa_type (brigVar->type);
59     }
60 
61   size_t alignment = get_brig_var_alignment (brigVar);
62 
63   if (brigVar->segment == BRIG_SEGMENT_READONLY
64       || brigVar->segment == BRIG_SEGMENT_KERNARG
65       || (brigVar->modifier & BRIG_VARIABLE_CONST))
66     TYPE_READONLY (t) = 1;
67 
68   TYPE_ADDR_SPACE (t) = gccbrig_get_target_addr_space_id (brigVar->segment);
69 
70   var_decl = build_decl (UNKNOWN_LOCATION, var_decltype, name_identifier, t);
71 
72   SET_DECL_ALIGN (var_decl, alignment * BITS_PER_UNIT);
73 
74   /* Force the HSA alignments.  */
75   DECL_USER_ALIGN (var_decl) = 1;
76 
77   TREE_USED (var_decl) = 1;
78 
79   TREE_PUBLIC (var_decl) = 1;
80   if (is_definition)
81     DECL_EXTERNAL (var_decl) = 0;
82   else
83     DECL_EXTERNAL (var_decl) = 1; /* The definition is elsewhere.  */
84 
85   if (brigVar->init != 0)
86     {
87       gcc_assert (brigVar->segment == BRIG_SEGMENT_READONLY
88 		  || brigVar->segment == BRIG_SEGMENT_GLOBAL);
89 
90       const BrigBase *cst_operand_data
91 	= m_parent.get_brig_operand_entry (brigVar->init);
92 
93       tree initializer = NULL_TREE;
94       if (cst_operand_data->kind == BRIG_KIND_OPERAND_CONSTANT_BYTES)
95 	initializer = get_tree_cst_for_hsa_operand
96 	  ((const BrigOperandConstantBytes *) cst_operand_data, t);
97       else
98 	error ("variable initializers of type %x not implemented",
99 	       cst_operand_data->kind);
100       gcc_assert (initializer != NULL_TREE);
101       DECL_INITIAL (var_decl) = initializer;
102     }
103 
104   if (var_decltype == PARM_DECL)
105     {
106       DECL_ARG_TYPE (var_decl) = TREE_TYPE (var_decl);
107       DECL_EXTERNAL (var_decl) = 0;
108       TREE_PUBLIC (var_decl) = 0;
109     }
110 
111   TREE_ADDRESSABLE (var_decl) = 1;
112 
113   TREE_USED (var_decl) = 1;
114   DECL_NONLOCAL (var_decl) = 1;
115   DECL_ARTIFICIAL (var_decl) = 0;
116 
117   return var_decl;
118 }
119 
120 size_t
operator ()(const BrigBase * base)121 brig_directive_variable_handler::operator () (const BrigBase *base)
122 {
123   const BrigDirectiveVariable *brigVar = (const BrigDirectiveVariable *) base;
124 
125   bool is_definition = brigVar->modifier & BRIG_VARIABLE_DEFINITION;
126 
127   size_t var_size;
128   tree var_type;
129   if (brigVar->type & BRIG_TYPE_ARRAY)
130     {
131       tree element_type
132 	= gccbrig_tree_type_for_hsa_type (brigVar->type & ~BRIG_TYPE_ARRAY);
133       uint64_t element_count = gccbrig_to_uint64_t (brigVar->dim);
134       if (is_definition && element_count == 0)
135 	fatal_error (UNKNOWN_LOCATION, "Array definition with zero elements.");
136       var_type = build_array_type_nelts (element_type, element_count);
137       size_t element_size = tree_to_uhwi (TYPE_SIZE (element_type));
138       var_size = element_size * element_count / 8;
139     }
140   else
141     {
142       var_type = gccbrig_tree_type_for_hsa_type (brigVar->type);
143       var_size = tree_to_uhwi (TYPE_SIZE (var_type)) / 8;
144     }
145 
146   size_t alignment = get_brig_var_alignment (brigVar);
147 
148   bool function_scope = m_parent.m_cf != NULL;
149 
150   if (function_scope)
151     m_parent.m_cf->m_function_scope_vars.insert (base);
152 
153   std::string var_name = m_parent.get_mangled_name (brigVar);
154   if (brigVar->segment == BRIG_SEGMENT_GROUP)
155     {
156       /* Non-kernel scope group variables have been added at the
157 	 'analyze' stage.  */
158       m_parent.add_group_variable (var_name, var_size, alignment,
159 				   function_scope);
160       return base->byteCount;
161     }
162 
163   /* During analyze, handle only (module scope) group variables.  */
164   if (m_parent.m_analyzing)
165     return base->byteCount;
166 
167   if (brigVar->segment == BRIG_SEGMENT_KERNARG)
168     {
169       /* Do not create a real variable, but only a table of
170 	 offsets to the kernarg segment buffer passed as the
171 	 single argument by the kernel launcher for later
172 	 reference.  Ignore kernel declarations.  */
173       if (m_parent.m_cf != NULL && m_parent.m_cf->m_func_decl != NULL_TREE)
174 	m_parent.m_cf->append_kernel_arg (brigVar, var_size, alignment);
175       return base->byteCount;
176     }
177   else if (brigVar->segment == BRIG_SEGMENT_PRIVATE
178 	   || brigVar->segment == BRIG_SEGMENT_SPILL)
179     {
180       /* Private variables are handled like group variables,
181 	 except that their offsets are multiplied by the work-item
182 	 flat id, when accessed.  */
183       if (!m_parent.has_private_variable (var_name))
184 	m_parent.append_private_variable (var_name, var_size, alignment);
185       return base->byteCount;
186     }
187   else if (brigVar->segment == BRIG_SEGMENT_GLOBAL
188 	   || brigVar->segment == BRIG_SEGMENT_READONLY)
189     {
190       tree def = is_definition ? NULL_TREE :
191 	m_parent.global_variable (var_name);
192 
193       if (!is_definition && def != NULL_TREE)
194 	{
195 	  /* We have a definition already for this declaration.
196 	     Use the definition instead of the declaration.  */
197 	}
198       else if (gccbrig_might_be_host_defined_var_p (brigVar))
199 	{
200 	  tree var_decl = build_variable (brigVar);
201 	  m_parent.add_host_def_var_ptr (var_name, var_decl);
202 	}
203       else
204 	{
205 	  tree var_decl = build_variable (brigVar);
206 	  /* Make all global variables program scope for now
207 	     so we can get their address from the Runtime API.  */
208 	  DECL_CONTEXT (var_decl) = NULL_TREE;
209 	  TREE_STATIC (var_decl) = 1;
210 	  TREE_PUBLIC (var_decl) = 1;
211 	  set_externally_visible (var_decl);
212 	  m_parent.add_global_variable (var_name, var_decl);
213 	}
214     }
215   else if (brigVar->segment == BRIG_SEGMENT_ARG)
216     {
217 
218       if (m_parent.m_cf->m_generating_arg_block)
219 	{
220 	  tree var_decl = build_variable (brigVar);
221 	  tree bind_expr = m_parent.m_cf->m_current_bind_expr;
222 
223 	  DECL_CONTEXT (var_decl) = m_parent.m_cf->m_func_decl;
224 	  DECL_CHAIN (var_decl) = BIND_EXPR_VARS (bind_expr);
225 	  BIND_EXPR_VARS (bind_expr) = var_decl;
226 	  TREE_PUBLIC (var_decl) = 0;
227 
228 	  m_parent.m_cf->add_arg_variable (brigVar, var_decl);
229 	}
230       else
231 	{
232 	  /* Must be an incoming function argument which has
233 	     been parsed in brig-function-handler.cc.  No
234 	     need to generate anything here.  */
235 	}
236     }
237   else
238     gcc_unreachable ();
239 
240   return base->byteCount;
241 }
242 
243 /* Returns the alignment for the given BRIG variable.  In case the variable
244    explicitly defines alignment and its larger than the natural alignment,
245    returns it instead of the natural one.  */
246 
247 size_t
get_brig_var_alignment(const BrigDirectiveVariable * brigVar)248 brig_directive_variable_handler::get_brig_var_alignment
249 (const BrigDirectiveVariable *brigVar)
250 {
251 
252   size_t defined_alignment
253     = brigVar->align == BRIG_ALIGNMENT_NONE ? 0 : 1 << (brigVar->align - 1);
254   size_t natural_alignment;
255   if (brigVar->type & BRIG_TYPE_ARRAY)
256     {
257       tree element_type
258 	= gccbrig_tree_type_for_hsa_type (brigVar->type & ~BRIG_TYPE_ARRAY);
259       size_t element_size = tree_to_uhwi (TYPE_SIZE (element_type));
260       natural_alignment = element_size / BITS_PER_UNIT;
261     }
262   else
263     {
264       tree t = gccbrig_tree_type_for_hsa_type (brigVar->type);
265       natural_alignment = tree_to_uhwi (TYPE_SIZE (t)) / BITS_PER_UNIT;
266     }
267 
268   return natural_alignment > defined_alignment
269     ? natural_alignment : defined_alignment;
270 }
271