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 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 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 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