glsl: check if induction var incremented before use in terminator
authorTimothy Arceri <tarceri@itsqueeze.com>
Thu, 21 Sep 2017 03:55:56 +0000 (13:55 +1000)
committerTimothy Arceri <tarceri@itsqueeze.com>
Mon, 9 Oct 2017 23:05:37 +0000 (10:05 +1100)
do-while loops can increment the starting value before the
condition is checked. e.g.

  do {
    ndx++;
  } while (ndx < 3);

This commit changes the code to detect this and reduces the
iteration count by 1 if found.

V2: fix terminator spelling

Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
Reviewed-by: Elie Tournier <elie.tournier@collabora.com>
Tested-by: Dieter Nützel <Dieter@nuetzel-hh.de>
src/compiler/glsl/loop_analysis.cpp

index 81a07f78f8f7532756a30de3e7986fb029d61040..78279844dc84609247e39eb7c452e44f414967d6 100644 (file)
@@ -171,6 +171,40 @@ calculate_iterations(ir_rvalue *from, ir_rvalue *to, ir_rvalue *increment,
    return (valid_loop) ? iter_value : -1;
 }
 
+static bool
+incremented_before_terminator(ir_loop *loop, ir_variable *var,
+                              ir_if *terminator)
+{
+   for (exec_node *node = loop->body_instructions.get_head();
+        !node->is_tail_sentinel();
+        node = node->get_next()) {
+      ir_instruction *ir = (ir_instruction *) node;
+
+      switch (ir->ir_type) {
+      case ir_type_if:
+         if (ir->as_if() == terminator)
+            return false;
+         break;
+
+      case ir_type_assignment: {
+         ir_assignment *assign = ir->as_assignment();
+         ir_variable *assignee = assign->lhs->whole_variable_referenced();
+
+         if (assignee == var) {
+            assert(assign->condition == NULL);
+            return true;
+         }
+
+         break;
+      }
+
+      default:
+         break;
+      }
+   }
+
+   unreachable("Unable to find induction variable");
+}
 
 /**
  * Record the fact that the given loop variable was referenced inside the loop.
@@ -582,6 +616,10 @@ loop_analysis::visit_leave(ir_loop *ir)
             t->iterations = calculate_iterations(init, limit, lv->increment,
                                                  cmp);
 
+            if (incremented_before_terminator(ir, var, t->ir)) {
+               t->iterations--;
+            }
+
             if (t->iterations >= 0 &&
                 (ls->limiting_terminator == NULL ||
                  t->iterations < ls->limiting_terminator->iterations)) {