diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index 40f148ba96a..5323e682637 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -143,6 +143,7 @@ files_libnir = files( 'nir_lower_clip_halfz.c', 'nir_lower_convert_alu_types.c', 'nir_lower_variable_initializers.c', + 'nir_lower_discard_if.c', 'nir_lower_discard_or_demote.c', 'nir_lower_double_ops.c', 'nir_lower_drawpixels.c', diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 91660a2f836..dc675939215 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -5137,6 +5137,8 @@ typedef enum { bool nir_lower_interpolation(nir_shader *shader, nir_lower_interpolation_options options); +bool nir_lower_discard_if(nir_shader *shader); + bool nir_lower_discard_or_demote(nir_shader *shader, bool force_correct_quad_ops_after_discard); diff --git a/src/compiler/nir/nir_lower_discard_if.c b/src/compiler/nir/nir_lower_discard_if.c new file mode 100644 index 00000000000..ac34ad45ae2 --- /dev/null +++ b/src/compiler/nir/nir_lower_discard_if.c @@ -0,0 +1,103 @@ +/* + * Copyright 2018 Collabora Ltd. + * + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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 "compiler/nir/nir_builder.h" + +static bool +lower_discard_if_instr(nir_builder *b, nir_instr *instr_, UNUSED void *cb_data) +{ + if (instr_->type != nir_instr_type_intrinsic) + return false; + + nir_intrinsic_instr *instr = nir_instr_as_intrinsic(instr_); + + if (instr->intrinsic == nir_intrinsic_discard_if) { + b->cursor = nir_before_instr(&instr->instr); + + nir_if *if_stmt = nir_push_if(b, nir_ssa_for_src(b, instr->src[0], 1)); + nir_discard(b); + nir_pop_if(b, if_stmt); + nir_instr_remove(&instr->instr); + return true; + } else if (instr->intrinsic == nir_intrinsic_terminate_if || + instr->intrinsic == nir_intrinsic_demote_if) { + unreachable("todo: handle terminates and demotes for Vulkan"); + } + + /* a shader like this (shaders@glsl-fs-discard-04): + + uniform int j, k; + + void main() + { + for (int i = 0; i < j; i++) { + if (i > k) + continue; + discard; + } + gl_FragColor = vec4(0.0, 1.0, 0.0, 0.0); + } + + + + will generate nir like: + + loop { + //snip + if ssa_11 { + block block_5: + / preds: block_4 / + vec1 32 ssa_17 = iadd ssa_50, ssa_31 + / succs: block_7 / + } else { + block block_6: + / preds: block_4 / + intrinsic discard () () <-- not last instruction + vec1 32 ssa_23 = iadd ssa_50, ssa_31 <-- dead code loop itr increment + / succs: block_7 / + } + //snip + } + + which means that we can't assert like this: + + assert(instr->intrinsic != nir_intrinsic_discard || + nir_block_last_instr(instr->instr.block) == &instr->instr); + + + and it's unnecessary anyway since later optimizations will dce the + instructions following the discard + */ + + return false; +} + +bool +nir_lower_discard_if(nir_shader *shader) +{ + return nir_shader_instructions_pass(shader, + lower_discard_if_instr, + nir_metadata_none, + NULL); +} diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index d677bfc79e6..6fb257697dd 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -75,79 +75,6 @@ reads_work_dim(nir_shader *shader) return BITSET_TEST(shader->info.system_values_read, SYSTEM_VALUE_WORK_DIM); } -static bool -lower_discard_if_instr(nir_builder *b, nir_instr *instr_, UNUSED void *cb_data) -{ - if (instr_->type != nir_instr_type_intrinsic) - return false; - - nir_intrinsic_instr *instr = nir_instr_as_intrinsic(instr_); - - if (instr->intrinsic == nir_intrinsic_discard_if) { - b->cursor = nir_before_instr(&instr->instr); - - nir_if *if_stmt = nir_push_if(b, nir_ssa_for_src(b, instr->src[0], 1)); - nir_discard(b); - nir_pop_if(b, if_stmt); - nir_instr_remove(&instr->instr); - return true; - } - /* a shader like this (shaders@glsl-fs-discard-04): - - uniform int j, k; - - void main() - { - for (int i = 0; i < j; i++) { - if (i > k) - continue; - discard; - } - gl_FragColor = vec4(0.0, 1.0, 0.0, 0.0); - } - - - - will generate nir like: - - loop { - //snip - if ssa_11 { - block block_5: - / preds: block_4 / - vec1 32 ssa_17 = iadd ssa_50, ssa_31 - / succs: block_7 / - } else { - block block_6: - / preds: block_4 / - intrinsic discard () () <-- not last instruction - vec1 32 ssa_23 = iadd ssa_50, ssa_31 <-- dead code loop itr increment - / succs: block_7 / - } - //snip - } - - which means that we can't assert like this: - - assert(instr->intrinsic != nir_intrinsic_discard || - nir_block_last_instr(instr->instr.block) == &instr->instr); - - - and it's unnecessary anyway since post-vtn optimizing will dce the instructions following the discard - */ - - return false; -} - -static bool -lower_discard_if(nir_shader *shader) -{ - return nir_shader_instructions_pass(shader, - lower_discard_if_instr, - nir_metadata_dominance, - NULL); -} - static bool lower_work_dim_instr(nir_builder *b, nir_instr *in, void *data) { @@ -1858,7 +1785,7 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir, optimize_nir(nir); NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL); - NIR_PASS_V(nir, lower_discard_if); + NIR_PASS_V(nir, nir_lower_discard_if); NIR_PASS_V(nir, nir_lower_fragcolor, nir->info.fs.color_is_dual_source ? 1 : 8); NIR_PASS_V(nir, lower_64bit_vertex_attribs);