Mesa (shader-work): glsl/loop_analysis: fix miscompilation with continues before cond breaks
Luca Barbieri
lb at kemper.freedesktop.org
Tue Sep 14 02:30:47 UTC 2010
Module: Mesa
Branch: shader-work
Commit: 50d23201da0628f65a72278bc66e7c607064b983
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=50d23201da0628f65a72278bc66e7c607064b983
Author: Luca Barbieri <luca at luca-barbieri.com>
Date: Tue Sep 14 04:15:25 2010 +0200
glsl/loop_analysis: fix miscompilation with continues before cond breaks
In the following case, we currently incorrectly determine that the loop
has at most 8 iterations, while it is in fact an infinite loop.
for(;; ++i)
{
foo();
if(i >= 4) continue;
if(i < 8) break;
}
To fix this, stop looking for induction variable terminators if we hit
a continue, or a continue nested inside ifs.
---
src/glsl/loop_analysis.cpp | 40 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)
diff --git a/src/glsl/loop_analysis.cpp b/src/glsl/loop_analysis.cpp
index 91e34da..687825c 100644
--- a/src/glsl/loop_analysis.cpp
+++ b/src/glsl/loop_analysis.cpp
@@ -32,6 +32,37 @@ static bool all_expression_operands_are_loop_constant(ir_rvalue *,
static ir_rvalue *get_basic_induction_increment(ir_assignment *, hash_table *);
+struct contains_continue_visitor : public ir_hierarchical_visitor
+{
+ bool contains_continue;
+
+ contains_continue_visitor()
+ {
+ this->contains_continue = false;
+ }
+
+ virtual ir_visitor_status visit(ir_loop_jump *ir)
+ {
+ if(ir->is_continue()) {
+ contains_continue = true;
+ return visit_stop;
+ }
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_enter(class ir_loop *)
+ {
+ /* continues inside nested loops are harmless */
+ return visit_continue_with_parent;
+ }
+};
+
+bool contains_continue(ir_instruction* ir)
+{
+ contains_continue_visitor visitor;
+ ir->accept(&visitor);
+ return visitor.contains_continue;
+}
loop_state::loop_state()
{
@@ -212,6 +243,12 @@ loop_analysis::visit_leave(ir_loop *ir)
if (((ir_instruction *) node)->as_variable())
continue;
+ /* If we find a continue, we cannot go ahead, because
+ * the following instructions may never get executed
+ */
+ if(contains_continue((ir_instruction*) node))
+ break;
+
ir_if *if_stmt = ((ir_instruction *) node)->as_if();
if ((if_stmt != NULL) && is_loop_terminator(if_stmt))
@@ -464,6 +501,9 @@ get_basic_induction_increment(ir_assignment *ir, hash_table *var_hash)
* Detects if-statements of the form
*
* (if (expression bool ...) (break))
+ *
+ * NOTE: if we ever extend it to allow other instructions before the break, we
+ * need to return false if contains_continue() apply to any of those instructions.
*/
bool
is_loop_terminator(ir_if *ir)
More information about the mesa-commit
mailing list