glsl: Refine the loop instruction counting.

Before, we were only counting top-level instructions.  But if we have
an assignment of a giant expression tree (such as the ones eventually
generated by glsl-fs-unroll), we were counting the same as an
assignment of a variable deref.

glsl-fs-unroll-explosion now fails in a reasonable amount of time on
i965 because the unrolling didn't go ridiculously far.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
Eric Anholt 2012-02-21 13:37:49 -08:00
parent 7f1cbf12bc
commit be5f27a84d

View file

@ -50,13 +50,44 @@ is_break(ir_instruction *ir)
&& ((ir_loop_jump *) ir)->is_break();
}
class loop_unroll_count : public ir_hierarchical_visitor {
public:
int nodes;
bool fail;
loop_unroll_count(exec_list *list)
{
nodes = 0;
fail = false;
run(list);
}
virtual ir_visitor_status visit_enter(ir_assignment *ir)
{
nodes++;
return visit_continue;
}
virtual ir_visitor_status visit_enter(ir_expression *ir)
{
nodes++;
return visit_continue;
}
virtual ir_visitor_status visit_enter(ir_loop *ir)
{
fail = true;
return visit_continue;
}
};
ir_visitor_status
loop_unroll_visitor::visit_leave(ir_loop *ir)
{
loop_variable_state *const ls = this->state->get(ir);
int iterations;
unsigned ir_count;
/* If we've entered a loop that hasn't been analyzed, something really,
* really bad has happened.
@ -81,17 +112,10 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
/* Don't try to unroll nested loops and loops with a huge body.
*/
ir_count = 0;
foreach_list(node, &ir->body_instructions) {
++ir_count;
loop_unroll_count count(&ir->body_instructions);
/* If the loop body gets to huge, do not unroll. */
if (5*max_iterations < ir_count*iterations)
if (count.fail || count.nodes * iterations > (int)max_iterations * 5)
return visit_continue;
/* Do not unroll loops with child loop nodes. */
if (((ir_instruction *) node)->as_loop())
return visit_continue;
}
if (ls->num_loop_jumps > 1)
return visit_continue;