diff options
author | Timothy Arceri <[email protected]> | 2017-09-05 15:59:07 +1000 |
---|---|---|
committer | Timothy Arceri <[email protected]> | 2017-10-10 10:05:37 +1100 |
commit | ab23b759f241a4e2247efa28bd28a5f20149c70b (patch) | |
tree | 949b51f7e99fb7eec1116ebea4eabc8746cbb283 /src/compiler/glsl | |
parent | c63ce5c95d03f300be4a0f4b09e1d0cbc90e554e (diff) |
glsl: don't drop instructions from unreachable terminators continue branch
These instructions will be executed on every iteration of the loop
we cannot drop them.
V2:
- move removal of unreachable terminators from the terminator list
to the same place they are removed from the IR as suggested by
Nicolai.
Reviewed-by: Nicolai Hähnle <[email protected]>
Tested-by: Dieter Nützel <[email protected]>
Diffstat (limited to 'src/compiler/glsl')
-rw-r--r-- | src/compiler/glsl/loop_analysis.h | 7 | ||||
-rw-r--r-- | src/compiler/glsl/loop_unroll.cpp | 28 |
2 files changed, 27 insertions, 8 deletions
diff --git a/src/compiler/glsl/loop_analysis.h b/src/compiler/glsl/loop_analysis.h index 8f824046945..99b6bf75638 100644 --- a/src/compiler/glsl/loop_analysis.h +++ b/src/compiler/glsl/loop_analysis.h @@ -34,6 +34,13 @@ extern class loop_state * analyze_loop_variables(exec_list *instructions); +static inline bool +is_break(ir_instruction *ir) +{ + return ir != NULL && ir->ir_type == ir_type_loop_jump && + ((ir_loop_jump *) ir)->is_break(); +} + extern bool unroll_loops(exec_list *instructions, loop_state *ls, diff --git a/src/compiler/glsl/loop_unroll.cpp b/src/compiler/glsl/loop_unroll.cpp index 7eea439454b..358cbf10af4 100644 --- a/src/compiler/glsl/loop_unroll.cpp +++ b/src/compiler/glsl/loop_unroll.cpp @@ -53,13 +53,6 @@ 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; @@ -333,16 +326,35 @@ loop_unroll_visitor::visit_leave(ir_loop *ir) * bound, then that terminates the loop, so we don't even need the limiting * terminator. */ - foreach_in_list(loop_terminator, t, &ls->terminators) { + 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, ©_list, branch_instructions); + + t->ir->insert_before(©_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; } } |