summaryrefslogtreecommitdiff
path: root/lib/mesa/src/compiler/glsl/loop_unroll.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mesa/src/compiler/glsl/loop_unroll.cpp')
-rw-r--r--lib/mesa/src/compiler/glsl/loop_unroll.cpp264
1 files changed, 53 insertions, 211 deletions
diff --git a/lib/mesa/src/compiler/glsl/loop_unroll.cpp b/lib/mesa/src/compiler/glsl/loop_unroll.cpp
index 04b8b4f49..aea2743cd 100644
--- a/lib/mesa/src/compiler/glsl/loop_unroll.cpp
+++ b/lib/mesa/src/compiler/glsl/loop_unroll.cpp
@@ -24,7 +24,8 @@
#include "compiler/glsl_types.h"
#include "loop_analysis.h"
#include "ir_hierarchical_visitor.h"
-#include "main/consts_exts.h"
+
+#include "main/mtypes.h"
namespace {
@@ -41,9 +42,7 @@ public:
virtual ir_visitor_status visit_leave(ir_loop *ir);
void simple_unroll(ir_loop *ir, int iterations);
void complex_unroll(ir_loop *ir, int iterations,
- bool continue_from_then_branch,
- bool limiting_term_first,
- bool lt_continue_from_then_branch);
+ bool continue_from_then_branch);
void splice_post_if_instructions(ir_if *ir_if, exec_list *splice_dest);
loop_state *state;
@@ -54,6 +53,13 @@ public:
} /* anonymous namespace */
+static bool
+is_break(ir_instruction *ir)
+{
+ return ir != NULL && ir->ir_type == ir_type_loop_jump
+ && ((ir_loop_jump *) ir)->is_break();
+}
+
class loop_unroll_count : public ir_hierarchical_visitor {
public:
int nodes;
@@ -100,7 +106,7 @@ public:
if (options->EmitNoIndirectSampler) {
if ((ir->array->type->is_array() &&
ir->array->type->contains_sampler()) &&
- !ir->array_index->constant_expression_value(ralloc_parent(ir))) {
+ !ir->array_index->constant_expression_value()) {
unsupported_variable_indexing = true;
return visit_continue;
}
@@ -177,57 +183,6 @@ void
loop_unroll_visitor::simple_unroll(ir_loop *ir, int iterations)
{
void *const mem_ctx = ralloc_parent(ir);
- loop_variable_state *const ls = this->state->get(ir);
-
- /* If there are no terminators, then the loop iteration count must be 1.
- * This is the 'do { } while (false);' case.
- */
- assert(!ls->terminators.is_empty() || iterations == 1);
-
- ir_instruction *first_ir =
- (ir_instruction *) ir->body_instructions.get_head();
-
- if (!first_ir) {
- /* The loop is empty remove it and return */
- ir->remove();
- return;
- }
-
- ir_if *limit_if = NULL;
- bool exit_branch_has_instructions = false;
- if (ls->limiting_terminator) {
- limit_if = ls->limiting_terminator->ir;
- ir_instruction *ir_if_last = (ir_instruction *)
- limit_if->then_instructions.get_tail();
-
- if (is_break(ir_if_last)) {
- if (ir_if_last != limit_if->then_instructions.get_head())
- exit_branch_has_instructions = true;
-
- splice_post_if_instructions(limit_if, &limit_if->else_instructions);
- ir_if_last->remove();
- } else {
- ir_if_last = (ir_instruction *)
- limit_if->else_instructions.get_tail();
- assert(is_break(ir_if_last));
-
- if (ir_if_last != limit_if->else_instructions.get_head())
- exit_branch_has_instructions = true;
-
- splice_post_if_instructions(limit_if, &limit_if->then_instructions);
- ir_if_last->remove();
- }
- }
-
- /* Because 'iterations' is the number of times we pass over the *entire*
- * loop body before hitting the first break, we need to bump the number of
- * iterations if the limiting terminator is not the first instruction in
- * the loop, or it the exit branch contains instructions. This ensures we
- * execute any instructions before the terminator or in its exit branch.
- */
- if (!ls->terminators.is_empty() &&
- (limit_if != first_ir->as_if() || exit_branch_has_instructions))
- iterations++;
for (int i = 0; i < iterations; i++) {
exec_list copy_list;
@@ -279,22 +234,11 @@ loop_unroll_visitor::simple_unroll(ir_loop *ir, int iterations)
*/
void
loop_unroll_visitor::complex_unroll(ir_loop *ir, int iterations,
- bool second_term_then_continue,
- bool extra_iteration_required,
- bool first_term_then_continue)
+ bool continue_from_then_branch)
{
void *const mem_ctx = ralloc_parent(ir);
ir_instruction *ir_to_replace = ir;
- /* Because 'iterations' is the number of times we pass over the *entire*
- * loop body before hitting the first break, we need to bump the number of
- * iterations if the limiting terminator is not the first instruction in
- * the loop, or it the exit branch contains instructions. This ensures we
- * execute any instructions before the terminator or in its exit branch.
- */
- if (extra_iteration_required)
- iterations++;
-
for (int i = 0; i < iterations; i++) {
exec_list copy_list;
@@ -304,10 +248,6 @@ loop_unroll_visitor::complex_unroll(ir_loop *ir, int iterations,
ir_if *ir_if = ((ir_instruction *) copy_list.get_tail())->as_if();
assert(ir_if != NULL);
- exec_list *const first_list = first_term_then_continue
- ? &ir_if->then_instructions : &ir_if->else_instructions;
- ir_if = ((ir_instruction *) first_list->get_tail())->as_if();
-
ir_to_replace->insert_before(&copy_list);
ir_to_replace->remove();
@@ -315,10 +255,10 @@ loop_unroll_visitor::complex_unroll(ir_loop *ir, int iterations,
ir_to_replace =
new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_continue);
- exec_list *const second_term_continue_list = second_term_then_continue
+ exec_list *const list = (continue_from_then_branch)
? &ir_if->then_instructions : &ir_if->else_instructions;
- second_term_continue_list->push_tail(ir_to_replace);
+ list->push_tail(ir_to_replace);
}
ir_to_replace->remove();
@@ -360,26 +300,12 @@ loop_unroll_visitor::splice_post_if_instructions(ir_if *ir_if,
}
}
-static bool
-exit_branch_has_instructions(ir_if *term_if, bool lt_then_continue)
-{
- if (lt_then_continue) {
- if (term_if->else_instructions.get_head() ==
- term_if->else_instructions.get_tail())
- return false;
- } else {
- if (term_if->then_instructions.get_head() ==
- term_if->then_instructions.get_tail())
- return false;
- }
-
- return true;
-}
ir_visitor_status
loop_unroll_visitor::visit_leave(ir_loop *ir)
{
loop_variable_state *const ls = this->state->get(ir);
+ int iterations;
/* If we've entered a loop that hasn't been analyzed, something really,
* really bad has happened.
@@ -389,80 +315,13 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
return visit_continue;
}
- /* Limiting terminator may have iteration count of zero,
- * this is a valid case because the loop may break during
- * the first iteration.
- */
-
- /* Remove the conditional break statements associated with all terminators
- * 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.
+ /* Don't try to unroll loops where the number of iterations is not known
+ * at compile-time.
*/
- foreach_in_list_safe(loop_terminator, t, &ls->terminators) {
- if (t->iterations < 0)
- continue;
-
- exec_list *branch_instructions;
- if (t != ls->limiting_terminator) {
- ir_instruction *ir_if_last = (ir_instruction *)
- t->ir->then_instructions.get_tail();
- if (is_break(ir_if_last)) {
- branch_instructions = &t->ir->else_instructions;
- } else {
- branch_instructions = &t->ir->then_instructions;
- assert(is_break((ir_instruction *)
- t->ir->else_instructions.get_tail()));
- }
-
- exec_list copy_list;
- copy_list.make_empty();
- clone_ir_list(ir, &copy_list, branch_instructions);
-
- t->ir->insert_before(&copy_list);
- t->ir->remove();
-
- assert(ls->num_loop_jumps > 0);
- ls->num_loop_jumps--;
-
- /* Also remove it from the terminator list */
- t->remove();
-
- this->progress = true;
- }
- }
-
- 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.
- */
+ if (ls->limiting_terminator == NULL)
return visit_continue;
- }
- int iterations = ls->limiting_terminator->iterations;
+ iterations = ls->limiting_terminator->iterations;
const int max_iterations = options->MaxUnrollIterations;
@@ -492,6 +351,7 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
return visit_continue;
if (predicted_num_loop_jumps == 0) {
+ ls->limiting_terminator->ir->remove();
simple_unroll(ir, iterations);
return visit_continue;
}
@@ -506,69 +366,51 @@ loop_unroll_visitor::visit_leave(ir_loop *ir)
*/
last_ir->remove();
+ ls->limiting_terminator->ir->remove();
simple_unroll(ir, 1);
return visit_continue;
}
- /* Complex unrolling can only handle two terminators. One with an unknown
- * iteration count and one with a known iteration count. We have already
- * made sure we have a known iteration count above and removed any
- * unreachable terminators with a known count. Here we make sure there
- * isn't any additional unknown terminators, or any other jumps nested
- * inside futher ifs.
- */
- if (ls->num_loop_jumps != 2 || ls->terminators.length() != 2)
- return visit_continue;
-
- ir_instruction *first_ir =
- (ir_instruction *) ir->body_instructions.get_head();
-
- unsigned term_count = 0;
- bool first_term_then_continue = false;
- foreach_in_list(loop_terminator, t, &ls->terminators) {
- ir_if *ir_if = t->ir->as_if();
- assert(ir_if != NULL);
+ /* recognize loops in the form produced by ir_lower_jumps */
+ foreach_in_list(ir_instruction, cur_ir, &ir->body_instructions) {
+ /* Skip the limiting terminator, since it will go away when we
+ * unroll.
+ */
+ if (cur_ir == ls->limiting_terminator->ir)
+ continue;
- ir_instruction *ir_if_last =
- (ir_instruction *) ir_if->then_instructions.get_tail();
-
- if (is_break(ir_if_last)) {
- splice_post_if_instructions(ir_if, &ir_if->else_instructions);
- ir_if_last->remove();
- if (term_count == 1) {
- bool ebi =
- exit_branch_has_instructions(ls->limiting_terminator->ir,
- first_term_then_continue);
- complex_unroll(ir, iterations, false,
- first_ir->as_if() != ls->limiting_terminator->ir ||
- ebi,
- first_term_then_continue);
- return visit_continue;
- }
- } else {
- ir_if_last =
- (ir_instruction *) ir_if->else_instructions.get_tail();
+ ir_if *ir_if = cur_ir->as_if();
+ if (ir_if != NULL) {
+ /* Determine which if-statement branch, if any, ends with a
+ * break. The branch that did *not* have the break will get a
+ * temporary continue inserted in each iteration of the loop
+ * unroll.
+ *
+ * Note that since ls->num_loop_jumps is <= 1, it is impossible
+ * for both branches to end with a break.
+ */
+ ir_instruction *ir_if_last =
+ (ir_instruction *) ir_if->then_instructions.get_tail();
- assert(is_break(ir_if_last));
if (is_break(ir_if_last)) {
- splice_post_if_instructions(ir_if, &ir_if->then_instructions);
+ ls->limiting_terminator->ir->remove();
+ splice_post_if_instructions(ir_if, &ir_if->else_instructions);
ir_if_last->remove();
- if (term_count == 1) {
- bool ebi =
- exit_branch_has_instructions(ls->limiting_terminator->ir,
- first_term_then_continue);
- complex_unroll(ir, iterations, true,
- first_ir->as_if() != ls->limiting_terminator->ir ||
- ebi,
- first_term_then_continue);
+ complex_unroll(ir, iterations, false);
+ return visit_continue;
+ } else {
+ ir_if_last =
+ (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);
return visit_continue;
- } else {
- first_term_then_continue = true;
}
}
}
-
- term_count++;
}
/* Did not find the break statement. It must be in a complex if-nesting,