X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fdrivers%2Fdri%2Fi965%2Fbrw_dead_control_flow.cpp;h=114dc6cb21240da5f3982160d27f8a2c151ac9d0;hb=26fdb7e51e9f6b407ad8c635850ccffbd01876bc;hp=8bdf0943e2e45ae02f63f47ca1aa3515708f0536;hpb=a97cd0f4d7902965d5173f4bcbf2ad27c0eb5d12;p=mesa.git 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 8bdf0943e2e..114dc6cb212 100644 --- a/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp +++ b/src/mesa/drivers/dri/i965/brw_dead_control_flow.cpp @@ -32,52 +32,88 @@ /* Look for and eliminate dead control flow: * * - if/endif - * - if/else/endif + * - else in else/endif + * - then in if/else/endif */ bool -dead_control_flow_eliminate(backend_visitor *v) +dead_control_flow_eliminate(backend_shader *s) { bool progress = false; - cfg_t cfg(v); + foreach_block_safe (block, s->cfg) { + bblock_t *prev_block = block->prev(); - for (int b = 0; b < cfg.num_blocks; b++) { - bblock_t *block = cfg.blocks[b]; - bool found = false; + if (!prev_block) + continue; + + backend_instruction *const inst = block->start(); + backend_instruction *const prev_inst = prev_block->end(); - /* ENDIF instructions, by definition, can only be found at the ends of + /* ENDIF instructions, by definition, can only be found at the start of * basic blocks. */ - backend_instruction *endif_inst = block->end; - if (endif_inst->opcode != BRW_OPCODE_ENDIF) - continue; + if (inst->opcode == BRW_OPCODE_ENDIF && + prev_inst->opcode == BRW_OPCODE_ELSE) { + bblock_t *const else_block = prev_block; + backend_instruction *const else_inst = prev_inst; + + else_inst->remove(else_block); + progress = true; + } else if (inst->opcode == BRW_OPCODE_ENDIF && + prev_inst->opcode == BRW_OPCODE_IF) { + bblock_t *const endif_block = block; + bblock_t *const if_block = prev_block; + backend_instruction *const endif_inst = inst; + backend_instruction *const if_inst = prev_inst; + + bblock_t *earlier_block = NULL, *later_block = NULL; - backend_instruction *if_inst = NULL, *else_inst = NULL; - backend_instruction *prev_inst = (backend_instruction *) endif_inst->prev; - if (prev_inst->opcode == BRW_OPCODE_IF) { - if_inst = prev_inst; - found = true; - } else if (prev_inst->opcode == BRW_OPCODE_ELSE) { - else_inst = prev_inst; - - prev_inst = (backend_instruction *) prev_inst->prev; - if (prev_inst->opcode == BRW_OPCODE_IF) { - if_inst = prev_inst; - found = true; + if (if_block->start_ip == if_block->end_ip) { + earlier_block = if_block->prev(); + } else { + earlier_block = if_block; } - } + if_inst->remove(if_block); + + if (endif_block->start_ip == endif_block->end_ip) { + later_block = endif_block->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 = earlier_block->next(); + } + } + + progress = true; + } else if (inst->opcode == BRW_OPCODE_ELSE && + prev_inst->opcode == BRW_OPCODE_IF) { + bblock_t *const else_block = block; + backend_instruction *const if_inst = prev_inst; + backend_instruction *const else_inst = inst; + + /* Since the else-branch is becoming the new then-branch, the + * condition has to be inverted. + */ + if_inst->predicate_inverse = !if_inst->predicate_inverse; + else_inst->remove(else_block); - if (found) { - if_inst->remove(); - if (else_inst) - else_inst->remove(); - endif_inst->remove(); progress = true; } } if (progress) - v->invalidate_live_intervals(); + s->invalidate_live_intervals(); return progress; }