diff options
-rw-r--r-- | src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp | 54 |
1 files changed, 45 insertions, 9 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp b/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp index e6ace5c444f..56884e64bf1 100644 --- a/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp +++ b/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp @@ -42,13 +42,14 @@ dead_control_flow_eliminate(backend_visitor *v) v->calculate_cfg(); - foreach_block (block, v->cfg) { + foreach_block_safe (block, v->cfg) { + bblock_t *if_block = NULL, *else_block = NULL, *endif_block = block; bool found = false; /* ENDIF instructions, by definition, can only be found at the start of * basic blocks. */ - backend_instruction *endif_inst = block->start; + backend_instruction *endif_inst = endif_block->start; if (endif_inst->opcode != BRW_OPCODE_ENDIF) continue; @@ -56,6 +57,7 @@ dead_control_flow_eliminate(backend_visitor *v) backend_instruction *prev_inst = (backend_instruction *) endif_inst->prev; if (prev_inst->opcode == BRW_OPCODE_ELSE) { else_inst = prev_inst; + else_block = (bblock_t *)endif_block->link.prev; found = true; prev_inst = (backend_instruction *) prev_inst->prev; @@ -63,6 +65,8 @@ dead_control_flow_eliminate(backend_visitor *v) if (prev_inst->opcode == BRW_OPCODE_IF) { if_inst = prev_inst; + if_block = else_block != NULL ? (bblock_t *)else_block->link.prev + : (bblock_t *)endif_block->link.prev; found = true; } else { /* Don't remove the ENDIF if we didn't find a dead IF. */ @@ -70,18 +74,50 @@ dead_control_flow_eliminate(backend_visitor *v) } if (found) { - if (if_inst) - if_inst->remove(); - if (else_inst) - else_inst->remove(); - if (endif_inst) - endif_inst->remove(); + bblock_t *earlier_block = NULL, *later_block = NULL; + + if (if_inst) { + if (if_block->start_ip == if_block->end_ip) { + earlier_block = (bblock_t *)if_block->link.prev; + } else { + earlier_block = if_block; + } + if_inst->remove(if_block); + } + + if (else_inst) { + else_block->if_block->else_block = NULL; + else_inst->remove(else_block); + } + + if (endif_inst) { + if (endif_block->start_ip == endif_block->end_ip) { + later_block = (bblock_t *)endif_block->link.next; + } else { + later_block = endif_block; + } + endif_inst->remove(endif_block); + } + + assert((earlier_block == NULL) == (later_block == NULL)); + if (earlier_block && earlier_block->can_combine_with(later_block)) { + earlier_block->combine_with(later_block); + + /* If ENDIF was in its own block, then we've now deleted it and + * merged the two surrounding blocks, the latter of which the + * __next block pointer was pointing to. + */ + if (endif_block != later_block) { + __next = (bblock_t *)earlier_block->link.next; + } + } + progress = true; } } if (progress) - v->invalidate_live_intervals(); + v->invalidate_live_intervals(false); return progress; } |