Home | History | Annotate | Download | only in i965
      1 /*
      2  * Copyright  2013 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 /** @file brw_dead_control_flow.cpp
     25  *
     26  * This file implements the dead control flow elimination optimization pass.
     27  */
     28 
     29 #include "brw_shader.h"
     30 #include "brw_cfg.h"
     31 
     32 /* Look for and eliminate dead control flow:
     33  *
     34  *   - if/endif
     35  *   - else in else/endif
     36  *   - then in if/else/endif
     37  */
     38 bool
     39 dead_control_flow_eliminate(backend_shader *s)
     40 {
     41    bool progress = false;
     42 
     43    foreach_block_safe (block, s->cfg) {
     44       bblock_t *prev_block = block->prev();
     45 
     46       if (!prev_block)
     47          continue;
     48 
     49       backend_instruction *const inst = block->start();
     50       backend_instruction *const prev_inst = prev_block->end();
     51 
     52       /* ENDIF instructions, by definition, can only be found at the start of
     53        * basic blocks.
     54        */
     55       if (inst->opcode == BRW_OPCODE_ENDIF &&
     56           prev_inst->opcode == BRW_OPCODE_ELSE) {
     57          bblock_t *const else_block = prev_block;
     58          backend_instruction *const else_inst = prev_inst;
     59 
     60          else_inst->remove(else_block);
     61          progress = true;
     62       } else if (inst->opcode == BRW_OPCODE_ENDIF &&
     63                  prev_inst->opcode == BRW_OPCODE_IF) {
     64          bblock_t *const endif_block = block;
     65          bblock_t *const if_block = prev_block;
     66          backend_instruction *const endif_inst = inst;
     67          backend_instruction *const if_inst = prev_inst;
     68 
     69          bblock_t *earlier_block = NULL, *later_block = NULL;
     70 
     71          if (if_block->start_ip == if_block->end_ip) {
     72             earlier_block = if_block->prev();
     73          } else {
     74             earlier_block = if_block;
     75          }
     76          if_inst->remove(if_block);
     77 
     78          if (endif_block->start_ip == endif_block->end_ip) {
     79             later_block = endif_block->next();
     80          } else {
     81             later_block = endif_block;
     82          }
     83          endif_inst->remove(endif_block);
     84 
     85          assert((earlier_block == NULL) == (later_block == NULL));
     86          if (earlier_block && earlier_block->can_combine_with(later_block)) {
     87             earlier_block->combine_with(later_block);
     88 
     89             /* If ENDIF was in its own block, then we've now deleted it and
     90              * merged the two surrounding blocks, the latter of which the
     91              * __next block pointer was pointing to.
     92              */
     93             if (endif_block != later_block) {
     94                __next = earlier_block->next();
     95             }
     96          }
     97 
     98          progress = true;
     99       } else if (inst->opcode == BRW_OPCODE_ELSE &&
    100                  prev_inst->opcode == BRW_OPCODE_IF) {
    101          bblock_t *const else_block = block;
    102          backend_instruction *const if_inst = prev_inst;
    103          backend_instruction *const else_inst = inst;
    104 
    105          /* Since the else-branch is becoming the new then-branch, the
    106           * condition has to be inverted.
    107           */
    108          if_inst->predicate_inverse = !if_inst->predicate_inverse;
    109          else_inst->remove(else_block);
    110 
    111          progress = true;
    112       }
    113    }
    114 
    115    if (progress)
    116       s->invalidate_live_intervals();
    117 
    118    return progress;
    119 }
    120