v2: Start with everything uniform and mark non-uniformity. This is required in order to properly handle loops.
Cc: Kenneth Graunke <kenn...@whitecape.org> Cc: Connor Abbott <cwabbo...@gmail.com> --- src/compiler/Makefile.sources | 1 + src/compiler/nir/nir.c | 3 + src/compiler/nir/nir.h | 18 +++ src/compiler/nir/nir_analyze_uniformity.c | 188 ++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 src/compiler/nir/nir_analyze_uniformity.c diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources index 2455d4e..407197c 100644 --- a/src/compiler/Makefile.sources +++ b/src/compiler/Makefile.sources @@ -186,6 +186,7 @@ NIR_GENERATED_FILES = \ NIR_FILES = \ nir/nir.c \ nir/nir.h \ + nir/nir_analyze_uniformity.c \ nir/nir_array.h \ nir/nir_builder.h \ nir/nir_clone.c \ diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c index a9fac96..fd64ccd 100644 --- a/src/compiler/nir/nir.c +++ b/src/compiler/nir/nir.c @@ -357,6 +357,8 @@ nir_block_create(nir_shader *shader) exec_list_make_empty(&block->instr_list); + block->uniform = false; + return block; } @@ -1518,6 +1520,7 @@ nir_ssa_def_init(nir_instr *instr, nir_ssa_def *def, list_inithead(&def->if_uses); def->num_components = num_components; def->bit_size = bit_size; + def->uniform = false; if (instr->block) { nir_function_impl *impl = diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index dd1e407..4da318d 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -462,6 +462,14 @@ typedef struct nir_ssa_def { /* The bit-size of each channel; must be one of 8, 16, 32, or 64 */ uint8_t bit_size; + + /** True if this SSA def has the same value for all invocations + * + * An SSA def can be uniform even if it is defined in non-uniform + * control-flow. In this case, it has the same value for all invocations + * which reach its definition. + */ + bool uniform; } nir_ssa_def; struct nir_src; @@ -1480,6 +1488,14 @@ typedef struct nir_block { /** generic block index; generated by nir_index_blocks */ unsigned index; + /** True if this block is only executed uniformly + * + * A block is said to execute uniformly if, whenever one invocation enters + * the block, all invocations enter the block and have all taken the same + * path from the start block to this block. + */ + bool uniform; + /* * Each block can only have up to 2 successors, so we put them in a simple * array - no need for anything more complicated. @@ -2567,6 +2583,8 @@ bool nir_normalize_cubemap_coords(nir_shader *shader); void nir_live_ssa_defs_impl(nir_function_impl *impl); +void nir_analyze_uniformity(nir_shader *shader); + void nir_loop_analyze_impl(nir_function_impl *impl, nir_variable_mode indirect_mask); diff --git a/src/compiler/nir/nir_analyze_uniformity.c b/src/compiler/nir/nir_analyze_uniformity.c new file mode 100644 index 0000000..42693f3 --- /dev/null +++ b/src/compiler/nir/nir_analyze_uniformity.c @@ -0,0 +1,188 @@ +/* + * Copyright © 2016 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "nir.h" + +/** + * Uniform analysis + */ + +static bool +src_is_uniform(nir_src *src, void *state) +{ + return src->is_ssa && src->ssa->uniform; +} + +static bool +mark_def_non_uniform(nir_ssa_def *def, void *state) +{ + bool *progress = state; + + if (def->uniform) { + *progress = true; + def->uniform = false; + } + + return true; +} + +static void +mark_block_non_uniform(nir_block *block, bool *progress) +{ + if (block->uniform) { + *progress = true; + block->uniform = false; + } +} + +static bool +block_all_predecessors_uniform(nir_block *block) +{ + struct set_entry *entry; + set_foreach(block->predecessors, entry) { + nir_block *pred = (nir_block *)entry->key; + if (!pred->uniform) + return false; + } + return true; +} + +static void +analyze_uniformity_block(nir_block *block, bool *progress) +{ + if (nir_cf_node_prev(&block->cf_node) == NULL && + block->cf_node.parent->type == nir_cf_node_if) { + /* We are the start of the else or then list of an if. If the condition + * of that if isn't uniform, then neither is this block. + */ + nir_if *parent_if = nir_cf_node_as_if(block->cf_node.parent); + if (!parent_if->condition.is_ssa || !parent_if->condition.ssa->uniform) + mark_block_non_uniform(block, progress); + } + + if (!block_all_predecessors_uniform(block)) + mark_block_non_uniform(block, progress); + + nir_foreach_instr(instr, block) { + switch (instr->type) { + case nir_instr_type_ssa_undef: + /* Undefs are uniformly undefined! */ + assert(nir_instr_as_ssa_undef(instr)->def.uniform); + break; + + case nir_instr_type_load_const: + /* load_const is always uniform */ + assert(nir_instr_as_load_const(instr)->def.uniform); + break; + + case nir_instr_type_phi: { + /* For phis we need to take into account both the sources and the + * predecessor blocks + */ + nir_phi_instr *phi = nir_instr_as_phi(instr); + assert(phi->dest.is_ssa); + nir_foreach_phi_src(src, phi) { + assert(src->src.is_ssa); + if (!src->pred->uniform || !src->src.ssa->uniform) { + mark_def_non_uniform(&phi->dest.ssa, progress); + break; + } + } + break; + } + + case nir_instr_type_intrinsic: { + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + assert(intrin->dest.is_ssa); + + switch (intrin->intrinsic) { + case nir_intrinsic_image_load: + case nir_intrinsic_image_size: + case nir_intrinsic_image_samples: + case nir_intrinsic_get_buffer_size: + case nir_intrinsic_vulkan_resource_index: + case nir_intrinsic_load_patch_vertices_in: + case nir_intrinsic_load_num_work_groups: + case nir_intrinsic_load_uniform: + case nir_intrinsic_load_ubo: + case nir_intrinsic_load_push_constant: + /* Anything in this list is guaranteed to be uniform whenever all + * of the sources to the intrinsic are uniform. + */ + if (!nir_foreach_src(instr, src_is_uniform, NULL)) + mark_def_non_uniform(&intrin->dest.ssa, progress); + break; + + default: + /* Anything that isn't in the list above can't easily be + * guaranteed to be uniform + */ + mark_def_non_uniform(&intrin->dest.ssa, progress); + break; + } + break; + } + + default: + if (!nir_foreach_src(instr, src_is_uniform, NULL)) + nir_foreach_ssa_def(instr, mark_def_non_uniform, progress); + break; + } + } +} + +static bool +mark_def_uniform(nir_ssa_def *def, void *state) +{ + def->uniform = true; + return true; +} + +static void +analyze_uniformity_impl(nir_function_impl *impl) +{ + /* First, mark everything uniform */ + nir_foreach_block(block, impl) { + block->uniform = true; + nir_foreach_instr(instr, block) + nir_foreach_ssa_def(instr, mark_def_uniform, NULL); + } + + /* Now systematically destroy uniformness until there is no more. */ + bool progress; + do { + nir_foreach_block(block, impl) + analyze_uniformity_block(block, &progress); + } while (progress); +} + +void +nir_analyze_uniformity(nir_shader *shader) +{ + nir_foreach_function(function, shader) { + if (!function->impl) + continue; + + analyze_uniformity_impl(function->impl); + } +} -- 2.5.0.400.gff86faf _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev