From d3a0da555f2a2e961bc7322a84002e4a2c565884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Wed, 1 Jan 2025 16:37:48 -0500 Subject: [PATCH] radeonsi: lower indirect indexing sooner We need to do this before we gather shader_info because lowering indirect indexing can trigger more code elimination. The opts_not_run parameter is removed because it was only needed for array temps. Reviewed-by: Pierre-Eric Pelloux-Prayer Part-of: --- src/gallium/drivers/radeonsi/si_shader.c | 64 ++++++++++---------- src/gallium/drivers/radeonsi/si_shader.h | 2 +- src/gallium/drivers/radeonsi/si_shader_nir.c | 4 +- 3 files changed, 34 insertions(+), 36 deletions(-) diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index 62c22b4c403..053ca355987 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -2361,6 +2361,32 @@ static bool run_pre_link_optimization_passes(struct si_nir_shader_ctx *ctx) } } + if (progress) { + si_nir_opts(sel->screen, nir, true); + progress = false; + } + + /* Remove dead temps before we lower indirect indexing. */ + NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL); + + /* Lower indirect indexing last. + * + * Shader variant optimizations (such as uniform inlining, replacing barycentrics, and IO + * elimination) can help eliminate indirect indexing, so this should be done after that. + * + * Note that the code can still contain tautologies such as "array1[i] == array2[i]" when + * array1 and array2 have provably equal values (NIR doesn't have a pass that can do that), + * which NIR can optimize only after we lower indirecting indexing, so it's important that + * we lower it before we gather shader_info. + */ + + /* Lower indirect indexing of large constant arrays to the load_constant intrinsic, which + * will be turned into PC-relative loads from a data section next to the shader. + */ + NIR_PASS(progress, nir, nir_opt_large_constants, glsl_get_natural_size_align_bytes, 16); + + /* Lower all other indirect indexing to if-else ladders or scratch. */ + progress |= ac_nir_lower_indirect_derefs(nir, sel->screen->info.gfx_level); return progress; } @@ -2370,7 +2396,7 @@ static bool run_pre_link_optimization_passes(struct si_nir_shader_ctx *ctx) * in hw registers from now on. */ static void run_late_optimization_and_lowering_passes(struct si_nir_shader_ctx *ctx, - bool progress, bool opts_not_run) + bool progress) { struct si_shader *shader = ctx->shader; struct si_shader_selector *sel = shader->selector; @@ -2410,29 +2436,6 @@ static void run_late_optimization_and_lowering_passes(struct si_nir_shader_ctx * (nir->info.stage == MESA_SHADER_GEOMETRY && shader->key.ge.as_ngg)) && !shader->key.ge.as_ls && !shader->key.ge.as_es; - if (progress) { - si_nir_opts(sel->screen, nir, opts_not_run); - opts_not_run = false; - progress = false; - } - - /* Lower large variables that are always constant with load_constant intrinsics, which - * get turned into PC-relative loads from a data section next to the shader. - * - * Loop unrolling caused by uniform inlining can help eliminate indirect indexing, so - * this should be done after that. - * - * The pass crashes if there are dead temps of lowered IO interface types, so remove - * them first. - */ - NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_function_temp, NULL); - NIR_PASS(progress, nir, nir_opt_large_constants, glsl_get_natural_size_align_bytes, 16); - - /* Loop unrolling caused by uniform inlining can help eliminate indirect indexing, so - * this should be done after that. - */ - progress |= ac_nir_lower_indirect_derefs(nir, sel->screen->info.gfx_level); - if (nir->info.stage == MESA_SHADER_VERTEX) NIR_PASS(progress, nir, si_nir_lower_vs_inputs, shader, &ctx->args); @@ -2536,8 +2539,7 @@ static void run_late_optimization_and_lowering_passes(struct si_nir_shader_ctx * NIR_PASS(progress, nir, si_nir_lower_resource, shader, &ctx->args); if (progress) { - si_nir_opts(sel->screen, nir, opts_not_run); - opts_not_run = false; + si_nir_opts(sel->screen, nir, false); progress = false; } @@ -2593,8 +2595,7 @@ static void run_late_optimization_and_lowering_passes(struct si_nir_shader_ctx * } if (progress) { - si_nir_opts(sel->screen, nir, opts_not_run); - opts_not_run = false; + si_nir_opts(sel->screen, nir, false); progress = false; } @@ -2685,7 +2686,6 @@ static void get_nir_shaders(struct si_shader *shader, struct si_linked_shaders * get_prev_stage_input_nir(shader, linked); bool progress[SI_NUM_LINKED_SHADERS] = {0}; - bool opts_not_run[SI_NUM_LINKED_SHADERS] = {true, true}; for (unsigned i = 0; i < SI_NUM_LINKED_SHADERS; i++) { if (linked->shader[i].nir) { @@ -2710,8 +2710,7 @@ static void get_nir_shaders(struct si_shader *shader, struct si_linked_shaders * if (shader->selector->stage == MESA_SHADER_FRAGMENT) { if (progress[1]) { - si_nir_opts(shader->selector->screen, linked->consumer.nir, opts_not_run[1]); - opts_not_run[1] = false; + si_nir_opts(shader->selector->screen, linked->consumer.nir, false); progress[1] = false; } @@ -2735,8 +2734,7 @@ static void get_nir_shaders(struct si_shader *shader, struct si_linked_shaders * for (unsigned i = 0; i < SI_NUM_LINKED_SHADERS; i++) { if (linked->shader[i].nir) { - run_late_optimization_and_lowering_passes(&linked->shader[i], progress[i], - opts_not_run[i]); + run_late_optimization_and_lowering_passes(&linked->shader[i], progress[i]); } } diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h index f777c0b907a..dd6f023c3a2 100644 --- a/src/gallium/drivers/radeonsi/si_shader.h +++ b/src/gallium/drivers/radeonsi/si_shader.h @@ -1083,7 +1083,7 @@ void si_nir_scan_shader(struct si_screen *sscreen, struct nir_shader *nir, void si_lower_mediump_io(struct nir_shader *nir); bool si_alu_to_scalar_packed_math_filter(const struct nir_instr *instr, const void *data); -void si_nir_opts(struct si_screen *sscreen, struct nir_shader *nir, bool first); +void si_nir_opts(struct si_screen *sscreen, struct nir_shader *nir, bool has_array_temps); void si_nir_late_opts(struct nir_shader *nir); char *si_finalize_nir(struct pipe_screen *screen, struct nir_shader *nir); diff --git a/src/gallium/drivers/radeonsi/si_shader_nir.c b/src/gallium/drivers/radeonsi/si_shader_nir.c index aa12aded4ce..0486d3b46ea 100644 --- a/src/gallium/drivers/radeonsi/si_shader_nir.c +++ b/src/gallium/drivers/radeonsi/si_shader_nir.c @@ -55,7 +55,7 @@ static uint8_t si_vectorize_callback(const nir_instr *instr, const void *data) } } -void si_nir_opts(struct si_screen *sscreen, struct nir_shader *nir, bool first) +void si_nir_opts(struct si_screen *sscreen, struct nir_shader *nir, bool has_array_temps) { bool use_aco = sscreen->use_aco || nir->info.use_aco_amd; bool progress; @@ -70,7 +70,7 @@ void si_nir_opts(struct si_screen *sscreen, struct nir_shader *nir, bool first) nir->options->lower_to_scalar_filter, (void *)use_aco); NIR_PASS(progress, nir, nir_lower_phis_to_scalar, false); - if (first) { + if (has_array_temps) { NIR_PASS(progress, nir, nir_split_array_vars, nir_var_function_temp); NIR_PASS(lower_alu_to_scalar, nir, nir_shrink_vec_array_vars, nir_var_function_temp); NIR_PASS(progress, nir, nir_opt_find_array_copies);