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