Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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.  * Authors:
  24.  *    Jason Ekstrand <jason@jlekstrand.net>
  25.  */
  26.  
  27. #include "brw_nir.h"
  28.  
  29. /*
  30.  * This file implements an analysis pass that determines when we have to do
  31.  * a boolean resolve on Gen <= 5.  Instructions that need a boolean resolve
  32.  * will have the booleans portion of the instr->pass_flags field set to
  33.  * BRW_NIR_BOOLEAN_NEEDS_RESOLVE.
  34.  */
  35.  
  36.  
  37. /** Returns the resolve status for the given source
  38.  *
  39.  * If the source has a parent instruction then the resolve status is the
  40.  * status of the parent instruction.  If the source does not have a parent
  41.  * instruction then we don't know so we return NON_BOOLEAN.
  42.  */
  43. static uint8_t
  44. get_resolve_status_for_src(nir_src *src)
  45. {
  46.    nir_instr *src_instr = nir_src_get_parent_instr(src);
  47.    if (src_instr) {
  48.       uint8_t resolve_status = src_instr->pass_flags & BRW_NIR_BOOLEAN_MASK;
  49.  
  50.       /* If the source instruction needs resolve, then from the perspective
  51.        * of the user, it's a true boolean.
  52.        */
  53.       if (resolve_status == BRW_NIR_BOOLEAN_NEEDS_RESOLVE)
  54.          resolve_status = BRW_NIR_BOOLEAN_NO_RESOLVE;
  55.       return resolve_status;
  56.    } else {
  57.       return BRW_NIR_NON_BOOLEAN;
  58.    }
  59. }
  60.  
  61. /** Marks the given source as needing a resolve
  62.  *
  63.  * If the given source corresponds to an unresolved boolean it marks it as
  64.  * needing a resolve.  Otherwise, we leave it alone.
  65.  */
  66. static bool
  67. src_mark_needs_resolve(nir_src *src, void *void_state)
  68. {
  69.    nir_instr *src_instr = nir_src_get_parent_instr(src);
  70.    if (src_instr) {
  71.       uint8_t resolve_status = src_instr->pass_flags & BRW_NIR_BOOLEAN_MASK;
  72.  
  73.       /* If the source instruction is unresolved, then mark it as needing
  74.        * to be resolved.
  75.        */
  76.       if (resolve_status == BRW_NIR_BOOLEAN_UNRESOLVED) {
  77.          src_instr->pass_flags &= ~BRW_NIR_BOOLEAN_MASK;
  78.          src_instr->pass_flags |= BRW_NIR_BOOLEAN_NEEDS_RESOLVE;
  79.       }
  80.  
  81.    }
  82.  
  83.    return true;
  84. }
  85.  
  86. static bool
  87. analyze_boolean_resolves_block(nir_block *block, void *void_state)
  88. {
  89.    nir_foreach_instr(block, instr) {
  90.       switch (instr->type) {
  91.       case nir_instr_type_alu: {
  92.          /* For ALU instructions, the resolve status is handled in a
  93.           * three-step process.
  94.           *
  95.           * 1) Look at the instruction type and sources and determine if it
  96.           *    can be left unresolved.
  97.           *
  98.           * 2) Look at the destination and see if we have to resolve
  99.           *    anyway.  (This is the case if this instruction is not the
  100.           *    only instruction writing to a given register.)
  101.           *
  102.           * 3) If the instruction has a resolve status other than
  103.           *    BOOL_UNRESOLVED or BOOL_NEEDS_RESOLVE then we walk through
  104.           *    the sources and ensure that they are also resolved.  This
  105.           *    ensures that we don't end up with any stray unresolved
  106.           *    booleans going into ADDs or something like that.
  107.           */
  108.  
  109.          uint8_t resolve_status;
  110.          nir_alu_instr *alu = nir_instr_as_alu(instr);
  111.          switch (alu->op) {
  112.          case nir_op_flt:
  113.          case nir_op_ilt:
  114.          case nir_op_ult:
  115.          case nir_op_fge:
  116.          case nir_op_ige:
  117.          case nir_op_uge:
  118.          case nir_op_feq:
  119.          case nir_op_ieq:
  120.          case nir_op_fne:
  121.          case nir_op_ine:
  122.          case nir_op_f2b:
  123.          case nir_op_i2b:
  124.             /* This instruction will turn into a CMP when we actually emit
  125.              * so the result will have to be resolved before it can be used.
  126.              */
  127.             resolve_status = BRW_NIR_BOOLEAN_UNRESOLVED;
  128.  
  129.             /* Even though the destination is allowed to be left unresolved,
  130.              * the sources are treated as regular integers or floats so
  131.              * they need to be resolved.
  132.              */
  133.             nir_foreach_src(instr, src_mark_needs_resolve, NULL);
  134.             break;
  135.  
  136.          case nir_op_imov:
  137.          case nir_op_inot:
  138.             /* This is a single-source instruction.  Just copy the resolve
  139.              * status from the source.
  140.              */
  141.             resolve_status = get_resolve_status_for_src(&alu->src[0].src);
  142.             break;
  143.  
  144.          case nir_op_iand:
  145.          case nir_op_ior:
  146.          case nir_op_ixor: {
  147.             uint8_t src0_status = get_resolve_status_for_src(&alu->src[0].src);
  148.             uint8_t src1_status = get_resolve_status_for_src(&alu->src[1].src);
  149.  
  150.             if (src0_status == src1_status) {
  151.                resolve_status = src0_status;
  152.             } else if (src0_status == BRW_NIR_NON_BOOLEAN ||
  153.                        src1_status == BRW_NIR_NON_BOOLEAN) {
  154.                /* If one of the sources is a non-boolean then the whole
  155.                 * thing is a non-boolean.
  156.                 */
  157.                resolve_status = BRW_NIR_NON_BOOLEAN;
  158.             } else {
  159.                /* At this point one of them is a true boolean and one is a
  160.                 * boolean that needs a resolve.  We could either resolve the
  161.                 * unresolved source or we could resolve here.  If we resolve
  162.                 * the unresolved source then we get two resolves for the price
  163.                 * of one.  Just set this one to BOOLEAN_NO_RESOLVE and we'll
  164.                 * let the code below force a resolve on the unresolved source.
  165.                 */
  166.                resolve_status = BRW_NIR_BOOLEAN_NO_RESOLVE;
  167.             }
  168.             break;
  169.          }
  170.  
  171.          default:
  172.             resolve_status = BRW_NIR_NON_BOOLEAN;
  173.          }
  174.  
  175.          /* If the destination is SSA-like, go ahead allow unresolved booleans.
  176.           * If the destination register doesn't have a well-defined parent_instr
  177.           * we need to resolve immediately.
  178.           */
  179.          if (alu->dest.dest.reg.reg->parent_instr == NULL &&
  180.              resolve_status == BRW_NIR_BOOLEAN_UNRESOLVED) {
  181.             resolve_status = BRW_NIR_BOOLEAN_NEEDS_RESOLVE;
  182.          }
  183.  
  184.          instr->pass_flags = (instr->pass_flags & ~BRW_NIR_BOOLEAN_MASK) |
  185.                              resolve_status;
  186.  
  187.          /* Finally, resolve sources if it's needed */
  188.          switch (resolve_status) {
  189.          case BRW_NIR_BOOLEAN_NEEDS_RESOLVE:
  190.          case BRW_NIR_BOOLEAN_UNRESOLVED:
  191.             /* This instruction is either unresolved or we're doing the
  192.              * resolve here; leave the sources alone.
  193.              */
  194.             break;
  195.  
  196.          case BRW_NIR_BOOLEAN_NO_RESOLVE:
  197.          case BRW_NIR_NON_BOOLEAN:
  198.             nir_foreach_src(instr, src_mark_needs_resolve, NULL);
  199.             break;
  200.  
  201.          default:
  202.             unreachable("Invalid boolean flag");
  203.          }
  204.  
  205.          break;
  206.       }
  207.  
  208.       case nir_instr_type_load_const: {
  209.          nir_load_const_instr *load = nir_instr_as_load_const(instr);
  210.  
  211.          /* For load_const instructions, it's a boolean exactly when it holds
  212.           * one of the values NIR_TRUE or NIR_FALSE.
  213.           *
  214.           * Since load_const instructions don't have any sources, we don't
  215.           * have to worry about resolving them.
  216.           */
  217.          instr->pass_flags &= ~BRW_NIR_BOOLEAN_MASK;
  218.          if (load->value.u[0] == NIR_TRUE || load->value.u[0] == NIR_FALSE) {
  219.             instr->pass_flags |= BRW_NIR_BOOLEAN_NO_RESOLVE;
  220.          } else {
  221.             instr->pass_flags |= BRW_NIR_NON_BOOLEAN;
  222.          }
  223.          continue;
  224.       }
  225.  
  226.       default:
  227.          /* Everything else is an unknown non-boolean value and needs to
  228.           * have all sources resolved.
  229.           */
  230.          instr->pass_flags = (instr->pass_flags & ~BRW_NIR_BOOLEAN_MASK) |
  231.                              BRW_NIR_NON_BOOLEAN;
  232.          nir_foreach_src(instr, src_mark_needs_resolve, NULL);
  233.          continue;
  234.       }
  235.    }
  236.  
  237.    nir_if *following_if = nir_block_get_following_if(block);
  238.    if (following_if)
  239.       src_mark_needs_resolve(&following_if->condition, NULL);
  240.  
  241.    return true;
  242. }
  243.  
  244. static void
  245. analyze_boolean_resolves_impl(nir_function_impl *impl)
  246. {
  247.    nir_foreach_block(impl, analyze_boolean_resolves_block, NULL);
  248. }
  249.  
  250. void
  251. brw_nir_analyze_boolean_resolves(nir_shader *shader)
  252. {
  253.    nir_foreach_overload(shader, overload)
  254.       if (overload->impl)
  255.          analyze_boolean_resolves_impl(overload->impl);
  256. }
  257.