1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2018 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci */ 24bf215546Sopenharmony_ci#include <ctype.h> 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "glsl_types.h" 27bf215546Sopenharmony_ci#include "linker_util.h" 28bf215546Sopenharmony_ci#include "util/bitscan.h" 29bf215546Sopenharmony_ci#include "util/set.h" 30bf215546Sopenharmony_ci#include "ir_uniform.h" /* for gl_uniform_storage */ 31bf215546Sopenharmony_ci#include "main/shader_types.h" 32bf215546Sopenharmony_ci#include "main/consts_exts.h" 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci/** 35bf215546Sopenharmony_ci * Given a string identifying a program resource, break it into a base name 36bf215546Sopenharmony_ci * and an optional array index in square brackets. 37bf215546Sopenharmony_ci * 38bf215546Sopenharmony_ci * If an array index is present, \c out_base_name_end is set to point to the 39bf215546Sopenharmony_ci * "[" that precedes the array index, and the array index itself is returned 40bf215546Sopenharmony_ci * as a long. 41bf215546Sopenharmony_ci * 42bf215546Sopenharmony_ci * If no array index is present (or if the array index is negative or 43bf215546Sopenharmony_ci * mal-formed), \c out_base_name_end, is set to point to the null terminator 44bf215546Sopenharmony_ci * at the end of the input string, and -1 is returned. 45bf215546Sopenharmony_ci * 46bf215546Sopenharmony_ci * Only the final array index is parsed; if the string contains other array 47bf215546Sopenharmony_ci * indices (or structure field accesses), they are left in the base name. 48bf215546Sopenharmony_ci * 49bf215546Sopenharmony_ci * No attempt is made to check that the base name is properly formed; 50bf215546Sopenharmony_ci * typically the caller will look up the base name in a hash table, so 51bf215546Sopenharmony_ci * ill-formed base names simply turn into hash table lookup failures. 52bf215546Sopenharmony_ci */ 53bf215546Sopenharmony_cilong 54bf215546Sopenharmony_cilink_util_parse_program_resource_name(const GLchar *name, const size_t len, 55bf215546Sopenharmony_ci const GLchar **out_base_name_end) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci /* Section 7.3.1 ("Program Interfaces") of the OpenGL 4.3 spec says: 58bf215546Sopenharmony_ci * 59bf215546Sopenharmony_ci * "When an integer array element or block instance number is part of 60bf215546Sopenharmony_ci * the name string, it will be specified in decimal form without a "+" 61bf215546Sopenharmony_ci * or "-" sign or any extra leading zeroes. Additionally, the name 62bf215546Sopenharmony_ci * string will not include white space anywhere in the string." 63bf215546Sopenharmony_ci */ 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci *out_base_name_end = name + len; 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci if (len == 0 || name[len-1] != ']') 68bf215546Sopenharmony_ci return -1; 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci /* Walk backwards over the string looking for a non-digit character. This 71bf215546Sopenharmony_ci * had better be the opening bracket for an array index. 72bf215546Sopenharmony_ci * 73bf215546Sopenharmony_ci * Initially, i specifies the location of the ']'. Since the string may 74bf215546Sopenharmony_ci * contain only the ']' charcater, walk backwards very carefully. 75bf215546Sopenharmony_ci */ 76bf215546Sopenharmony_ci unsigned i; 77bf215546Sopenharmony_ci for (i = len - 1; (i > 0) && isdigit(name[i-1]); --i) 78bf215546Sopenharmony_ci /* empty */ ; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci if ((i == 0) || name[i-1] != '[') 81bf215546Sopenharmony_ci return -1; 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci long array_index = strtol(&name[i], NULL, 10); 84bf215546Sopenharmony_ci if (array_index < 0) 85bf215546Sopenharmony_ci return -1; 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci /* Check for leading zero */ 88bf215546Sopenharmony_ci if (name[i] == '0' && name[i+1] != ']') 89bf215546Sopenharmony_ci return -1; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci *out_base_name_end = name + (i - 1); 92bf215546Sopenharmony_ci return array_index; 93bf215546Sopenharmony_ci} 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci/* Utility methods shared between the GLSL IR and the NIR */ 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci/* From the OpenGL 4.6 specification, 7.3.1.1 Naming Active Resources: 98bf215546Sopenharmony_ci * 99bf215546Sopenharmony_ci * "For an active shader storage block member declared as an array of an 100bf215546Sopenharmony_ci * aggregate type, an entry will be generated only for the first array 101bf215546Sopenharmony_ci * element, regardless of its type. Such block members are referred to as 102bf215546Sopenharmony_ci * top-level arrays. If the block member is an aggregate type, the 103bf215546Sopenharmony_ci * enumeration rules are then applied recursively." 104bf215546Sopenharmony_ci */ 105bf215546Sopenharmony_cibool 106bf215546Sopenharmony_cilink_util_should_add_buffer_variable(struct gl_shader_program *prog, 107bf215546Sopenharmony_ci struct gl_uniform_storage *uniform, 108bf215546Sopenharmony_ci int top_level_array_base_offset, 109bf215546Sopenharmony_ci int top_level_array_size_in_bytes, 110bf215546Sopenharmony_ci int second_element_offset, 111bf215546Sopenharmony_ci int block_index) 112bf215546Sopenharmony_ci{ 113bf215546Sopenharmony_ci /* If the uniform is not a shader storage buffer or is not an array return 114bf215546Sopenharmony_ci * true. 115bf215546Sopenharmony_ci */ 116bf215546Sopenharmony_ci if (!uniform->is_shader_storage || top_level_array_size_in_bytes == 0) 117bf215546Sopenharmony_ci return true; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci int after_top_level_array = top_level_array_base_offset + 120bf215546Sopenharmony_ci top_level_array_size_in_bytes; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci /* Check for a new block, or that we are not dealing with array elements of 123bf215546Sopenharmony_ci * a top member array other than the first element. 124bf215546Sopenharmony_ci */ 125bf215546Sopenharmony_ci if (block_index != uniform->block_index || 126bf215546Sopenharmony_ci uniform->offset >= after_top_level_array || 127bf215546Sopenharmony_ci uniform->offset < second_element_offset) { 128bf215546Sopenharmony_ci return true; 129bf215546Sopenharmony_ci } 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci return false; 132bf215546Sopenharmony_ci} 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_cibool 135bf215546Sopenharmony_cilink_util_add_program_resource(struct gl_shader_program *prog, 136bf215546Sopenharmony_ci struct set *resource_set, 137bf215546Sopenharmony_ci GLenum type, const void *data, uint8_t stages) 138bf215546Sopenharmony_ci{ 139bf215546Sopenharmony_ci assert(data); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci /* If resource already exists, do not add it again. */ 142bf215546Sopenharmony_ci if (_mesa_set_search(resource_set, data)) 143bf215546Sopenharmony_ci return true; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci prog->data->ProgramResourceList = 146bf215546Sopenharmony_ci reralloc(prog->data, 147bf215546Sopenharmony_ci prog->data->ProgramResourceList, 148bf215546Sopenharmony_ci gl_program_resource, 149bf215546Sopenharmony_ci prog->data->NumProgramResourceList + 1); 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci if (!prog->data->ProgramResourceList) { 152bf215546Sopenharmony_ci linker_error(prog, "Out of memory during linking.\n"); 153bf215546Sopenharmony_ci return false; 154bf215546Sopenharmony_ci } 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci struct gl_program_resource *res = 157bf215546Sopenharmony_ci &prog->data->ProgramResourceList[prog->data->NumProgramResourceList]; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci res->Type = type; 160bf215546Sopenharmony_ci res->Data = data; 161bf215546Sopenharmony_ci res->StageReferences = stages; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci prog->data->NumProgramResourceList++; 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci _mesa_set_add(resource_set, data); 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci return true; 168bf215546Sopenharmony_ci} 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci/** 171bf215546Sopenharmony_ci * Search through the list of empty blocks to find one that fits the current 172bf215546Sopenharmony_ci * uniform. 173bf215546Sopenharmony_ci */ 174bf215546Sopenharmony_ciint 175bf215546Sopenharmony_cilink_util_find_empty_block(struct gl_shader_program *prog, 176bf215546Sopenharmony_ci struct gl_uniform_storage *uniform) 177bf215546Sopenharmony_ci{ 178bf215546Sopenharmony_ci const unsigned entries = MAX2(1, uniform->array_elements); 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci foreach_list_typed(struct empty_uniform_block, block, link, 181bf215546Sopenharmony_ci &prog->EmptyUniformLocations) { 182bf215546Sopenharmony_ci /* Found a block with enough slots to fit the uniform */ 183bf215546Sopenharmony_ci if (block->slots == entries) { 184bf215546Sopenharmony_ci unsigned start = block->start; 185bf215546Sopenharmony_ci exec_node_remove(&block->link); 186bf215546Sopenharmony_ci ralloc_free(block); 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci return start; 189bf215546Sopenharmony_ci /* Found a block with more slots than needed. It can still be used. */ 190bf215546Sopenharmony_ci } else if (block->slots > entries) { 191bf215546Sopenharmony_ci unsigned start = block->start; 192bf215546Sopenharmony_ci block->start += entries; 193bf215546Sopenharmony_ci block->slots -= entries; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci return start; 196bf215546Sopenharmony_ci } 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci return -1; 200bf215546Sopenharmony_ci} 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_civoid 203bf215546Sopenharmony_cilink_util_update_empty_uniform_locations(struct gl_shader_program *prog) 204bf215546Sopenharmony_ci{ 205bf215546Sopenharmony_ci struct empty_uniform_block *current_block = NULL; 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ci for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) { 208bf215546Sopenharmony_ci /* We found empty space in UniformRemapTable. */ 209bf215546Sopenharmony_ci if (prog->UniformRemapTable[i] == NULL) { 210bf215546Sopenharmony_ci /* We've found the beginning of a new continous block of empty slots */ 211bf215546Sopenharmony_ci if (!current_block || current_block->start + current_block->slots != i) { 212bf215546Sopenharmony_ci current_block = rzalloc(prog, struct empty_uniform_block); 213bf215546Sopenharmony_ci current_block->start = i; 214bf215546Sopenharmony_ci exec_list_push_tail(&prog->EmptyUniformLocations, 215bf215546Sopenharmony_ci ¤t_block->link); 216bf215546Sopenharmony_ci } 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci /* The current block continues, so we simply increment its slots */ 219bf215546Sopenharmony_ci current_block->slots++; 220bf215546Sopenharmony_ci } 221bf215546Sopenharmony_ci } 222bf215546Sopenharmony_ci} 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_civoid 225bf215546Sopenharmony_cilink_util_check_subroutine_resources(struct gl_shader_program *prog) 226bf215546Sopenharmony_ci{ 227bf215546Sopenharmony_ci unsigned mask = prog->data->linked_stages; 228bf215546Sopenharmony_ci while (mask) { 229bf215546Sopenharmony_ci const int i = u_bit_scan(&mask); 230bf215546Sopenharmony_ci struct gl_program *p = prog->_LinkedShaders[i]->Program; 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci if (p->sh.NumSubroutineUniformRemapTable > MAX_SUBROUTINE_UNIFORM_LOCATIONS) { 233bf215546Sopenharmony_ci linker_error(prog, "Too many %s shader subroutine uniforms\n", 234bf215546Sopenharmony_ci _mesa_shader_stage_to_string(i)); 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci} 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci/** 240bf215546Sopenharmony_ci * Validate uniform resources used by a program versus the implementation limits 241bf215546Sopenharmony_ci */ 242bf215546Sopenharmony_civoid 243bf215546Sopenharmony_cilink_util_check_uniform_resources(const struct gl_constants *consts, 244bf215546Sopenharmony_ci struct gl_shader_program *prog) 245bf215546Sopenharmony_ci{ 246bf215546Sopenharmony_ci unsigned total_uniform_blocks = 0; 247bf215546Sopenharmony_ci unsigned total_shader_storage_blocks = 0; 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 250bf215546Sopenharmony_ci struct gl_linked_shader *sh = prog->_LinkedShaders[i]; 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci if (sh == NULL) 253bf215546Sopenharmony_ci continue; 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci if (sh->num_uniform_components > 256bf215546Sopenharmony_ci consts->Program[i].MaxUniformComponents) { 257bf215546Sopenharmony_ci if (consts->GLSLSkipStrictMaxUniformLimitCheck) { 258bf215546Sopenharmony_ci linker_warning(prog, "Too many %s shader default uniform block " 259bf215546Sopenharmony_ci "components, but the driver will try to optimize " 260bf215546Sopenharmony_ci "them out; this is non-portable out-of-spec " 261bf215546Sopenharmony_ci "behavior\n", 262bf215546Sopenharmony_ci _mesa_shader_stage_to_string(i)); 263bf215546Sopenharmony_ci } else { 264bf215546Sopenharmony_ci linker_error(prog, "Too many %s shader default uniform block " 265bf215546Sopenharmony_ci "components\n", 266bf215546Sopenharmony_ci _mesa_shader_stage_to_string(i)); 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci } 269bf215546Sopenharmony_ci 270bf215546Sopenharmony_ci if (sh->num_combined_uniform_components > 271bf215546Sopenharmony_ci consts->Program[i].MaxCombinedUniformComponents) { 272bf215546Sopenharmony_ci if (consts->GLSLSkipStrictMaxUniformLimitCheck) { 273bf215546Sopenharmony_ci linker_warning(prog, "Too many %s shader uniform components, " 274bf215546Sopenharmony_ci "but the driver will try to optimize them out; " 275bf215546Sopenharmony_ci "this is non-portable out-of-spec behavior\n", 276bf215546Sopenharmony_ci _mesa_shader_stage_to_string(i)); 277bf215546Sopenharmony_ci } else { 278bf215546Sopenharmony_ci linker_error(prog, "Too many %s shader uniform components\n", 279bf215546Sopenharmony_ci _mesa_shader_stage_to_string(i)); 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci total_shader_storage_blocks += sh->Program->info.num_ssbos; 284bf215546Sopenharmony_ci total_uniform_blocks += sh->Program->info.num_ubos; 285bf215546Sopenharmony_ci } 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci if (total_uniform_blocks > consts->MaxCombinedUniformBlocks) { 288bf215546Sopenharmony_ci linker_error(prog, "Too many combined uniform blocks (%d/%d)\n", 289bf215546Sopenharmony_ci total_uniform_blocks, consts->MaxCombinedUniformBlocks); 290bf215546Sopenharmony_ci } 291bf215546Sopenharmony_ci 292bf215546Sopenharmony_ci if (total_shader_storage_blocks > consts->MaxCombinedShaderStorageBlocks) { 293bf215546Sopenharmony_ci linker_error(prog, "Too many combined shader storage blocks (%d/%d)\n", 294bf215546Sopenharmony_ci total_shader_storage_blocks, 295bf215546Sopenharmony_ci consts->MaxCombinedShaderStorageBlocks); 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci for (unsigned i = 0; i < prog->data->NumUniformBlocks; i++) { 299bf215546Sopenharmony_ci if (prog->data->UniformBlocks[i].UniformBufferSize > 300bf215546Sopenharmony_ci consts->MaxUniformBlockSize) { 301bf215546Sopenharmony_ci linker_error(prog, "Uniform block %s too big (%d/%d)\n", 302bf215546Sopenharmony_ci prog->data->UniformBlocks[i].name.string, 303bf215546Sopenharmony_ci prog->data->UniformBlocks[i].UniformBufferSize, 304bf215546Sopenharmony_ci consts->MaxUniformBlockSize); 305bf215546Sopenharmony_ci } 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci for (unsigned i = 0; i < prog->data->NumShaderStorageBlocks; i++) { 309bf215546Sopenharmony_ci if (prog->data->ShaderStorageBlocks[i].UniformBufferSize > 310bf215546Sopenharmony_ci consts->MaxShaderStorageBlockSize) { 311bf215546Sopenharmony_ci linker_error(prog, "Shader storage block %s too big (%d/%d)\n", 312bf215546Sopenharmony_ci prog->data->ShaderStorageBlocks[i].name.string, 313bf215546Sopenharmony_ci prog->data->ShaderStorageBlocks[i].UniformBufferSize, 314bf215546Sopenharmony_ci consts->MaxShaderStorageBlockSize); 315bf215546Sopenharmony_ci } 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci} 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_civoid 320bf215546Sopenharmony_cilink_util_calculate_subroutine_compat(struct gl_shader_program *prog) 321bf215546Sopenharmony_ci{ 322bf215546Sopenharmony_ci unsigned mask = prog->data->linked_stages; 323bf215546Sopenharmony_ci while (mask) { 324bf215546Sopenharmony_ci const int i = u_bit_scan(&mask); 325bf215546Sopenharmony_ci struct gl_program *p = prog->_LinkedShaders[i]->Program; 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci for (unsigned j = 0; j < p->sh.NumSubroutineUniformRemapTable; j++) { 328bf215546Sopenharmony_ci if (p->sh.SubroutineUniformRemapTable[j] == INACTIVE_UNIFORM_EXPLICIT_LOCATION) 329bf215546Sopenharmony_ci continue; 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[j]; 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci if (!uni) 334bf215546Sopenharmony_ci continue; 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci int count = 0; 337bf215546Sopenharmony_ci if (p->sh.NumSubroutineFunctions == 0) { 338bf215546Sopenharmony_ci linker_error(prog, "subroutine uniform %s defined but no valid functions found\n", uni->type->name); 339bf215546Sopenharmony_ci continue; 340bf215546Sopenharmony_ci } 341bf215546Sopenharmony_ci for (unsigned f = 0; f < p->sh.NumSubroutineFunctions; f++) { 342bf215546Sopenharmony_ci struct gl_subroutine_function *fn = &p->sh.SubroutineFunctions[f]; 343bf215546Sopenharmony_ci for (int k = 0; k < fn->num_compat_types; k++) { 344bf215546Sopenharmony_ci if (fn->types[k] == uni->type) { 345bf215546Sopenharmony_ci count++; 346bf215546Sopenharmony_ci break; 347bf215546Sopenharmony_ci } 348bf215546Sopenharmony_ci } 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci uni->num_compatible_subroutines = count; 351bf215546Sopenharmony_ci } 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci} 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci/** 356bf215546Sopenharmony_ci * Recursive part of the public mark_array_elements_referenced function. 357bf215546Sopenharmony_ci * 358bf215546Sopenharmony_ci * The recursion occurs when an entire array-of- is accessed. See the 359bf215546Sopenharmony_ci * implementation for more details. 360bf215546Sopenharmony_ci * 361bf215546Sopenharmony_ci * \param dr List of array_deref_range elements to be 362bf215546Sopenharmony_ci * processed. 363bf215546Sopenharmony_ci * \param count Number of array_deref_range elements to be 364bf215546Sopenharmony_ci * processed. 365bf215546Sopenharmony_ci * \param scale Current offset scale. 366bf215546Sopenharmony_ci * \param linearized_index Current accumulated linearized array index. 367bf215546Sopenharmony_ci */ 368bf215546Sopenharmony_civoid 369bf215546Sopenharmony_ci_mark_array_elements_referenced(const struct array_deref_range *dr, 370bf215546Sopenharmony_ci unsigned count, unsigned scale, 371bf215546Sopenharmony_ci unsigned linearized_index, 372bf215546Sopenharmony_ci BITSET_WORD *bits) 373bf215546Sopenharmony_ci{ 374bf215546Sopenharmony_ci /* Walk through the list of array dereferences in least- to 375bf215546Sopenharmony_ci * most-significant order. Along the way, accumulate the current 376bf215546Sopenharmony_ci * linearized offset and the scale factor for each array-of-. 377bf215546Sopenharmony_ci */ 378bf215546Sopenharmony_ci for (unsigned i = 0; i < count; i++) { 379bf215546Sopenharmony_ci if (dr[i].index < dr[i].size) { 380bf215546Sopenharmony_ci linearized_index += dr[i].index * scale; 381bf215546Sopenharmony_ci scale *= dr[i].size; 382bf215546Sopenharmony_ci } else { 383bf215546Sopenharmony_ci /* For each element in the current array, update the count and 384bf215546Sopenharmony_ci * offset, then recurse to process the remaining arrays. 385bf215546Sopenharmony_ci * 386bf215546Sopenharmony_ci * There is some inefficency here if the last eBITSET_WORD *bitslement in the 387bf215546Sopenharmony_ci * array_deref_range list specifies the entire array. In that case, 388bf215546Sopenharmony_ci * the loop will make recursive calls with count == 0. In the call, 389bf215546Sopenharmony_ci * all that will happen is the bit will be set. 390bf215546Sopenharmony_ci */ 391bf215546Sopenharmony_ci for (unsigned j = 0; j < dr[i].size; j++) { 392bf215546Sopenharmony_ci _mark_array_elements_referenced(&dr[i + 1], 393bf215546Sopenharmony_ci count - (i + 1), 394bf215546Sopenharmony_ci scale * dr[i].size, 395bf215546Sopenharmony_ci linearized_index + (j * scale), 396bf215546Sopenharmony_ci bits); 397bf215546Sopenharmony_ci } 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci return; 400bf215546Sopenharmony_ci } 401bf215546Sopenharmony_ci } 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci BITSET_SET(bits, linearized_index); 404bf215546Sopenharmony_ci} 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci/** 407bf215546Sopenharmony_ci * Mark a set of array elements as accessed. 408bf215546Sopenharmony_ci * 409bf215546Sopenharmony_ci * If every \c array_deref_range is for a single index, only a single 410bf215546Sopenharmony_ci * element will be marked. If any \c array_deref_range is for an entire 411bf215546Sopenharmony_ci * array-of-, then multiple elements will be marked. 412bf215546Sopenharmony_ci * 413bf215546Sopenharmony_ci * Items in the \c array_deref_range list appear in least- to 414bf215546Sopenharmony_ci * most-significant order. This is the \b opposite order the indices 415bf215546Sopenharmony_ci * appear in the GLSL shader text. An array access like 416bf215546Sopenharmony_ci * 417bf215546Sopenharmony_ci * x = y[1][i][3]; 418bf215546Sopenharmony_ci * 419bf215546Sopenharmony_ci * would appear as 420bf215546Sopenharmony_ci * 421bf215546Sopenharmony_ci * { { 3, n }, { m, m }, { 1, p } } 422bf215546Sopenharmony_ci * 423bf215546Sopenharmony_ci * where n, m, and p are the sizes of the arrays-of-arrays. 424bf215546Sopenharmony_ci * 425bf215546Sopenharmony_ci * The set of marked array elements can later be queried by 426bf215546Sopenharmony_ci * \c ::is_linearized_index_referenced. 427bf215546Sopenharmony_ci * 428bf215546Sopenharmony_ci * \param dr List of array_deref_range elements to be processed. 429bf215546Sopenharmony_ci * \param count Number of array_deref_range elements to be processed. 430bf215546Sopenharmony_ci */ 431bf215546Sopenharmony_civoid 432bf215546Sopenharmony_cilink_util_mark_array_elements_referenced(const struct array_deref_range *dr, 433bf215546Sopenharmony_ci unsigned count, unsigned array_depth, 434bf215546Sopenharmony_ci BITSET_WORD *bits) 435bf215546Sopenharmony_ci{ 436bf215546Sopenharmony_ci if (count != array_depth) 437bf215546Sopenharmony_ci return; 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci _mark_array_elements_referenced(dr, count, 1, 0, bits); 440bf215546Sopenharmony_ci} 441