| /* |
| * Copyright © 2020 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 "nir_builder.h" |
| #include "nir_conversion_builder.h" |
| |
| static bool |
| try_simplify_convert_intrin(nir_intrinsic_instr *conv) |
| { |
| bool progress = false; |
| |
| nir_alu_type src_type = nir_intrinsic_src_type(conv); |
| nir_alu_type dest_type = nir_intrinsic_dest_type(conv); |
| |
| nir_rounding_mode rounding = nir_intrinsic_rounding_mode(conv); |
| nir_rounding_mode simple_rounding = |
| nir_simplify_conversion_rounding(src_type, dest_type, rounding); |
| if (rounding != simple_rounding) { |
| nir_intrinsic_set_rounding_mode(conv, simple_rounding); |
| progress = true; |
| } |
| |
| if (nir_intrinsic_saturate(conv) && |
| nir_alu_type_range_contains_type_range(dest_type, src_type)) { |
| nir_intrinsic_set_saturate(conv, false); |
| progress = true; |
| } |
| |
| return progress; |
| } |
| |
| static void |
| lower_convert_alu_types_instr(nir_builder *b, nir_intrinsic_instr *conv) |
| { |
| assert(conv->intrinsic == nir_intrinsic_convert_alu_types); |
| assert(conv->src[0].is_ssa && conv->dest.is_ssa); |
| |
| b->cursor = nir_instr_remove(&conv->instr); |
| nir_ssa_def *val = |
| nir_convert_with_rounding(b, conv->src[0].ssa, |
| nir_intrinsic_src_type(conv), |
| nir_intrinsic_dest_type(conv), |
| nir_intrinsic_rounding_mode(conv), |
| nir_intrinsic_saturate(conv)); |
| nir_ssa_def_rewrite_uses(&conv->dest.ssa, nir_src_for_ssa(val)); |
| } |
| |
| static bool |
| opt_simplify_convert_alu_types_impl(nir_function_impl *impl) |
| { |
| bool progress = false; |
| bool lowered_instr = false; |
| |
| nir_builder b; |
| nir_builder_init(&b, impl); |
| |
| nir_foreach_block(block, impl) { |
| nir_foreach_instr_safe(instr, block) { |
| if (instr->type != nir_instr_type_intrinsic) |
| continue; |
| |
| nir_intrinsic_instr *conv = nir_instr_as_intrinsic(instr); |
| if (conv->intrinsic != nir_intrinsic_convert_alu_types) |
| continue; |
| |
| if (try_simplify_convert_intrin(conv)) |
| progress = true; |
| |
| if (nir_intrinsic_rounding_mode(conv) == nir_rounding_mode_undef && |
| !nir_intrinsic_saturate(conv)) { |
| lower_convert_alu_types_instr(&b, conv); |
| lowered_instr = true; |
| } |
| } |
| } |
| |
| if (lowered_instr) { |
| nir_metadata_preserve(impl, nir_metadata_block_index | |
| nir_metadata_dominance); |
| } else { |
| nir_metadata_preserve(impl, nir_metadata_all); |
| } |
| |
| return progress; |
| } |
| |
| bool |
| nir_opt_simplify_convert_alu_types(nir_shader *shader) |
| { |
| bool progress = false; |
| |
| nir_foreach_function(func, shader) { |
| if (func->impl && opt_simplify_convert_alu_types_impl(func->impl)) |
| progress = true; |
| } |
| |
| return progress; |
| } |
| |
| static bool |
| lower_convert_alu_types_impl(nir_function_impl *impl, |
| bool (*should_lower)(nir_intrinsic_instr *)) |
| { |
| bool progress = false; |
| |
| nir_builder b; |
| nir_builder_init(&b, impl); |
| |
| nir_foreach_block(block, impl) { |
| nir_foreach_instr_safe(instr, block) { |
| if (instr->type != nir_instr_type_intrinsic) |
| continue; |
| |
| nir_intrinsic_instr *conv = nir_instr_as_intrinsic(instr); |
| if (conv->intrinsic != nir_intrinsic_convert_alu_types) |
| continue; |
| |
| if (should_lower != NULL && !should_lower(conv)) |
| continue; |
| |
| lower_convert_alu_types_instr(&b, conv); |
| progress = true; |
| } |
| } |
| |
| if (progress) { |
| nir_metadata_preserve(impl, nir_metadata_block_index | |
| nir_metadata_dominance); |
| } else { |
| nir_metadata_preserve(impl, nir_metadata_all); |
| } |
| |
| return progress; |
| } |
| |
| bool |
| nir_lower_convert_alu_types(nir_shader *shader, |
| bool (*should_lower)(nir_intrinsic_instr *)) |
| { |
| bool progress = false; |
| |
| nir_foreach_function(func, shader) { |
| if (func->impl && lower_convert_alu_types_impl(func->impl, should_lower)) |
| progress = true; |
| } |
| |
| return progress; |
| } |
| |
| static bool |
| is_constant(nir_intrinsic_instr *conv) |
| { |
| assert(conv->intrinsic == nir_intrinsic_convert_alu_types); |
| return nir_src_is_const(conv->src[0]); |
| } |
| |
| bool |
| nir_lower_constant_convert_alu_types(nir_shader *shader) |
| { |
| return nir_lower_convert_alu_types(shader, is_constant); |
| } |
| |
| static bool |
| is_alu_conversion(const nir_instr *instr, UNUSED const void *_data) |
| { |
| return instr->type == nir_instr_type_alu && |
| nir_op_infos[nir_instr_as_alu(instr)->op].is_conversion; |
| } |
| |
| static nir_ssa_def * |
| lower_alu_conversion(nir_builder *b, nir_instr *instr, UNUSED void *_data) |
| { |
| nir_alu_instr *alu = nir_instr_as_alu(instr); |
| return nir_convert_alu_types(b, nir_ssa_for_alu_src(b, alu, 0), |
| nir_op_infos[alu->op].input_types[0], |
| nir_op_infos[alu->op].output_type, |
| nir_rounding_mode_undef, false); |
| } |
| |
| bool |
| nir_lower_alu_conversion_to_intrinsic(nir_shader *shader) |
| { |
| return nir_shader_lower_instructions(shader, is_alu_conversion, |
| lower_alu_conversion, NULL); |
| } |