*
* This peephole pass removes the IF and ENDIF instructions and predicates the
* BREAK, dropping two instructions from the loop body.
+ *
+ * If the loop was a DO { ... } WHILE loop, it looks like
+ *
+ * loop:
+ * ...
+ * CMP.f0
+ * (+f0) IF
+ * BREAK
+ * ENDIF
+ * WHILE loop
+ *
+ * and we can remove the BREAK instruction and predicate the WHILE.
*/
bool
jump_inst->opcode != BRW_OPCODE_CONTINUE)
continue;
- fs_inst *if_inst = (fs_inst *)((bblock_t *)block->link.prev)->end();
+ fs_inst *if_inst = (fs_inst *)block->prev()->end();
if (if_inst->opcode != BRW_OPCODE_IF)
continue;
- fs_inst *endif_inst = (fs_inst *)((bblock_t *)block->link.next)->start();
+ fs_inst *endif_inst = (fs_inst *)block->next()->start();
if (endif_inst->opcode != BRW_OPCODE_ENDIF)
continue;
bblock_t *jump_block = block;
- bblock_t *if_block = (bblock_t *)jump_block->link.prev;
- bblock_t *endif_block = (bblock_t *)jump_block->link.next;
+ bblock_t *if_block = jump_block->prev();
+ bblock_t *endif_block = jump_block->next();
/* For Sandybridge with IF with embedded comparison we need to emit an
* instruction to set the flag register.
bblock_t *earlier_block = if_block;
if (if_block->start_ip == if_block->end_ip) {
- earlier_block = (bblock_t *)if_block->link.prev;
+ earlier_block = if_block->prev();
}
if_inst->remove(if_block);
bblock_t *later_block = endif_block;
if (endif_block->start_ip == endif_block->end_ip) {
- later_block = (bblock_t *)endif_block->link.next;
+ later_block = endif_block->next();
}
endif_inst->remove(endif_block);
- earlier_block->children.make_empty();
- later_block->parents.make_empty();
+ if (!earlier_block->ends_with_control_flow()) {
+ earlier_block->children.make_empty();
+ earlier_block->add_successor(cfg->mem_ctx, jump_block);
+ }
- earlier_block->add_successor(cfg->mem_ctx, jump_block);
+ if (!later_block->starts_with_control_flow()) {
+ later_block->parents.make_empty();
+ }
jump_block->add_successor(cfg->mem_ctx, later_block);
if (earlier_block->can_combine_with(jump_block)) {
block = earlier_block;
}
+ /* Now look at the first instruction of the block following the BREAK. If
+ * it's a WHILE, we can delete the break, predicate the WHILE, and join
+ * the two basic blocks.
+ */
+ bblock_t *while_block = earlier_block->next();
+ fs_inst *while_inst = (fs_inst *)while_block->start();
+
+ if (jump_inst->opcode == BRW_OPCODE_BREAK &&
+ while_inst->opcode == BRW_OPCODE_WHILE &&
+ while_inst->predicate == BRW_PREDICATE_NONE) {
+ jump_inst->remove(earlier_block);
+ while_inst->predicate = jump_inst->predicate;
+ while_inst->predicate_inverse = !jump_inst->predicate_inverse;
+
+ earlier_block->children.make_empty();
+ earlier_block->add_successor(cfg->mem_ctx, while_block);
+
+ assert(earlier_block->can_combine_with(while_block));
+ earlier_block->combine_with(while_block);
+
+ earlier_block->next()->parents.make_empty();
+ earlier_block->add_successor(cfg->mem_ctx, earlier_block->next());
+ }
+
progress = true;
}