glsl: Handle 16-bit types in loop analysis
[mesa.git] / src / compiler / glsl / loop_analysis.cpp
index aae8fc62cd06537e5774b3b944a38fa09533aec3..6f0b3287a5b17599eef2937842b4998516a2e14f 100644 (file)
@@ -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
@@ -135,12 +161,21 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
       case GLSL_TYPE_INT:
          iter = new(mem_ctx) ir_constant(iter_value + bias[i]);
          break;
+      case GLSL_TYPE_INT16:
+         iter = new(mem_ctx) ir_constant(uint16_t(iter_value + bias[i]));
+         break;
       case GLSL_TYPE_UINT:
          iter = new(mem_ctx) ir_constant(unsigned(iter_value + bias[i]));
          break;
+      case GLSL_TYPE_UINT16:
+         iter = new(mem_ctx) ir_constant(uint16_t(iter_value + bias[i]));
+         break;
       case GLSL_TYPE_FLOAT:
          iter = new(mem_ctx) ir_constant(float(iter_value + bias[i]));
          break;
+      case GLSL_TYPE_FLOAT16:
+         iter = new(mem_ctx) ir_constant(float16_t(float(iter_value + bias[i])));
+         break;
       case GLSL_TYPE_DOUBLE:
          iter = new(mem_ctx) ir_constant(double(iter_value + bias[i]));
          break;
@@ -172,6 +207,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 +651,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 ||