| /* |
| * Copyright © 2019 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| * IN THE SOFTWARE. |
| */ |
| |
| #include "nir.h" |
| #include "util/bitset.h" |
| |
| static void |
| set_type(unsigned idx, nir_alu_type type, BITSET_WORD *float_types, |
| BITSET_WORD *int_types, bool *progress) |
| { |
| switch (nir_alu_type_get_base_type(type)) { |
| case nir_type_bool: |
| case nir_type_int: |
| case nir_type_uint: |
| if (int_types && !BITSET_TEST(int_types, idx)) { |
| *progress = true; |
| BITSET_SET(int_types, idx); |
| } |
| break; |
| |
| case nir_type_float: |
| if (float_types && !BITSET_TEST(float_types, idx)) { |
| *progress = true; |
| BITSET_SET(float_types, idx); |
| } |
| break; |
| |
| default: |
| unreachable("Invalid base nir_alu_type"); |
| } |
| } |
| |
| static void |
| copy_type(unsigned src, unsigned dst, bool src_is_sink, |
| BITSET_WORD *types, bool *progress) |
| { |
| if (!types) |
| return; |
| |
| if (BITSET_TEST(types, dst)) { |
| if (BITSET_TEST(types, src)) |
| return; |
| BITSET_SET(types, src); |
| *progress = true; |
| } else if (BITSET_TEST(types, src) && !src_is_sink) { |
| BITSET_SET(types, dst); |
| *progress = true; |
| } |
| } |
| |
| static void |
| copy_types(nir_src src, nir_dest *dest, BITSET_WORD *float_types, |
| BITSET_WORD *int_types, bool *progress) |
| { |
| bool src_is_sink = nir_src_is_const(src) || |
| src.ssa->parent_instr->type == nir_instr_type_ssa_undef; |
| copy_type(src.ssa->index, dest->ssa.index, src_is_sink, float_types, progress); |
| copy_type(src.ssa->index, dest->ssa.index, src_is_sink, int_types, progress); |
| } |
| |
| /** Gather up ALU types for SSA values |
| * |
| * This pass attempts to determine, for each SSA value, the type of data (int |
| * or float) that will be stored in it. The pass is greedy in the sense that |
| * it just assigns intness or floatness to types without any attempt to sort |
| * out the interesting cases where a given type may be both. |
| * |
| * The output of the pass is a pair of bitsets which has the intness or |
| * floatness of each SSA value recorded by index. It is the responsibility of |
| * the caller to index the SSA defs using nir_index_ssa_defs and allocate the |
| * bitsets. Either bitset is allowed to be NULL in which case no data is |
| * recorded for that type. |
| */ |
| void |
| nir_gather_ssa_types(nir_function_impl *impl, |
| BITSET_WORD *float_types, |
| BITSET_WORD *int_types) |
| { |
| bool progress; |
| do { |
| progress = false; |
| |
| nir_foreach_block(block, impl) { |
| nir_foreach_instr(instr, block) { |
| switch (instr->type) { |
| case nir_instr_type_alu: { |
| nir_alu_instr *alu = nir_instr_as_alu(instr); |
| assert(alu->dest.dest.is_ssa); |
| const nir_op_info *info = &nir_op_infos[alu->op]; |
| switch (alu->op) { |
| case nir_op_mov: |
| case nir_op_vec2: |
| case nir_op_vec3: |
| case nir_op_vec4: |
| for (unsigned i = 0; i < info->num_inputs; i++) { |
| copy_types(alu->src[i].src, &alu->dest.dest, |
| float_types, int_types, &progress); |
| } |
| break; |
| |
| case nir_op_bcsel: |
| case nir_op_b32csel: |
| set_type(alu->src[0].src.ssa->index, nir_type_bool, |
| float_types, int_types, &progress); |
| copy_types(alu->src[1].src, &alu->dest.dest, |
| float_types, int_types, &progress); |
| copy_types(alu->src[2].src, &alu->dest.dest, |
| float_types, int_types, &progress); |
| break; |
| |
| default: |
| for (unsigned i = 0; i < info->num_inputs; i++) { |
| assert(alu->src[i].src.is_ssa); |
| set_type(alu->src[i].src.ssa->index, info->input_types[i], |
| float_types, int_types, &progress); |
| } |
| set_type(alu->dest.dest.ssa.index, info->output_type, |
| float_types, int_types, &progress); |
| } |
| break; |
| } |
| |
| case nir_instr_type_tex: { |
| nir_tex_instr *tex = nir_instr_as_tex(instr); |
| for (unsigned i = 0; i < tex->num_srcs; i++) { |
| assert(tex->src[i].src.is_ssa); |
| set_type(tex->src[i].src.ssa->index, |
| nir_tex_instr_src_type(tex, i), |
| float_types, int_types, &progress); |
| } |
| assert(tex->dest.is_ssa); |
| set_type(tex->dest.ssa.index, tex->dest_type, |
| float_types, int_types, &progress); |
| break; |
| } |
| |
| case nir_instr_type_intrinsic: { |
| nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); |
| /* We could go nuts here, but we'll just handle a few simple |
| * cases and let everything else be untyped. |
| */ |
| switch (intrin->intrinsic) { |
| case nir_intrinsic_load_deref: { |
| nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); |
| |
| assert(intrin->dest.is_ssa); |
| set_type(intrin->dest.ssa.index, |
| nir_get_nir_type_for_glsl_type(deref->type), |
| float_types, int_types, &progress); |
| break; |
| } |
| |
| case nir_intrinsic_store_deref: { |
| nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); |
| |
| assert(intrin->src[1].is_ssa); |
| set_type(intrin->src[1].ssa->index, |
| nir_get_nir_type_for_glsl_type(deref->type), |
| float_types, int_types, &progress); |
| break; |
| } |
| |
| case nir_intrinsic_load_input: |
| case nir_intrinsic_load_uniform: |
| assert(intrin->dest.is_ssa); |
| set_type(intrin->dest.ssa.index, |
| nir_intrinsic_type(intrin), |
| float_types, int_types, &progress); |
| break; |
| |
| case nir_intrinsic_store_output: |
| assert(intrin->src[0].is_ssa); |
| set_type(intrin->src[0].ssa->index, |
| nir_intrinsic_type(intrin), |
| float_types, int_types, &progress); |
| break; |
| |
| default: |
| break; |
| } |
| |
| /* For the most part, we leave other intrinsics alone. Most |
| * of them don't matter in OpenGL ES 2.0 drivers anyway. |
| * However, we should at least check if this is some sort of |
| * IO intrinsic and flag it's offset and index sources. |
| */ |
| nir_src *offset_src = nir_get_io_offset_src(intrin); |
| if (offset_src) { |
| assert(offset_src->is_ssa); |
| set_type(offset_src->ssa->index, nir_type_int, |
| float_types, int_types, &progress); |
| } |
| break; |
| } |
| |
| case nir_instr_type_phi: { |
| nir_phi_instr *phi = nir_instr_as_phi(instr); |
| assert(phi->dest.is_ssa); |
| nir_foreach_phi_src(src, phi) { |
| copy_types(src->src, &phi->dest, |
| float_types, int_types, &progress); |
| } |
| break; |
| } |
| |
| default: |
| break; |
| } |
| } |
| } |
| } while (progress); |
| } |