Home | History | Annotate | Download | only in i965
      1 /*
      2  * Copyright  2015 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 
     25 /** @file brw_vec4_cmod_propagation.cpp
     26  *
     27  * Really similar to brw_fs_cmod_propagation but adapted to vec4 needs. Check
     28  * brw_fs_cmod_propagation for further details on the rationale behind this
     29  * optimization.
     30  */
     31 
     32 #include "brw_vec4.h"
     33 #include "brw_cfg.h"
     34 #include "brw_eu.h"
     35 
     36 namespace brw {
     37 
     38 static bool
     39 opt_cmod_propagation_local(bblock_t *block)
     40 {
     41    bool progress = false;
     42    int ip = block->end_ip + 1;
     43 
     44    foreach_inst_in_block_reverse_safe(vec4_instruction, inst, block) {
     45       ip--;
     46 
     47       if ((inst->opcode != BRW_OPCODE_AND &&
     48            inst->opcode != BRW_OPCODE_CMP &&
     49            inst->opcode != BRW_OPCODE_MOV) ||
     50           inst->predicate != BRW_PREDICATE_NONE ||
     51           !inst->dst.is_null() ||
     52           inst->src[0].file != VGRF ||
     53           inst->src[0].abs)
     54          continue;
     55 
     56       if (inst->opcode == BRW_OPCODE_AND &&
     57           !(inst->src[1].is_one() &&
     58             inst->conditional_mod == BRW_CONDITIONAL_NZ &&
     59             !inst->src[0].negate))
     60          continue;
     61 
     62       if (inst->opcode == BRW_OPCODE_CMP && !inst->src[1].is_zero())
     63          continue;
     64 
     65       if (inst->opcode == BRW_OPCODE_MOV &&
     66           inst->conditional_mod != BRW_CONDITIONAL_NZ)
     67          continue;
     68 
     69       bool read_flag = false;
     70       foreach_inst_in_block_reverse_starting_from(vec4_instruction, scan_inst, inst) {
     71          if (regions_overlap(inst->src[0], inst->size_read(0),
     72                              scan_inst->dst, scan_inst->size_written)) {
     73             if ((scan_inst->predicate && scan_inst->opcode != BRW_OPCODE_SEL) ||
     74                 scan_inst->dst.offset != inst->src[0].offset ||
     75                 (scan_inst->dst.writemask != WRITEMASK_X &&
     76                  scan_inst->dst.writemask != WRITEMASK_XYZW) ||
     77                 (scan_inst->dst.writemask == WRITEMASK_XYZW &&
     78                  inst->src[0].swizzle != BRW_SWIZZLE_XYZW) ||
     79                 (inst->dst.writemask & ~scan_inst->dst.writemask) != 0 ||
     80                 scan_inst->exec_size != inst->exec_size ||
     81                 scan_inst->group != inst->group) {
     82                break;
     83             }
     84 
     85             /* CMP's result is the same regardless of dest type. */
     86             if (inst->conditional_mod == BRW_CONDITIONAL_NZ &&
     87                 scan_inst->opcode == BRW_OPCODE_CMP &&
     88                 (inst->dst.type == BRW_REGISTER_TYPE_D ||
     89                  inst->dst.type == BRW_REGISTER_TYPE_UD)) {
     90                inst->remove(block);
     91                progress = true;
     92                break;
     93             }
     94 
     95             /* If the AND wasn't handled by the previous case, it isn't safe
     96              * to remove it.
     97              */
     98             if (inst->opcode == BRW_OPCODE_AND)
     99                break;
    100 
    101             /* Comparisons operate differently for ints and floats */
    102             if (scan_inst->dst.type != inst->dst.type &&
    103                 (scan_inst->dst.type == BRW_REGISTER_TYPE_F ||
    104                  inst->dst.type == BRW_REGISTER_TYPE_F))
    105                break;
    106 
    107             /* If the instruction generating inst's source also wrote the
    108              * flag, and inst is doing a simple .nz comparison, then inst
    109              * is redundant - the appropriate value is already in the flag
    110              * register.  Delete inst.
    111              */
    112             if (inst->conditional_mod == BRW_CONDITIONAL_NZ &&
    113                 !inst->src[0].negate &&
    114                 scan_inst->writes_flag()) {
    115                inst->remove(block);
    116                progress = true;
    117                break;
    118             }
    119 
    120             /* The conditional mod of the CMP/CMPN instructions behaves
    121              * specially because the flag output is not calculated from the
    122              * result of the instruction, but the other way around, which
    123              * means that even if the condmod to propagate and the condmod
    124              * from the CMP instruction are the same they will in general give
    125              * different results because they are evaluated based on different
    126              * inputs.
    127              */
    128             if (scan_inst->opcode == BRW_OPCODE_CMP ||
    129                 scan_inst->opcode == BRW_OPCODE_CMPN)
    130                break;
    131 
    132             /* Otherwise, try propagating the conditional. */
    133             enum brw_conditional_mod cond =
    134                inst->src[0].negate ? brw_swap_cmod(inst->conditional_mod)
    135                                    : inst->conditional_mod;
    136 
    137             if (scan_inst->can_do_cmod() &&
    138                 ((!read_flag && scan_inst->conditional_mod == BRW_CONDITIONAL_NONE) ||
    139                  scan_inst->conditional_mod == cond)) {
    140                scan_inst->conditional_mod = cond;
    141                inst->remove(block);
    142                progress = true;
    143             }
    144             break;
    145          }
    146 
    147          if (scan_inst->writes_flag())
    148             break;
    149 
    150          read_flag = read_flag || scan_inst->reads_flag();
    151       }
    152    }
    153 
    154    return progress;
    155 }
    156 
    157 bool
    158 vec4_visitor::opt_cmod_propagation()
    159 {
    160    bool progress = false;
    161 
    162    foreach_block_reverse(block, cfg) {
    163       progress = opt_cmod_propagation_local(block) || progress;
    164    }
    165 
    166    if (progress)
    167       invalidate_live_intervals();
    168 
    169    return progress;
    170 }
    171 
    172 } /* namespace brw */
    173