Merge remote-tracking branch 'mesa-public/master' into vulkan
[mesa.git] / src / glsl / loop_controls.cpp
index b528810f40d928a41b1e29688e6e04874b7f20a2..51804bb5fe8563077fab5efe69326b0b9bca792d 100644 (file)
@@ -21,7 +21,7 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include <climits>
+#include <limits.h>
 #include "main/compiler.h"
 #include "glsl_types.h"
 #include "loop_analysis.h"
@@ -88,7 +88,7 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
    if (from == NULL || to == NULL || increment == NULL)
       return -1;
 
-   void *mem_ctx = talloc_init("%s", __func__);
+   void *mem_ctx = ralloc_context(NULL);
 
    ir_expression *const sub =
       new(mem_ctx) ir_expression(ir_binop_sub, from->type, to, from);
@@ -102,9 +102,10 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
       return -1;
 
    if (!iter->type->is_integer()) {
+      const ir_expression_operation op = iter->type->is_double()
+         ? ir_unop_d2i : ir_unop_f2i;
       ir_rvalue *cast =
-        new(mem_ctx) ir_expression(ir_unop_f2i, glsl_type::int_type, iter,
-                                   NULL);
+         new(mem_ctx) ir_expression(op, glsl_type::int_type, iter, NULL);
 
       iter = cast->constant_expression_value();
    }
@@ -122,10 +123,24 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
    const int bias[] = { -1, 0, 1 };
    bool valid_loop = false;
 
-   for (unsigned i = 0; i < Elements(bias); i++) {
-      iter = (increment->type->is_integer())
-        ? new(mem_ctx) ir_constant(iter_value + bias[i])
-        : new(mem_ctx) ir_constant(float(iter_value + bias[i]));
+   for (unsigned i = 0; i < ARRAY_SIZE(bias); i++) {
+      /* Increment may be of type int, uint or float. */
+      switch (increment->type->base_type) {
+      case GLSL_TYPE_INT:
+         iter = new(mem_ctx) ir_constant(iter_value + bias[i]);
+         break;
+      case GLSL_TYPE_UINT:
+         iter = new(mem_ctx) ir_constant(unsigned(iter_value + bias[i]));
+         break;
+      case GLSL_TYPE_FLOAT:
+         iter = new(mem_ctx) ir_constant(float(iter_value + bias[i]));
+         break;
+      case GLSL_TYPE_DOUBLE:
+         iter = new(mem_ctx) ir_constant(double(iter_value + bias[i]));
+         break;
+      default:
+          unreachable("Unsupported type for loop iterator.");
+      }
 
       ir_expression *const mul =
         new(mem_ctx) ir_expression(ir_binop_mul, increment->type, iter,
@@ -147,10 +162,11 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
       }
    }
 
-   talloc_free(mem_ctx);
+   ralloc_free(mem_ctx);
    return (valid_loop) ? iter_value : -1;
 }
 
+namespace {
 
 class loop_control_visitor : public ir_hierarchical_visitor {
 public:
@@ -167,6 +183,7 @@ public:
    bool progress;
 };
 
+} /* anonymous namespace */
 
 ir_visitor_status
 loop_control_visitor::visit_leave(ir_loop *ir)
@@ -181,114 +198,39 @@ loop_control_visitor::visit_leave(ir_loop *ir)
       return visit_continue;
    }
 
-   /* Search the loop terminating conditions for one of the form 'i < c' where
-    * i is a loop induction variable, c is a constant, and < is any relative
-    * operator.
-    */
-   int max_iterations = ls->max_iterations;
+   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;
+      }
+   }
 
-   if(ir->from && ir->to && ir->increment)
-      max_iterations = calculate_iterations(ir->from, ir->to, ir->increment, (ir_expression_operation)ir->cmp);
+   /* Remove the conditional break statements associated with all terminators
+    * that are associated with a fixed iteration count, except for the one
+    * associated with the limiting terminator--that one needs to stay, since
+    * it terminates the loop.  Exception: if the loop still has a normative
+    * bound, then that terminates the loop, so we don't even need the limiting
+    * terminator.
+    */
+   foreach_in_list(loop_terminator, t, &ls->terminators) {
+      if (t->iterations < 0)
+         continue;
 
-   if(max_iterations < 0)
-      max_iterations = INT_MAX;
+      if (t != ls->limiting_terminator) {
+         t->ir->remove();
 
-   foreach_list(node, &ls->terminators) {
-      loop_terminator *t = (loop_terminator *) node;
-      ir_if *if_stmt = t->ir;
+         assert(ls->num_loop_jumps > 0);
+         ls->num_loop_jumps--;
 
-      /* If-statements can be either 'if (expr)' or 'if (deref)'.  We only care
-       * about the former here.
-       */
-      ir_expression *cond = if_stmt->condition->as_expression();
-      if (cond == NULL)
-        continue;
-
-      switch (cond->operation) {
-      case ir_binop_less:
-      case ir_binop_greater:
-      case ir_binop_lequal:
-      case ir_binop_gequal: {
-        /* The expressions that we care about will either be of the form
-         * 'counter < limit' or 'limit < counter'.  Figure out which is
-         * which.
-         */
-        ir_rvalue *counter = cond->operands[0]->as_dereference_variable();
-        ir_constant *limit = cond->operands[1]->as_constant();
-        enum ir_expression_operation cmp = cond->operation;
-
-        if (limit == NULL) {
-           counter = cond->operands[1]->as_dereference_variable();
-           limit = cond->operands[0]->as_constant();
-
-           switch (cmp) {
-           case ir_binop_less:    cmp = ir_binop_gequal;  break;
-           case ir_binop_greater: cmp = ir_binop_lequal;  break;
-           case ir_binop_lequal:  cmp = ir_binop_greater; break;
-           case ir_binop_gequal:  cmp = ir_binop_less;    break;
-           default: assert(!"Should not get here.");
-           }
-        }
-
-        if ((counter == NULL) || (limit == NULL))
-           break;
-
-        ir_variable *var = counter->variable_referenced();
-
-        ir_rvalue *init = find_initial_value(ir, var);
-
-        foreach_list(iv_node, &ls->induction_variables) {
-           loop_variable *lv = (loop_variable *) iv_node;
-
-           if (lv->var == var) {
-              const int iterations = calculate_iterations(init, limit,
-                                                          lv->increment,
-                                                          cmp);
-              if (iterations >= 0) {
-                 /* If the new iteration count is lower than the previously
-                  * believed iteration count, update the loop control values.
-                  */
-                 if (iterations < max_iterations) {
-                    ir->from = init->clone(ir, NULL);
-                    ir->to = limit->clone(ir, NULL);
-                    ir->increment = lv->increment->clone(ir, NULL);
-                    ir->counter = lv->var;
-                    ir->cmp = cmp;
-
-                    max_iterations = iterations;
-                 }
-
-                 /* Remove the conditional break statement.  The loop
-                  * controls are now set such that the exit condition will be
-                  * satisfied.
-                  */
-                 if_stmt->remove();
-
-                 assert(ls->num_loop_jumps > 0);
-                 ls->num_loop_jumps--;
-
-                 this->progress = true;
-              }
-
-              break;
-           }
-        }
-        break;
-      }
-
-      default:
-        break;
+         this->progress = true;
       }
    }
 
-   /* If we have proven the one of the loop exit conditions is satisifed before
-    * running the loop once, remove the loop.
-    */
-   if (max_iterations == 0)
-      ir->remove();
-   else
-      ls->max_iterations = max_iterations;
-
    return visit_continue;
 }