summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimothy Arceri <[email protected]>2018-03-26 11:41:51 +1100
committerJuan A. Suarez Romero <[email protected]>2018-03-28 16:51:21 +0200
commit189b25e3df298d8f4d4c69d50b763288caecc621 (patch)
tree3e4065c4315536982abf7779eac887cfdbedcaea
parentded412b467f0dea08e3c065f413262d30a842dba (diff)
nir: fix crash in loop unroll corner case
When an if nesting inside anouther if is optimised away we can end up with a loop terminator and following block that looks like this: if ssa_596 { block block_5: /* preds: block_4 */ vec1 32 ssa_601 = load_const (0xffffffff /* -nan */) break /* succs: block_8 */ } else { block block_6: /* preds: block_4 */ /* succs: block_7 */ } block block_7: /* preds: block_6 */ vec1 32 ssa_602 = phi block_6: ssa_552 vec1 32 ssa_603 = phi block_6: ssa_553 vec1 32 ssa_604 = iadd ssa_551, ssa_66 The problem is the phis. Loop unrolling expects the last block in the loop to be empty once we splice the instructions in the last block into the continue branch. The problem is we cant move phis so here we lower the phis to regs when preparing the loop for unrolling. As it could be possible to have multiple additional blocks/ifs following the terminator we just convert all phis at the top level of the loop body for simplicity. We also add some comments to loop_prepare_for_unroll() while we are here. Fixes: 51daccb289eb "nir: add a loop unrolling pass" Reviewed-by: Jason Ekstrand <[email protected]> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105670 (cherry picked from commit 629ee690addad9b3dc8f68cfff5ae09858f31caf)
-rw-r--r--src/compiler/nir/nir_opt_loop_unroll.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/src/compiler/nir/nir_opt_loop_unroll.c b/src/compiler/nir/nir_opt_loop_unroll.c
index dae5bfc9020..0e9cb500b58 100644
--- a/src/compiler/nir/nir_opt_loop_unroll.c
+++ b/src/compiler/nir/nir_opt_loop_unroll.c
@@ -39,10 +39,10 @@
#define LOOP_UNROLL_LIMIT 96
/* Prepare this loop for unrolling by first converting to lcssa and then
- * converting the phis from the loops first block and the block that follows
- * the loop into regs. Partially converting out of SSA allows us to unroll
- * the loop without having to keep track of and update phis along the way
- * which gets tricky and doesn't add much value over conveting to regs.
+ * converting the phis from the top level of the loop body to regs.
+ * Partially converting out of SSA allows us to unroll the loop without having
+ * to keep track of and update phis along the way which gets tricky and
+ * doesn't add much value over converting to regs.
*
* The loop may have a continue instruction at the end of the loop which does
* nothing. Once we're out of SSA, we can safely delete it so we don't have
@@ -53,13 +53,20 @@ loop_prepare_for_unroll(nir_loop *loop)
{
nir_convert_loop_to_lcssa(loop);
- nir_lower_phis_to_regs_block(nir_loop_first_block(loop));
+ /* Lower phis at the top level of the loop body */
+ foreach_list_typed_safe(nir_cf_node, node, node, &loop->body) {
+ if (nir_cf_node_block == node->type) {
+ nir_lower_phis_to_regs_block(nir_cf_node_as_block(node));
+ }
+ }
+ /* Lower phis after the loop */
nir_block *block_after_loop =
nir_cf_node_as_block(nir_cf_node_next(&loop->cf_node));
nir_lower_phis_to_regs_block(block_after_loop);
+ /* Remove continue if its the last instruction in the loop */
nir_instr *last_instr = nir_block_last_instr(nir_loop_last_block(loop));
if (last_instr && last_instr->type == nir_instr_type_jump) {
assert(nir_instr_as_jump(last_instr)->type == nir_jump_continue);