Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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_cmod_propagation.cpp
  29.  *
  30.  * Implements a pass that propagates the conditional modifier from a CMP x 0.0
  31.  * instruction into the instruction that generated x. For instance, in this
  32.  * sequence
  33.  *
  34.  *    add(8)          g70<1>F    g69<8,8,1>F    4096F
  35.  *    cmp.ge.f0(8)    null       g70<8,8,1>F    0F
  36.  *
  37.  * we can do the comparison as part of the ADD instruction directly:
  38.  *
  39.  *    add.ge.f0(8)    g70<1>F    g69<8,8,1>F    4096F
  40.  *
  41.  * If there had been a use of the flag register and another CMP using g70
  42.  *
  43.  *    add.ge.f0(8)    g70<1>F    g69<8,8,1>F    4096F
  44.  *    (+f0) sel(8)    g71<F>     g72<8,8,1>F    g73<8,8,1>F
  45.  *    cmp.ge.f0(8)    null       g70<8,8,1>F    0F
  46.  *
  47.  * we can recognize that the CMP is generating the flag value that already
  48.  * exists and therefore remove the instruction.
  49.  */
  50.  
  51. static bool
  52. opt_cmod_propagation_local(bblock_t *block)
  53. {
  54.    bool progress = false;
  55.    int ip = block->end_ip + 1;
  56.  
  57.    foreach_inst_in_block_reverse_safe(fs_inst, inst, block) {
  58.       ip--;
  59.  
  60.       if ((inst->opcode != BRW_OPCODE_AND &&
  61.            inst->opcode != BRW_OPCODE_CMP &&
  62.            inst->opcode != BRW_OPCODE_MOV) ||
  63.           inst->predicate != BRW_PREDICATE_NONE ||
  64.           !inst->dst.is_null() ||
  65.           inst->src[0].file != GRF ||
  66.           inst->src[0].abs)
  67.          continue;
  68.  
  69.       /* Only an AND.NZ can be propagated.  Many AND.Z instructions are
  70.        * generated (for ir_unop_not in fs_visitor::emit_bool_to_cond_code).
  71.        * Propagating those would require inverting the condition on the CMP.
  72.        * This changes both the flag value and the register destination of the
  73.        * CMP.  That result may be used elsewhere, so we can't change its value
  74.        * on a whim.
  75.        */
  76.       if (inst->opcode == BRW_OPCODE_AND &&
  77.           !(inst->src[1].is_one() &&
  78.             inst->conditional_mod == BRW_CONDITIONAL_NZ &&
  79.             !inst->src[0].negate))
  80.          continue;
  81.  
  82.       if (inst->opcode == BRW_OPCODE_CMP && !inst->src[1].is_zero())
  83.          continue;
  84.  
  85.       if (inst->opcode == BRW_OPCODE_MOV &&
  86.           inst->conditional_mod != BRW_CONDITIONAL_NZ)
  87.          continue;
  88.  
  89.       bool read_flag = false;
  90.       foreach_inst_in_block_reverse_starting_from(fs_inst, scan_inst, inst,
  91.                                                   block) {
  92.          if (scan_inst->overwrites_reg(inst->src[0])) {
  93.             if (scan_inst->is_partial_write() ||
  94.                 scan_inst->dst.reg_offset != inst->src[0].reg_offset)
  95.                break;
  96.  
  97.             /* CMP's result is the same regardless of dest type. */
  98.             if (inst->conditional_mod == BRW_CONDITIONAL_NZ &&
  99.                 scan_inst->opcode == BRW_OPCODE_CMP &&
  100.                 (inst->dst.type == BRW_REGISTER_TYPE_D ||
  101.                  inst->dst.type == BRW_REGISTER_TYPE_UD)) {
  102.                inst->remove(block);
  103.                progress = true;
  104.                break;
  105.             }
  106.  
  107.             /* If the AND wasn't handled by the previous case, it isn't safe
  108.              * to remove it.
  109.              */
  110.             if (inst->opcode == BRW_OPCODE_AND)
  111.                break;
  112.  
  113.             /* Comparisons operate differently for ints and floats */
  114.             if (scan_inst->dst.type != inst->dst.type &&
  115.                 (scan_inst->dst.type == BRW_REGISTER_TYPE_F ||
  116.                  inst->dst.type == BRW_REGISTER_TYPE_F))
  117.                break;
  118.  
  119.             /* If the instruction generating inst's source also wrote the
  120.              * flag, and inst is doing a simple .nz comparison, then inst
  121.              * is redundant - the appropriate value is already in the flag
  122.              * register.  Delete inst.
  123.              */
  124.             if (inst->conditional_mod == BRW_CONDITIONAL_NZ &&
  125.                 !inst->src[0].negate &&
  126.                 scan_inst->writes_flag()) {
  127.                inst->remove(block);
  128.                progress = true;
  129.                break;
  130.             }
  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. fs_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.