<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Thu, Dec 6, 2018 at 9:08 PM Timothy Arceri <<a href="mailto:tarceri@itsqueeze.com" target="_blank">tarceri@itsqueeze.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This detects an induction variable used as an array index to guess<br>
the trip count of the loop. This enables us to do a partial<br>
unroll of the loop, with can eventually result in the loop being<br>
eliminated.<br>
---<br>
 src/compiler/nir/nir.h              |  4 ++<br>
 src/compiler/nir/nir_loop_analyze.c | 78 ++++++++++++++++++++++++++---<br>
 2 files changed, 76 insertions(+), 6 deletions(-)<br>
<br>
diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
index ce4a81fbe1..a40e5a1418 100644<br>
--- a/src/compiler/nir/nir.h<br>
+++ b/src/compiler/nir/nir.h<br>
@@ -1878,6 +1878,7 @@ typedef struct {<br>
    nir_block *continue_from_block;<br>
<br>
    bool continue_from_then;<br>
+   bool induction_rhs;<br>
<br>
    struct list_head loop_terminator_link;<br>
 } nir_loop_terminator;<br>
@@ -1886,6 +1887,9 @@ typedef struct {<br>
    /* Number of instructions in the loop */<br>
    unsigned num_instructions;<br>
<br>
+   /* Guessed trip count based on array indexing */<br>
+   unsigned guessed_trip_count;<br>
+<br>
    /* Maximum number of times the loop is run (if known) */<br>
    unsigned max_trip_count;<br>
<br>
diff --git a/src/compiler/nir/nir_loop_analyze.c b/src/compiler/nir/nir_loop_analyze.c<br>
index eef224e4d5..ffcf2a3c27 100644<br>
--- a/src/compiler/nir/nir_loop_analyze.c<br>
+++ b/src/compiler/nir/nir_loop_analyze.c<br>
@@ -382,6 +382,50 @@ find_array_access_via_induction(loop_info_state *state,<br>
    return 0;<br>
 }<br>
<br>
+static bool<br>
+guess_loop_limit(loop_info_state *state, nir_const_value *limit_val,<br>
+                 nir_loop_variable *basic_ind)<br>
+{<br>
+   nir_foreach_block_in_cf_node(block, &state->loop->cf_node) {<br>
+      nir_foreach_instr(instr, block) {<br>
+         if (instr->type != nir_instr_type_intrinsic)<br>
+            continue;<br>
+<br>
+         nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);<br>
+<br>
+         /* Check for arrays variably-indexed by a loop induction variable. */<br>
+         if (intrin->intrinsic == nir_intrinsic_load_deref ||<br>
+             intrin->intrinsic == nir_intrinsic_store_deref ||<br>
+             intrin->intrinsic == nir_intrinsic_copy_deref) {<br>
+<br>
+            nir_loop_variable *array_idx = NULL;<br>
+            unsigned array_size =<br>
+               find_array_access_via_induction(state,<br>
+                                               nir_src_as_deref(intrin->src[0]),<br>
+                                               &array_idx);<br>
+            if (basic_ind == array_idx) {<br>
+               limit_val->i32[0] = array_size;<br>
+               return true;<br></blockquote><div><br></div><div>What if it's used for multiple array accesses of different lengths?  This just takes the first one.  It seems like we could be smarter.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+            }<br>
+<br>
+            if (intrin->intrinsic != nir_intrinsic_copy_deref)<br>
+               continue;<br>
+<br>
+            array_size =<br>
+               find_array_access_via_induction(state,<br>
+                                               nir_src_as_deref(intrin->src[1]),<br>
+                                               &array_idx);<br>
+            if (basic_ind == array_idx) {<br>
+               limit_val->i32[0] = array_size;<br>
+               return true;<br>
+            }<br>
+         }<br>
+      }<br>
+   }<br>
+<br>
+   return false;<br>
+}<br>
+<br>
 static int32_t<br>
 get_iteration(nir_op cond_op, nir_const_value *initial, nir_const_value *step,<br>
               nir_const_value *limit)<br>
@@ -558,6 +602,7 @@ static void<br>
 find_trip_count(loop_info_state *state)<br>
 {<br>
    bool trip_count_known = true;<br>
+   bool guessed_trip_count = false;<br>
    nir_loop_terminator *limiting_terminator = NULL;<br>
    int max_trip_count = -1;<br>
<br>
@@ -593,16 +638,33 @@ find_trip_count(loop_info_state *state)<br>
             basic_ind = get_loop_var(alu->src[1].src.ssa, state);<br>
             limit = get_loop_var(alu->src[0].src.ssa, state);<br>
             limit_rhs = false;<br>
+            terminator->induction_rhs = true;<br>
          }<br>
<br>
-         /* The comparison has to have a basic induction variable<br>
-          * and a constant for us to be able to find trip counts<br>
+         /* The comparison has to have a basic induction variable for us to be<br>
+          * able to find trip counts.<br>
           */<br>
-         if (basic_ind->type != basic_induction || !is_var_constant(limit)) {<br>
+         if (basic_ind->type != basic_induction) {<br>
             trip_count_known = false;<br>
             continue;<br>
          }<br>
<br>
+         /* Attempt to find a constant limit for the loop */<br>
+         nir_const_value limit_val;<br>
+         if (is_var_constant(limit)) {<br>
+            limit_val =<br>
+               nir_instr_as_load_const(limit->def->parent_instr)->value;<br>
+         } else {<br>
+            trip_count_known = false;<br>
+<br>
+            /* Guess loop limit based on array access */<br>
+            if (!guess_loop_limit(state, &limit_val, basic_ind)) {<br>
+               continue;<br>
+            }<br>
+<br>
+            guessed_trip_count = true;<br>
+         }<br>
+<br>
          /* We have determined that we have the following constants:<br>
           * (With the typical int i = 0; i < x; i++; as an example)<br>
           *    - Upper limit.<br>
@@ -619,9 +681,6 @@ find_trip_count(loop_info_state *state)<br>
             nir_instr_as_load_const(basic_ind->ind->invariant->def-><br>
                                        parent_instr)->value;<br>
<br>
-         nir_const_value limit_val =<br>
-            nir_instr_as_load_const(limit->def->parent_instr)->value;<br>
-<br>
          int iterations = calculate_iterations(&initial_val, &step_val,<br>
                                                &limit_val,<br>
                                                basic_ind->ind->alu_def, alu,<br>
@@ -631,6 +690,13 @@ find_trip_count(loop_info_state *state)<br>
          /* Where we not able to calculate the iteration count */<br>
          if (iterations == -1) {<br>
             trip_count_known = false;<br>
+            guessed_trip_count = false;<br>
+            continue;<br>
+         }<br>
+<br>
+         if (guessed_trip_count) {<br>
+            guessed_trip_count = false;<br></blockquote><div><br></div><div>This resetting confuses me.  Why not just make it local to the loop?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+            state->loop->info->guessed_trip_count = iterations;<br>
             continue;<br>
          }<br>
<br>
-- <br>
2.19.2<br>
<br>
_______________________________________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org" target="_blank">mesa-dev@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</blockquote></div></div>