Home | History | Annotate | Download | only in i965
      1 /*
      2  * Copyright  2014 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 #include "brw_fs.h"
     25 #include "brw_fs_live_variables.h"
     26 #include "brw_cfg.h"
     27 
     28 /** @file brw_fs_dead_code_eliminate.cpp
     29  *
     30  * Dataflow-aware dead code elimination.
     31  *
     32  * Walks the instruction list from the bottom, removing instructions that
     33  * have results that both aren't used in later blocks and haven't been read
     34  * yet in the tail end of this block.
     35  */
     36 
     37 /**
     38  * Is it safe to eliminate the instruction?
     39  */
     40 static bool
     41 can_eliminate(const fs_inst *inst, BITSET_WORD *flag_live)
     42 {
     43     return !inst->is_control_flow() &&
     44            !inst->has_side_effects() &&
     45            !(flag_live[0] & inst->flags_written()) &&
     46            !inst->writes_accumulator;
     47 }
     48 
     49 /**
     50  * Is it safe to omit the write, making the destination ARF null?
     51  */
     52 static bool
     53 can_omit_write(const fs_inst *inst)
     54 {
     55    switch (inst->opcode) {
     56    case SHADER_OPCODE_UNTYPED_ATOMIC:
     57    case SHADER_OPCODE_UNTYPED_ATOMIC_LOGICAL:
     58    case SHADER_OPCODE_TYPED_ATOMIC:
     59    case SHADER_OPCODE_TYPED_ATOMIC_LOGICAL:
     60       return true;
     61    default:
     62       /* We can eliminate the destination write for ordinary instructions,
     63        * but not most SENDs.
     64        */
     65       if (inst->opcode < 128 && inst->mlen == 0)
     66          return true;
     67 
     68       /* It might not be safe for other virtual opcodes. */
     69       return false;
     70    }
     71 }
     72 
     73 bool
     74 fs_visitor::dead_code_eliminate()
     75 {
     76    bool progress = false;
     77 
     78    calculate_live_intervals();
     79 
     80    int num_vars = live_intervals->num_vars;
     81    BITSET_WORD *live = rzalloc_array(NULL, BITSET_WORD, BITSET_WORDS(num_vars));
     82    BITSET_WORD *flag_live = rzalloc_array(NULL, BITSET_WORD, 1);
     83 
     84    foreach_block_reverse_safe(block, cfg) {
     85       memcpy(live, live_intervals->block_data[block->num].liveout,
     86              sizeof(BITSET_WORD) * BITSET_WORDS(num_vars));
     87       memcpy(flag_live, live_intervals->block_data[block->num].flag_liveout,
     88              sizeof(BITSET_WORD));
     89 
     90       foreach_inst_in_block_reverse_safe(fs_inst, inst, block) {
     91          if (inst->dst.file == VGRF) {
     92             const unsigned var = live_intervals->var_from_reg(inst->dst);
     93             bool result_live = false;
     94 
     95             for (unsigned i = 0; i < regs_written(inst); i++)
     96                result_live |= BITSET_TEST(live, var + i);
     97 
     98             if (!result_live &&
     99                 (can_omit_write(inst) || can_eliminate(inst, flag_live))) {
    100                inst->dst = fs_reg(retype(brw_null_reg(), inst->dst.type));
    101                progress = true;
    102             }
    103          }
    104 
    105          if (inst->dst.is_null() && can_eliminate(inst, flag_live)) {
    106             inst->opcode = BRW_OPCODE_NOP;
    107             progress = true;
    108          }
    109 
    110          if (inst->dst.file == VGRF) {
    111             if (!inst->is_partial_write()) {
    112                int var = live_intervals->var_from_reg(inst->dst);
    113                for (unsigned i = 0; i < regs_written(inst); i++) {
    114                   BITSET_CLEAR(live, var + i);
    115                }
    116             }
    117          }
    118 
    119          if (!inst->predicate && inst->exec_size >= 8)
    120             flag_live[0] &= ~inst->flags_written();
    121 
    122          if (inst->opcode == BRW_OPCODE_NOP) {
    123             inst->remove(block);
    124             continue;
    125          }
    126 
    127          for (int i = 0; i < inst->sources; i++) {
    128             if (inst->src[i].file == VGRF) {
    129                int var = live_intervals->var_from_reg(inst->src[i]);
    130 
    131                for (unsigned j = 0; j < regs_read(inst, i); j++) {
    132                   BITSET_SET(live, var + j);
    133                }
    134             }
    135          }
    136 
    137          flag_live[0] |= inst->flags_read(devinfo);
    138       }
    139    }
    140 
    141    ralloc_free(live);
    142    ralloc_free(flag_live);
    143 
    144    if (progress)
    145       invalidate_live_intervals();
    146 
    147    return progress;
    148 }
    149