glsl: don't demote tess control shader outputs
[mesa.git] / src / glsl / loop_controls.cpp
index a14ea6ba6be2f44d498a1a23243f0ec5050d90f3..51804bb5fe8563077fab5efe69326b0b9bca792d 100644 (file)
@@ -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,
@@ -183,52 +198,39 @@ loop_control_visitor::visit_leave(ir_loop *ir)
       return visit_continue;
    }
 
-   /* Figure out how many times the loop will run based on the iteration count
-    * annotations made by loop analysis, and give the loop a normative bound
-    * if possible.
-    */
-   unsigned max_iterations =
-      ls->max_iterations < 0 ? INT_MAX : ls->max_iterations;
-
-   if (ir->normative_bound >= 0)
-      max_iterations = ir->normative_bound;
-
-   /* If the limiting terminator has a lower iteration count than we'd
-    * previously inferred for this loop, then make the new iteration count the
-    * normative bound for this loop.
-    */
-   if (ls->limiting_terminator != NULL &&
-       (unsigned) ls->limiting_terminator->iterations < max_iterations) {
-      ir->normative_bound = ls->limiting_terminator->iterations;
-      max_iterations = ls->limiting_terminator->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;
+      }
    }
 
    /* Remove the conditional break statements associated with all terminators
-    * that are associated with a fixed iteration count; the normative bound
-    * will take care of terminating the loop.
+    * 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_list(node, &ls->terminators) {
-      loop_terminator *t = (loop_terminator *) node;
-
+   foreach_in_list(loop_terminator, t, &ls->terminators) {
       if (t->iterations < 0)
          continue;
 
-      t->ir->remove();
+      if (t != ls->limiting_terminator) {
+         t->ir->remove();
 
-      assert(ls->num_loop_jumps > 0);
-      ls->num_loop_jumps--;
+         assert(ls->num_loop_jumps > 0);
+         ls->num_loop_jumps--;
 
-      this->progress = true;
+         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;
 }