Mesa (master): nir/opt_vectorize: use a single instruction per hash entry instead of a vector

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Dec 31 17:03:11 UTC 2020


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

Author: Daniel Schürmann <daniel at schuermann.dev>
Date:   Wed Sep 23 15:08:13 2020 +0100

nir/opt_vectorize: use a single instruction per hash entry instead of a vector

This drastically simplifies vectorization but may potentially
lead to slightly worse vectorizations.

Reviewed-by: Connor Abbott <cwabbott0 at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6666>

---

 src/compiler/nir/nir_opt_vectorize.c | 139 ++++++-----------------------------
 1 file changed, 24 insertions(+), 115 deletions(-)

diff --git a/src/compiler/nir/nir_opt_vectorize.c b/src/compiler/nir/nir_opt_vectorize.c
index 80115be0ce5..2231651ea5e 100644
--- a/src/compiler/nir/nir_opt_vectorize.c
+++ b/src/compiler/nir/nir_opt_vectorize.c
@@ -62,8 +62,9 @@ hash_alu(uint32_t hash, const nir_alu_instr *instr)
 }
 
 static uint32_t
-hash_instr(const nir_instr *instr)
+hash_instr(const void *data)
 {
+   const nir_instr *instr = (nir_instr *) data;
    uint32_t hash = 0;
 
    switch (instr->type) {
@@ -96,8 +97,10 @@ alu_srcs_equal(const nir_alu_src *src1, const nir_alu_src *src2)
 }
 
 static bool
-instrs_equal(const nir_instr *instr1, const nir_instr *instr2)
+instrs_equal(const void *data1, const void *data2)
 {
+   const nir_instr *instr1 = (nir_instr *) data1;
+   const nir_instr *instr2 = (nir_instr *) data2;
    switch (instr1->type) {
    case nir_instr_type_alu: {
       nir_alu_instr *alu1 = nir_instr_as_alu(instr1);
@@ -315,78 +318,10 @@ instr_try_combine(struct nir_shader *nir, nir_instr *instr1, nir_instr *instr2,
    return &new_alu->instr;
 }
 
-/*
- * Use an array to represent a stack of instructions that are equivalent.
- *
- * We push and pop instructions off the stack in dominance order. The first
- * element dominates the second element which dominates the third, etc. When
- * trying to add to the stack, first we try and combine the instruction with
- * each of the instructions on the stack and, if successful, replace the
- * instruction on the stack with the newly-combined instruction.
- */
-
-static struct util_dynarray *
-vec_instr_stack_create(void *mem_ctx)
-{
-   struct util_dynarray *stack = ralloc(mem_ctx, struct util_dynarray);
-   util_dynarray_init(stack, mem_ctx);
-   return stack;
-}
-
-/* returns true if we were able to successfully replace the instruction */
-
-static bool
-vec_instr_stack_push(struct nir_shader *nir, struct util_dynarray *stack,
-                     nir_instr *instr,
-                     nir_opt_vectorize_cb filter, void *data)
-{
-   /* Walk the stack from child to parent to make live ranges shorter by
-    * matching the closest thing we can
-    */
-   util_dynarray_foreach_reverse(stack, nir_instr *, stack_instr) {
-      nir_instr *new_instr = instr_try_combine(nir, *stack_instr, instr,
-                                               filter, data);
-      if (new_instr) {
-         *stack_instr = new_instr;
-         return true;
-      }
-   }
-
-   util_dynarray_append(stack, nir_instr *, instr);
-   return false;
-}
-
-static void
-vec_instr_stack_pop(struct util_dynarray *stack, nir_instr *instr)
-{
-   ASSERTED nir_instr *last = util_dynarray_pop(stack, nir_instr *);
-   assert(last == instr);
-}
-
-static bool
-cmp_func(const void *data1, const void *data2)
-{
-   const struct util_dynarray *arr1 = data1;
-   const struct util_dynarray *arr2 = data2;
-
-   const nir_instr *instr1 = *(nir_instr **)util_dynarray_begin(arr1);
-   const nir_instr *instr2 = *(nir_instr **)util_dynarray_begin(arr2);
-
-   return instrs_equal(instr1, instr2);
-}
-
-static uint32_t
-hash_stack(const void *data)
-{
-   const struct util_dynarray *stack = data;
-   const nir_instr *first = *(nir_instr **)util_dynarray_begin(stack);
-   return hash_instr(first);
-}
-
 static struct set *
 vec_instr_set_create(void)
 {
-   return _mesa_set_create(NULL, hash_stack, cmp_func);
+   return _mesa_set_create(NULL, hash_instr, instrs_equal);
 }
 
 static void
@@ -403,54 +338,22 @@ vec_instr_set_add_or_rewrite(struct nir_shader *nir, struct set *instr_set,
    if (!instr_can_rewrite(instr))
       return false;
 
-   struct util_dynarray *new_stack = vec_instr_stack_create(instr_set);
-   vec_instr_stack_push(nir, new_stack, instr, filter, data);
-
-   struct set_entry *entry = _mesa_set_search(instr_set, new_stack);
-
+   struct set_entry *entry = _mesa_set_search(instr_set, instr);
    if (entry) {
-      ralloc_free(new_stack);
-      struct util_dynarray *stack = (struct util_dynarray *) entry->key;
-      return vec_instr_stack_push(nir, stack, instr, filter, data);
+      nir_instr *old_instr = (nir_instr *) entry->key;
+      _mesa_set_remove(instr_set, entry);
+      nir_instr *new_instr = instr_try_combine(nir, old_instr, instr,
+                                               filter, data);
+      if (new_instr) {
+         _mesa_set_add(instr_set, new_instr);
+         return true;
+      }
    }
 
-   _mesa_set_add(instr_set, new_stack);
+   _mesa_set_add(instr_set, instr);
    return false;
 }
 
-static void
-vec_instr_set_remove(struct nir_shader *nir, struct set *instr_set,
-                     nir_instr *instr, nir_opt_vectorize_cb filter, void *data)
-{
-   if (!instr_can_rewrite(instr))
-      return;
-
-   /*
-    * It's pretty unfortunate that we have to do this, but it's a side effect
-    * of the hash set interfaces. The hash set assumes that we're only
-    * interested in storing one equivalent element at a time, and if we try to
-    * insert a duplicate element it will remove the original. We could hack up
-    * the comparison function to "know" which input is an instruction we
-    * passed in and which is an array that's part of the entry, but that
-    * wouldn't work because we need to pass an array to _mesa_set_add() in
-    * vec_instr_add_or_rewrite() above, and _mesa_set_add() will call our
-    * comparison function as well.
-    */
-   struct util_dynarray *temp = vec_instr_stack_create(instr_set);
-   vec_instr_stack_push(nir, temp, instr, filter, data);
-   struct set_entry *entry = _mesa_set_search(instr_set, temp);
-   ralloc_free(temp);
-
-   if (entry) {
-      struct util_dynarray *stack = (struct util_dynarray *) entry->key;
-
-      if (util_dynarray_num_elements(stack, nir_instr *) > 1)
-         vec_instr_stack_pop(stack, instr);
-      else
-         _mesa_set_remove(instr_set, entry);
-   }
-}
-
 static bool
 vectorize_block(struct nir_shader *nir, nir_block *block,
                 struct set *instr_set,
@@ -468,8 +371,14 @@ vectorize_block(struct nir_shader *nir, nir_block *block,
       progress |= vectorize_block(nir, child, instr_set, filter, data);
    }
 
-   nir_foreach_instr_reverse(instr, block)
-      vec_instr_set_remove(nir, instr_set, instr, filter, data);
+   nir_foreach_instr_reverse(instr, block) {
+      if (instr->type != nir_instr_type_alu)
+         continue;
+
+      struct set_entry *entry = _mesa_set_search(instr_set, instr);
+      if (entry)
+         _mesa_set_remove(instr_set, entry);
+   }
 
    return progress;
 }



More information about the mesa-commit mailing list