From 383ecfbc70966a91382272c249b9750f3cff9031 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 30 Sep 2020 16:15:02 -0500 Subject: [PATCH] nir: Add a passes for nir_intrinsic_convert_alu_types This adds primarily two passes: One is a lowering pass which turns these conversion intrinsics into a series of ALU ops. The other is an optimization pass which attempt to simplify the conversion whenever possible in the hopes that we can turn it into a "normal" conversion op which doesn't need special treatment. Reviewed-by: Jesse Natalie Reviewed-by: Daniel Stone Part-of: --- src/compiler/Makefile.sources | 1 + src/compiler/nir/meson.build | 1 + src/compiler/nir/nir.h | 4 + src/compiler/nir/nir_lower_convert_alu_types.c | 182 +++++++++++++++++++++++++ 4 files changed, 188 insertions(+) create mode 100644 src/compiler/nir/nir_lower_convert_alu_types.c diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources index 73f0cb2..f597589 100644 --- a/src/compiler/Makefile.sources +++ b/src/compiler/Makefile.sources @@ -250,6 +250,7 @@ NIR_FILES = \ nir/nir_lower_clip_cull_distance_arrays.c \ nir/nir_lower_clip_disable.c \ nir/nir_lower_clip_halfz.c \ + nir/nir_lower_convert_alu_types.c \ nir/nir_lower_variable_initializers.c \ nir/nir_lower_discard_to_demote.c \ nir/nir_lower_double_ops.c \ diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index 657d4b4..f6030b0 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -129,6 +129,7 @@ files_libnir = files( 'nir_lower_clip_cull_distance_arrays.c', 'nir_lower_clip_disable.c', 'nir_lower_clip_halfz.c', + 'nir_lower_convert_alu_types.c', 'nir_lower_variable_initializers.c', 'nir_lower_discard_to_demote.c', 'nir_lower_double_ops.c', diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index ad96dba..d102417 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -4384,6 +4384,10 @@ bool nir_lower_alu_to_scalar(nir_shader *shader, nir_instr_filter_cb cb, const v bool nir_lower_bool_to_bitsize(nir_shader *shader); bool nir_lower_bool_to_float(nir_shader *shader); bool nir_lower_bool_to_int32(nir_shader *shader); +bool nir_opt_simplify_convert_alu_types(nir_shader *shader); +bool nir_lower_convert_alu_types(nir_shader *shader, + bool (*should_lower)(nir_intrinsic_instr *)); +bool nir_lower_constant_convert_alu_types(nir_shader *shader); bool nir_lower_int_to_float(nir_shader *shader); bool nir_lower_load_const_to_scalar(nir_shader *shader); bool nir_lower_read_invocation_to_scalar(nir_shader *shader); diff --git a/src/compiler/nir/nir_lower_convert_alu_types.c b/src/compiler/nir/nir_lower_convert_alu_types.c new file mode 100644 index 0000000..d2594b8 --- /dev/null +++ b/src/compiler/nir/nir_lower_convert_alu_types.c @@ -0,0 +1,182 @@ +/* + * 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); +} -- 2.7.4