diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/glsl/loop_analysis.h | 9 | ||||
-rw-r--r-- | src/glsl/loop_controls.cpp | 25 | ||||
-rw-r--r-- | src/glsl/loop_unroll.cpp | 27 |
3 files changed, 41 insertions, 20 deletions
diff --git a/src/glsl/loop_analysis.h b/src/glsl/loop_analysis.h index ae980567c06..6799f876cd7 100644 --- a/src/glsl/loop_analysis.h +++ b/src/glsl/loop_analysis.h @@ -39,15 +39,12 @@ analyze_loop_variables(exec_list *instructions); /** * Fill in loop control fields * - * Based on analysis of loop variables, this function tries to remove sequences - * in the loop of the form + * Based on analysis of loop variables, this function tries to remove + * redundant sequences in the loop of the form * * (if (expression bool ...) (break)) * - * and fill in the \c normative_bound field of the \c ir_loop. - * - * In this process, some conditional break-statements may be eliminated - * altogether. For example, if it is provable that one loop exit condition will + * For example, if it is provable that one loop exit condition will * always be satisfied before another, the unnecessary exit condition will be * removed. */ diff --git a/src/glsl/loop_controls.cpp b/src/glsl/loop_controls.cpp index 9e32ff5d5fa..385c2031c42 100644 --- a/src/glsl/loop_controls.cpp +++ b/src/glsl/loop_controls.cpp @@ -195,16 +195,19 @@ loop_control_visitor::visit_leave(ir_loop *ir) } /* If the limiting terminator has a lower iteration count than the - * normative loop bound (if any), then make this a normatively bounded - * loop with the new iteration count. + * normative loop bound (if any), then the loop doesn't need a normative + * bound anymore. */ - if (ir->normative_bound < 0 || iterations < ir->normative_bound) - ir->normative_bound = iterations; + if (ir->normative_bound >= 0 && iterations < ir->normative_bound) + ir->normative_bound = -1; } /* Remove the conditional break statements associated with all terminators - * that are associated with a fixed iteration count; the normative bound - * will take care of terminating the loop. + * that are associated with a fixed iteration count, except for the one + * associated with the limiting terminator--that one needs to stay, since + * it terminates the loop. Exception: if the loop still has a normative + * bound, then that terminates the loop, so we don't even need the limiting + * terminator. */ foreach_list(node, &ls->terminators) { loop_terminator *t = (loop_terminator *) node; @@ -212,12 +215,14 @@ loop_control_visitor::visit_leave(ir_loop *ir) if (t->iterations < 0) continue; - t->ir->remove(); + if (ir->normative_bound >= 0 || t != ls->limiting_terminator) { + t->ir->remove(); - assert(ls->num_loop_jumps > 0); - ls->num_loop_jumps--; + assert(ls->num_loop_jumps > 0); + ls->num_loop_jumps--; - this->progress = true; + this->progress = true; + } } return visit_continue; diff --git a/src/glsl/loop_unroll.cpp b/src/glsl/loop_unroll.cpp index 9472bc5a510..4645dcbab19 100644 --- a/src/glsl/loop_unroll.cpp +++ b/src/glsl/loop_unroll.cpp @@ -228,6 +228,9 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) loop_variable_state *const ls = this->state->get(ir); int iterations; + /* Note: normatively-bounded loops aren't created anymore. */ + assert(ir->normative_bound < 0); + /* If we've entered a loop that hasn't been analyzed, something really, * really bad has happened. */ @@ -239,10 +242,10 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) /* Don't try to unroll loops where the number of iterations is not known * at compile-time. */ - if (ir->normative_bound < 0) + if (ls->limiting_terminator == NULL) return visit_continue; - iterations = ir->normative_bound; + iterations = ls->limiting_terminator->iterations; /* Don't try to unroll loops that have zillions of iterations either. */ @@ -256,10 +259,17 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) if (count.fail || count.nodes * iterations > (int)max_iterations * 5) return visit_continue; - if (ls->num_loop_jumps > 1) + /* Note: the limiting terminator contributes 1 to ls->num_loop_jumps. + * We'll be removing the limiting terminator before we unroll. + */ + assert(ls->num_loop_jumps > 0); + unsigned predicted_num_loop_jumps = ls->num_loop_jumps - 1; + + if (predicted_num_loop_jumps > 1) return visit_continue; - if (ls->num_loop_jumps == 0) { + if (predicted_num_loop_jumps == 0) { + ls->limiting_terminator->ir->remove(); simple_unroll(ir, iterations); return visit_continue; } @@ -274,6 +284,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) */ last_ir->remove(); + ls->limiting_terminator->ir->remove(); simple_unroll(ir, 1); return visit_continue; } @@ -282,6 +293,12 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) /* recognize loops in the form produced by ir_lower_jumps */ ir_instruction *cur_ir = (ir_instruction *) node; + /* Skip the limiting terminator, since it will go away when we + * unroll. + */ + if (cur_ir == ls->limiting_terminator->ir) + continue; + ir_if *ir_if = cur_ir->as_if(); if (ir_if != NULL) { /* Determine which if-statement branch, if any, ends with a @@ -296,6 +313,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) (ir_instruction *) ir_if->then_instructions.get_tail(); if (is_break(ir_if_last)) { + ls->limiting_terminator->ir->remove(); splice_post_if_instructions(ir_if, &ir_if->else_instructions); ir_if_last->remove(); complex_unroll(ir, iterations, false); @@ -305,6 +323,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) (ir_instruction *) ir_if->else_instructions.get_tail(); if (is_break(ir_if_last)) { + ls->limiting_terminator->ir->remove(); splice_post_if_instructions(ir_if, &ir_if->then_instructions); ir_if_last->remove(); complex_unroll(ir, iterations, true); |