summaryrefslogtreecommitdiffstats
path: root/src/glsl
diff options
context:
space:
mode:
authorMathias Fröhlich <[email protected]>2012-01-25 17:35:01 +0100
committerMathias Fröhlich <[email protected]>2012-02-09 21:23:16 +0100
commit67007080b716c7e51039a381f407ababd68230f7 (patch)
tree07726358e0b898b5558eb9b6bc0b997c0d96cd14 /src/glsl
parentea228d97f811092b9ffcb90565184a7a8f089477 (diff)
glsl: Avoid excessive loop unrolling.
Avoid unrollong loops that are either nested loops or where the loop body times the unroll count is huge. The change is far from being perfect but it extends the loop unrolling decision heuristic by some additional safeguard. In particular this cuts down compilation of a shader precomputing atmospheric scattering integral tables containing two nesting levels in a loop from something way beyond some minutes (I never waited for it to finish) to some fractions of a second. This fixes piglit tests glsl-fs-unroll-explosion and glsl-vs-unroll-explosion on r600g. Reviewed-by: Eric Anholt <[email protected]> Signed-off-by: Mathias Fröhlich <[email protected]>
Diffstat (limited to 'src/glsl')
-rw-r--r--src/glsl/loop_unroll.cpp15
1 files changed, 15 insertions, 0 deletions
diff --git a/src/glsl/loop_unroll.cpp b/src/glsl/loop_unroll.cpp
index 5b84e101477..d0bcaa6703d 100644
--- a/src/glsl/loop_unroll.cpp
+++ b/src/glsl/loop_unroll.cpp
@@ -56,6 +56,7 @@ 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.
@@ -78,6 +79,20 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
if (iterations > (int) max_iterations)
return visit_continue;
+ /* Don't try to unroll nested loops and loops with a huge body.
+ */
+ ir_count = 0;
+ foreach_list(node, &ir->body_instructions) {
+ ++ir_count;
+
+ /* If the loop body gets to huge, do not unroll. */
+ if (5*max_iterations < ir_count*iterations)
+ 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;
else if (ls->num_loop_jumps) {