i965/blorp: Reduce the size of vertex buffer
[mesa.git] / src / mesa / drivers / dri / i965 / brw_dead_control_flow.cpp
index 8bdf0943e2e45ae02f63f47ca1aa3515708f0536..114dc6cb21240da5f3982160d27f8a2c151ac9d0 100644 (file)
 /* 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;
 }