summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Romanick <[email protected]>2016-02-18 18:08:58 -0800
committerIan Romanick <[email protected]>2016-02-24 18:43:40 -0800
commit9d9aeb91b13abf455c7d650d7f6583d8ec6c3895 (patch)
tree30d1e3cc41bcf4b4cd5ec59d900befb6c745eb8d
parent3eb476fa143f0c14d3e811ee6301ce7beb4e44f1 (diff)
glsl: Detect do-while-false loops and unroll them
Previously loops like do { // ... } while (false); that did not have any other loop-branch instructions would not be unrolled. This is commonly used to wrap multiline preprocessor macros. This produces IR like (loop ( ... break )) Since limiting_terminator was NULL, the loop unroller would throw up its hands and say, "I don't know how many iterations. How can I unroll this?" We can detect this another way. If there is no limiting_terminator and the only loop-branch is a break as the last IR, there's only one iteration. On my very old checkout of shader-db, this removes a loop from Orbital Explorer, but it does not otherwise affect the shader. The loop removed is the one the compiler inserts surrounding the switch statement. This change does prevent some seriously bad code generation in some patches to meta shaders that I recently sent out for review. Signed-off-by: Ian Romanick <[email protected]> Reviewed-by: Timothy Arceri <[email protected]>
-rw-r--r--src/compiler/glsl/loop_unroll.cpp30
1 files changed, 26 insertions, 4 deletions
diff --git a/src/compiler/glsl/loop_unroll.cpp b/src/compiler/glsl/loop_unroll.cpp
index aea2743cdb1..bc377dff3b9 100644
--- a/src/compiler/glsl/loop_unroll.cpp
+++ b/src/compiler/glsl/loop_unroll.cpp
@@ -315,11 +315,33 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
return visit_continue;
}
- /* Don't try to unroll loops where the number of iterations is not known
- * at compile-time.
- */
- if (ls->limiting_terminator == NULL)
+ if (ls->limiting_terminator == NULL) {
+ ir_instruction *last_ir =
+ (ir_instruction *) ir->body_instructions.get_tail();
+
+ /* If a loop has no induction variable and the last instruction is
+ * a break, unroll the loop with a count of 1. This is the classic
+ *
+ * do {
+ * // ...
+ * } while (false)
+ *
+ * that is used to wrap multi-line macros.
+ *
+ * If num_loop_jumps is not zero, last_ir cannot be NULL... there has to
+ * be at least num_loop_jumps instructions in the loop.
+ */
+ if (ls->num_loop_jumps == 1 && is_break(last_ir)) {
+ last_ir->remove();
+
+ simple_unroll(ir, 1);
+ }
+
+ /* Don't try to unroll loops where the number of iterations is not known
+ * at compile-time.
+ */
return visit_continue;
+ }
iterations = ls->limiting_terminator->iterations;