glsl: Remove integer matrix support from ir_dereference_array::constant_expression_value
[mesa.git] / src / compiler / glsl / loop_analysis.cpp
index 0fb6e9feb743dda471603af491555c7a13926ce6..9429e69c2a7fe4c7176bf60164bcb7e311336425 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;
@@ -107,7 +107,7 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
       return -1;
    }
 
-   if (!iter->type->is_integer()) {
+   if (!iter->type->is_integer_32()) {
       const ir_expression_operation op = iter->type->is_double()
          ? ir_unop_d2i : ir_unop_f2i;
       ir_rvalue *cast =
@@ -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;
 }
 
@@ -252,8 +283,7 @@ loop_variable::record_reference(bool in_assignee,
 
 loop_state::loop_state()
 {
-   this->ht = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
-                                      _mesa_key_pointer_equal);
+   this->ht = _mesa_pointer_hash_table_create(NULL);
    this->mem_ctx = ralloc_context(NULL);
    this->loop_found = false;
 }
@@ -289,6 +319,9 @@ loop_state::get(const ir_loop *ir)
 loop_variable *
 loop_variable_state::get(const ir_variable *ir)
 {
+   if (ir == NULL)
+      return NULL;
+
    hash_entry *entry = _mesa_hash_table_search(this->var_hash, ir);
    return entry ? (loop_variable *) entry->data : NULL;
 }
@@ -609,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 ||