Mesa (master): nir/opt_intrinsic: Optimize bcsel(b, shuffle(x, i), shuffle(x, j))

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Nov 3 23:31:09 UTC 2020


Module: Mesa
Branch: master
Commit: 4ff4d4e56966a40bff83d1813e3a308cff38736e
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=4ff4d4e56966a40bff83d1813e3a308cff38736e

Author: Jason Ekstrand <jason at jlekstrand.net>
Date:   Fri Oct 23 16:48:38 2020 -0500

nir/opt_intrinsic: Optimize bcsel(b, shuffle(x, i), shuffle(x, j))

The shuffles provided by the SPV_INTEL_subgroups extension generate

    bcsel(b, shuffle(x, i), shuffle(y, j))

In the case where x and y are the same, we can turn this into a shuffle
with the bcsel on the index which lets us drop a whole shuffle.

Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira at intel.com>
Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7366>

---

 src/compiler/nir/nir_opt_intrinsics.c | 88 +++++++++++++++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/src/compiler/nir/nir_opt_intrinsics.c b/src/compiler/nir/nir_opt_intrinsics.c
index 2b2e64c9fdd..1a0cc509296 100644
--- a/src/compiler/nir/nir_opt_intrinsics.c
+++ b/src/compiler/nir/nir_opt_intrinsics.c
@@ -28,6 +28,89 @@
  * \file nir_opt_intrinsics.c
  */
 
+static bool
+src_is_single_use_shuffle(nir_src src, nir_ssa_def **data, nir_ssa_def **index)
+{
+   nir_intrinsic_instr *shuffle = nir_src_as_intrinsic(src);
+   if (shuffle == NULL || shuffle->intrinsic != nir_intrinsic_shuffle)
+      return false;
+
+   /* This is only called when src is part of an ALU op so requiring no if
+    * uses is reasonable.  If we ever want to use this from an if statement,
+    * we can change it then.
+    */
+   if (!list_is_empty(&shuffle->dest.ssa.if_uses) ||
+       !list_is_singular(&shuffle->dest.ssa.uses))
+      return false;
+
+   assert(shuffle->src[0].is_ssa);
+   assert(shuffle->src[1].is_ssa);
+
+   *data = shuffle->src[0].ssa;
+   *index = shuffle->src[1].ssa;
+
+   return true;
+}
+
+static nir_ssa_def *
+try_opt_bcsel_of_shuffle(nir_builder *b, nir_alu_instr *alu)
+{
+   assert(alu->op == nir_op_bcsel);
+
+   if (!nir_alu_src_is_trivial_ssa(alu, 0))
+      return NULL;
+
+   nir_ssa_def *data1, *index1;
+   if (!nir_alu_src_is_trivial_ssa(alu, 1) ||
+       !src_is_single_use_shuffle(alu->src[1].src, &data1, &index1))
+      return NULL;
+
+   nir_ssa_def *data2, *index2;
+   if (!nir_alu_src_is_trivial_ssa(alu, 2) ||
+       !src_is_single_use_shuffle(alu->src[2].src, &data2, &index2))
+      return NULL;
+
+   if (data1 != data2)
+      return NULL;
+
+   nir_ssa_def *index = nir_bcsel(b, alu->src[0].src.ssa, index1, index2);
+   nir_intrinsic_instr *shuffle =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_shuffle);
+   shuffle->src[0] = nir_src_for_ssa(index);
+   shuffle->src[1] = nir_src_for_ssa(data1);
+   shuffle->num_components = alu->dest.dest.ssa.num_components;
+   nir_ssa_dest_init(&shuffle->instr, &shuffle->dest,
+                     alu->dest.dest.ssa.num_components,
+                     alu->dest.dest.ssa.bit_size, NULL);
+   nir_builder_instr_insert(b, &shuffle->instr);
+
+   return &shuffle->dest.ssa;
+}
+
+static bool
+opt_intrinsics_alu(nir_builder *b, nir_alu_instr *alu)
+{
+   nir_ssa_def *replacement = NULL;
+
+   switch (alu->op) {
+   case nir_op_bcsel:
+      replacement = try_opt_bcsel_of_shuffle(b, alu);
+      break;
+
+   default:
+      break;
+   }
+
+   if (replacement) {
+      nir_ssa_def_rewrite_uses(&alu->dest.dest.ssa,
+                               nir_src_for_ssa(replacement));
+      nir_instr_remove(&alu->instr);
+      return true;
+   } else {
+      return false;
+   }
+}
+
 static bool
 opt_intrinsics_intrin(nir_builder *b, nir_intrinsic_instr *intrin,
                       const struct nir_shader_compiler_options *options)
@@ -89,6 +172,11 @@ opt_intrinsics_impl(nir_function_impl *impl,
          b.cursor = nir_before_instr(instr);
 
          switch (instr->type) {
+         case nir_instr_type_alu:
+            if (opt_intrinsics_alu(&b, nir_instr_as_alu(instr)))
+               progress = true;
+            break;
+
          case nir_instr_type_intrinsic:
             if (opt_intrinsics_intrin(&b, nir_instr_as_intrinsic(instr),
                                       options))



More information about the mesa-commit mailing list