[Mesa-dev] [RFC v2] nir: Add a uniformity analysis pass
Jason Ekstrand
jason at jlekstrand.net
Sat Mar 4 03:05:59 UTC 2017
v2: Start with everything uniform and mark non-uniformity. This is
required in order to properly handle loops.
Cc: Kenneth Graunke <kenneth at whitecape.org>
Cc: Connor Abbott <cwabbott0 at 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
More information about the mesa-dev
mailing list