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