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