Mesa (master): glsl: Fix unroll of do{} while(false) like loops

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Sep 6 10:56:35 UTC 2019


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

Author: Danylo Piliaiev <danylo.piliaiev at globallogic.com>
Date:   Thu Aug 22 13:32:50 2019 +0300

glsl: Fix unroll of do{} while(false) like loops

For loops which condition is false on the first iteration
iteration count was falsely calculated under the assumption
that loop's condition is true until it becomes false, meaning
it's true at least one time.
Now such loops are reported as having 0 iteration.

Similar to the fix e71fc7f2 done in NIR.

Fixes tests/shaders/glsl-fs-loop-while-false-02.shader_test

Signed-off-by: Danylo Piliaiev <danylo.piliaiev at globallogic.com>
Reviewed-by: Timothy Arceri <tarceri at itsqueeze.com>

---

 src/compiler/glsl/loop_analysis.cpp | 43 +++++++++++++++++++++++++++++++------
 src/compiler/glsl/loop_unroll.cpp   | 15 ++++---------
 2 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/src/compiler/glsl/loop_analysis.cpp b/src/compiler/glsl/loop_analysis.cpp
index aae8fc62cd0..9429e69c2a7 100644
--- a/src/compiler/glsl/loop_analysis.cpp
+++ b/src/compiler/glsl/loop_analysis.cpp
@@ -88,7 +88,7 @@ find_initial_value(ir_loop *loop, ir_variable *var)
 static int
 calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
                      enum ir_expression_operation op, bool continue_from_then,
-                     bool swap_compare_operands)
+                     bool swap_compare_operands, bool inc_before_terminator)
 {
    if (from == NULL || to == NULL || increment == NULL)
       return -1;
@@ -118,6 +118,32 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
 
    int iter_value = iter->get_int_component(0);
 
+   /* Code after this block works under assumption that iterator will be
+    * incremented or decremented until it hits the limit,
+    * however the loop condition can be false on the first iteration.
+    * Handle such loops first.
+    */
+   {
+      ir_rvalue *first_value = from;
+      if (inc_before_terminator) {
+         first_value =
+            new(mem_ctx) ir_expression(ir_binop_add, from->type, from, increment);
+      }
+
+      ir_expression *cmp = swap_compare_operands
+            ? new(mem_ctx) ir_expression(op, glsl_type::bool_type, to, first_value)
+            : new(mem_ctx) ir_expression(op, glsl_type::bool_type, first_value, to);
+      if (continue_from_then)
+         cmp = new(mem_ctx) ir_expression(ir_unop_logic_not, cmp);
+
+      ir_constant *const cmp_result = cmp->constant_expression_value(mem_ctx);
+      assert(cmp_result != NULL);
+      if (cmp_result->get_bool_component(0)) {
+         ralloc_free(mem_ctx);
+         return 0;
+      }
+   }
+
    /* Make sure that the calculated number of iterations satisfies the exit
     * condition.  This is needed to catch off-by-one errors and some types of
     * ill-formed loops.  For example, we need to detect that the following
@@ -172,6 +198,11 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
    }
 
    ralloc_free(mem_ctx);
+
+   if (inc_before_terminator) {
+      iter_value--;
+   }
+
    return (valid_loop) ? iter_value : -1;
 }
 
@@ -611,13 +642,13 @@ loop_analysis::visit_leave(ir_loop *ir)
 
          loop_variable *lv = ls->get(var);
          if (lv != NULL && lv->is_induction_var()) {
+            bool inc_before_terminator =
+               incremented_before_terminator(ir, var, t->ir);
+
             t->iterations = calculate_iterations(init, limit, lv->increment,
                                                  cmp, t->continue_from_then,
-                                                 swap_compare_operands);
-
-            if (incremented_before_terminator(ir, var, t->ir)) {
-               t->iterations--;
-            }
+                                                 swap_compare_operands,
+                                                 inc_before_terminator);
 
             if (t->iterations >= 0 &&
                 (ls->limiting_terminator == NULL ||
diff --git a/src/compiler/glsl/loop_unroll.cpp b/src/compiler/glsl/loop_unroll.cpp
index 7e97c3cddf1..1a9229acc34 100644
--- a/src/compiler/glsl/loop_unroll.cpp
+++ b/src/compiler/glsl/loop_unroll.cpp
@@ -390,17 +390,10 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
       return visit_continue;
    }
 
-   if (ls->limiting_terminator != NULL) {
-      /* If the limiting terminator has an iteration count of zero, then we've
-       * proven that the loop cannot run, so delete it.
-       */
-      int iterations = ls->limiting_terminator->iterations;
-      if (iterations == 0) {
-         ir->remove();
-         this->progress = true;
-         return visit_continue;
-      }
-   }
+   /* Limiting terminator may have iteration count of zero,
+    * this is a valid case because the loop may break during
+    * the first iteration.
+    */
 
    /* Remove the conditional break statements associated with all terminators
     * that are associated with a fixed iteration count, except for the one




More information about the mesa-commit mailing list