Merge remote-tracking branch 'mesa-public/master' into vulkan
[mesa.git] / src / glsl / loop_unroll.cpp
index da532804a4a07d52ac3fd61285f3d935ad78633a..b9ea35077828335b90ce5f9dc26ca34b44a361fc 100644 (file)
@@ -64,6 +64,7 @@ class loop_unroll_count : public ir_hierarchical_visitor {
 public:
    int nodes;
    bool unsupported_variable_indexing;
+   bool array_indexed_by_induction_var_with_exact_iterations;
    /* If there are nested loops, the node count will be inaccurate. */
    bool nested_loop;
 
@@ -74,6 +75,7 @@ public:
       nodes = 0;
       nested_loop = false;
       unsupported_variable_indexing = false;
+      array_indexed_by_induction_var_with_exact_iterations = false;
 
       run(list);
    }
@@ -98,6 +100,18 @@ public:
 
    virtual ir_visitor_status visit_enter(ir_dereference_array *ir)
    {
+      /* Force unroll in case of dynamic indexing with sampler arrays
+       * when EmitNoIndirectSampler is set.
+       */
+      if (options->EmitNoIndirectSampler) {
+         if ((ir->array->type->is_array() &&
+              ir->array->type->contains_sampler()) &&
+             !ir->array_index->constant_expression_value()) {
+            unsupported_variable_indexing = true;
+            return visit_continue;
+         }
+      }
+
       /* Check for arrays variably-indexed by a loop induction variable.
        * Unrolling the loop may convert that access into constant-indexing.
        *
@@ -112,6 +126,14 @@ public:
          ir_variable *array = ir->array->variable_referenced();
          loop_variable *lv = ls->get(ir->array_index->variable_referenced());
          if (array && lv && lv->is_induction_var()) {
+            /* If an array is indexed by a loop induction variable, and the
+             * array size is exactly the number of loop iterations, this is
+             * probably a simple for-loop trying to access each element in
+             * turn; the application may expect it to be unrolled.
+             */
+            if (int(array->type->length) == ls->limiting_terminator->iterations)
+               array_indexed_by_induction_var_with_exact_iterations = true;
+
             switch (array->data.mode) {
             case ir_var_auto:
             case ir_var_temporary:
@@ -123,6 +145,7 @@ public:
                   unsupported_variable_indexing = true;
                break;
             case ir_var_uniform:
+            case ir_var_shader_storage:
                if (options->EmitNoIndirectUniform)
                   unsupported_variable_indexing = true;
                break;
@@ -314,7 +337,8 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
    bool loop_too_large =
       count.nested_loop || count.nodes * iterations > max_iterations * 5;
 
-   if (loop_too_large && !count.unsupported_variable_indexing)
+   if (loop_too_large && !count.unsupported_variable_indexing &&
+       !count.array_indexed_by_induction_var_with_exact_iterations)
       return visit_continue;
 
    /* Note: the limiting terminator contributes 1 to ls->num_loop_jumps.
@@ -347,10 +371,8 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
       return visit_continue;
    }
 
-   foreach_list(node, &ir->body_instructions) {
-      /* recognize loops in the form produced by ir_lower_jumps */
-      ir_instruction *cur_ir = (ir_instruction *) node;
-
+   /* recognize loops in the form produced by ir_lower_jumps */
+   foreach_in_list(ir_instruction, cur_ir, &ir->body_instructions) {
       /* Skip the limiting terminator, since it will go away when we
        * unroll.
        */