nir: calculate trip count for more loops
authorTimothy Arceri <tarceri@itsqueeze.com>
Tue, 20 Nov 2018 02:45:58 +0000 (13:45 +1100)
committerTimothy Arceri <tarceri@itsqueeze.com>
Tue, 12 Mar 2019 00:52:30 +0000 (00:52 +0000)
This adds support to loop analysis for loops where the induction
variable is compared to the result of min(variable, constant).

For example:

   for (int i = 0; i < imin(x, 4); i++)
      ...

We add a new bool to the loop terminator struct in order to
differentiate terminators with this exit condition.

Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/compiler/nir/nir.h
src/compiler/nir/nir_loop_analyze.c
src/compiler/nir/nir_opt_loop_unroll.c

index aac9ac448b88628d1b2454e17ffe49bc2a67850f..19e69c50f8f029636fa539105b40bf096475bd62 100644 (file)
@@ -1912,6 +1912,17 @@ typedef struct {
    bool continue_from_then;
    bool induction_rhs;
 
+   /* This is true if the terminators exact trip count is unknown. For
+    * example:
+    *
+    *    for (int i = 0; i < imin(x, 4); i++)
+    *       ...
+    *
+    * Here loop analysis would have set a max_trip_count of 4 however we dont
+    * know for sure that this is the exact trip count.
+    */
+   bool exact_trip_count_unknown;
+
    struct list_head loop_terminator_link;
 } nir_loop_terminator;
 
index 9cff670051ebf009c64594e91c16e68295440b6f..4c8028a666fac7469ca39f263e584402017f0120 100644 (file)
@@ -539,6 +539,35 @@ guess_loop_limit(loop_info_state *state, nir_const_value *limit_val,
    return false;
 }
 
+static bool
+try_find_limit_of_alu(nir_loop_variable *limit, nir_const_value *limit_val,
+                      nir_loop_terminator *terminator, loop_info_state *state)
+{
+   if(!is_var_alu(limit))
+      return false;
+
+   nir_alu_instr *limit_alu = nir_instr_as_alu(limit->def->parent_instr);
+
+   if (limit_alu->op == nir_op_imin ||
+       limit_alu->op == nir_op_fmin) {
+      limit = get_loop_var(limit_alu->src[0].src.ssa, state);
+
+      if (!is_var_constant(limit))
+         limit = get_loop_var(limit_alu->src[1].src.ssa, state);
+
+      if (!is_var_constant(limit))
+         return false;
+
+      *limit_val = nir_instr_as_load_const(limit->def->parent_instr)->value;
+
+      terminator->exact_trip_count_unknown = true;
+
+      return true;
+   }
+
+   return false;
+}
+
 static int32_t
 get_iteration(nir_op cond_op, nir_const_value *initial, nir_const_value *step,
               nir_const_value *limit)
@@ -770,12 +799,14 @@ find_trip_count(loop_info_state *state)
          } else {
             trip_count_known = false;
 
-            /* Guess loop limit based on array access */
-            if (!guess_loop_limit(state, &limit_val, basic_ind)) {
-               continue;
-            }
+            if (!try_find_limit_of_alu(limit, &limit_val, terminator, state)) {
+               /* Guess loop limit based on array access */
+               if (!guess_loop_limit(state, &limit_val, basic_ind)) {
+                  continue;
+               }
 
-            guessed_trip_count = true;
+               guessed_trip_count = true;
+            }
          }
 
          /* We have determined that we have the following constants:
index c700e6704dad7c1b31ea756651520decc2f48df5..a5a5ca3deeec5583048fdac1be3228b57270af02 100644 (file)
@@ -827,7 +827,8 @@ process_loops(nir_shader *sh, nir_cf_node *cf_node, bool *has_nested_loop_out)
       } else {
          /* Attempt to unroll loops with two terminators. */
          unsigned num_lt = list_length(&loop->info->loop_terminator_list);
-         if (num_lt == 2) {
+         if (num_lt == 2 &&
+             !loop->info->limiting_terminator->exact_trip_count_unknown) {
             bool limiting_term_second = true;
             nir_loop_terminator *terminator =
                list_first_entry(&loop->info->loop_terminator_list,