diff options
Diffstat (limited to 'mesalib/src/glsl/loop_unroll.cpp')
-rw-r--r-- | mesalib/src/glsl/loop_unroll.cpp | 86 |
1 files changed, 74 insertions, 12 deletions
diff --git a/mesalib/src/glsl/loop_unroll.cpp b/mesalib/src/glsl/loop_unroll.cpp index 789655ebd..da532804a 100644 --- a/mesalib/src/glsl/loop_unroll.cpp +++ b/mesalib/src/glsl/loop_unroll.cpp @@ -25,15 +25,18 @@ #include "loop_analysis.h" #include "ir_hierarchical_visitor.h" +#include "main/mtypes.h" + namespace { class loop_unroll_visitor : public ir_hierarchical_visitor { public: - loop_unroll_visitor(loop_state *state, unsigned max_iterations) + loop_unroll_visitor(loop_state *state, + const struct gl_shader_compiler_options *options) { this->state = state; this->progress = false; - this->max_iterations = max_iterations; + this->options = options; } virtual ir_visitor_status visit_leave(ir_loop *ir); @@ -45,7 +48,7 @@ public: loop_state *state; bool progress; - unsigned max_iterations; + const struct gl_shader_compiler_options *options; }; } /* anonymous namespace */ @@ -60,12 +63,17 @@ is_break(ir_instruction *ir) class loop_unroll_count : public ir_hierarchical_visitor { public: int nodes; - bool fail; + bool unsupported_variable_indexing; + /* If there are nested loops, the node count will be inaccurate. */ + bool nested_loop; - loop_unroll_count(exec_list *list) + loop_unroll_count(exec_list *list, loop_variable_state *ls, + const struct gl_shader_compiler_options *options) + : ls(ls), options(options) { nodes = 0; - fail = false; + nested_loop = false; + unsupported_variable_indexing = false; run(list); } @@ -84,9 +92,57 @@ public: virtual ir_visitor_status visit_enter(ir_loop *) { - fail = true; + nested_loop = true; + return visit_continue; + } + + virtual ir_visitor_status visit_enter(ir_dereference_array *ir) + { + /* Check for arrays variably-indexed by a loop induction variable. + * Unrolling the loop may convert that access into constant-indexing. + * + * Many drivers don't support particular kinds of variable indexing, + * and have to resort to using lower_variable_index_to_cond_assign to + * handle it. This results in huge amounts of horrible code, so we'd + * like to avoid that if possible. Here, we just note that it will + * happen. + */ + if ((ir->array->type->is_array() || ir->array->type->is_matrix()) && + !ir->array_index->as_constant()) { + ir_variable *array = ir->array->variable_referenced(); + loop_variable *lv = ls->get(ir->array_index->variable_referenced()); + if (array && lv && lv->is_induction_var()) { + switch (array->data.mode) { + case ir_var_auto: + case ir_var_temporary: + case ir_var_const_in: + case ir_var_function_in: + case ir_var_function_out: + case ir_var_function_inout: + if (options->EmitNoIndirectTemp) + unsupported_variable_indexing = true; + break; + case ir_var_uniform: + if (options->EmitNoIndirectUniform) + unsupported_variable_indexing = true; + break; + case ir_var_shader_in: + if (options->EmitNoIndirectInput) + unsupported_variable_indexing = true; + break; + case ir_var_shader_out: + if (options->EmitNoIndirectOutput) + unsupported_variable_indexing = true; + break; + } + } + } return visit_continue; } + +private: + loop_variable_state *ls; + const struct gl_shader_compiler_options *options; }; @@ -244,16 +300,21 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) iterations = ls->limiting_terminator->iterations; + const int max_iterations = options->MaxUnrollIterations; + /* Don't try to unroll loops that have zillions of iterations either. */ - if (iterations > (int) max_iterations) + if (iterations > max_iterations) return visit_continue; /* Don't try to unroll nested loops and loops with a huge body. */ - loop_unroll_count count(&ir->body_instructions); + loop_unroll_count count(&ir->body_instructions, ls, options); + + bool loop_too_large = + count.nested_loop || count.nodes * iterations > max_iterations * 5; - if (count.fail || count.nodes * iterations > (int)max_iterations * 5) + if (loop_too_large && !count.unsupported_variable_indexing) return visit_continue; /* Note: the limiting terminator contributes 1 to ls->num_loop_jumps. @@ -338,9 +399,10 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) bool -unroll_loops(exec_list *instructions, loop_state *ls, unsigned max_iterations) +unroll_loops(exec_list *instructions, loop_state *ls, + const struct gl_shader_compiler_options *options) { - loop_unroll_visitor v(ls, max_iterations); + loop_unroll_visitor v(ls, options); v.run(instructions); |