From 2ca10a854fb728e20fbf83141a566263079c11f1 Mon Sep 17 00:00:00 2001 From: Jesse Natalie Date: Tue, 22 Jul 2025 13:35:42 -0700 Subject: [PATCH] microsoft/compiler: Use NIR_PASS instead of NIR_PASS_V Part-of: --- src/microsoft/compiler/dxil_nir.c | 218 +++++++++++-------------- src/microsoft/compiler/dxil_nir.h | 2 +- src/microsoft/compiler/dxil_nir_tess.c | 6 +- src/microsoft/compiler/nir_to_dxil.c | 48 +++--- 4 files changed, 128 insertions(+), 146 deletions(-) diff --git a/src/microsoft/compiler/dxil_nir.c b/src/microsoft/compiler/dxil_nir.c index 40c129bdf8e..27cffc88bf9 100644 --- a/src/microsoft/compiler/dxil_nir.c +++ b/src/microsoft/compiler/dxil_nir.c @@ -214,12 +214,8 @@ dxil_nir_lower_constant_to_temp(nir_shader *nir) /* First pass: collect all UBO accesses that could be turned into * shader temp accesses. */ - nir_foreach_function(func, nir) { - if (!func->is_entrypoint) - continue; - assert(func->impl); - - nir_foreach_block(block, func->impl) { + nir_foreach_function_impl(impl, nir) { + nir_foreach_block(block, impl) { nir_foreach_instr_safe(instr, block) { if (instr->type != nir_instr_type_deref) continue; @@ -246,16 +242,18 @@ dxil_nir_lower_constant_to_temp(nir_shader *nir) progress = true; } + if (!progress) { + nir_shader_preserve_all_metadata(nir); + return false; + } + /* Second pass: patch all derefs that were accessing the converted UBOs * variables. */ - nir_foreach_function(func, nir) { - if (!func->is_entrypoint) - continue; - assert(func->impl); - - nir_builder b = nir_builder_create(func->impl); - nir_foreach_block(block, func->impl) { + nir_foreach_function_impl(impl, nir) { + nir_builder b = nir_builder_create(impl); + bool func_progress = false; + nir_foreach_block(block, impl) { nir_foreach_instr_safe(instr, block) { if (instr->type != nir_instr_type_deref) continue; @@ -272,11 +270,13 @@ dxil_nir_lower_constant_to_temp(nir_shader *nir) if (deref->deref_type == nir_deref_type_array) { b.cursor = nir_before_instr(instr); nir_src_rewrite(&deref->arr.index, nir_u2u32(&b, deref->arr.index.ssa)); + func_progress = true; } } } } } + nir_progress(func_progress, impl, nir_metadata_control_flow); } return progress; @@ -738,61 +738,37 @@ dxil_nir_lower_loads_stores_to_dxil(nir_shader *nir, } static bool -lower_deref_ssbo(nir_builder *b, nir_deref_instr *deref) +is_deref_ssbo(const nir_instr *instr, const void *state) { + if (instr->type != nir_instr_type_deref) + return false; + nir_deref_instr *deref = nir_instr_as_deref(instr); + return nir_deref_mode_is(deref, nir_var_mem_ssbo) && + deref->deref_type == nir_deref_type_var; +} + +static nir_def * +lower_deref_ssbo(nir_builder *b, nir_instr *instr, void *state) +{ + nir_deref_instr *deref = nir_instr_as_deref(instr); assert(nir_deref_mode_is(deref, nir_var_mem_ssbo)); - assert(deref->deref_type == nir_deref_type_var || - deref->deref_type == nir_deref_type_cast); + assert(deref->deref_type == nir_deref_type_var); nir_variable *var = deref->var; - b->cursor = nir_before_instr(&deref->instr); - - if (deref->deref_type == nir_deref_type_var) { - /* We turn all deref_var into deref_cast and build a pointer value based on - * the var binding which encodes the UAV id. - */ - nir_def *ptr = nir_imm_int64(b, (uint64_t)var->data.binding << 32); - nir_deref_instr *deref_cast = - nir_build_deref_cast(b, ptr, nir_var_mem_ssbo, deref->type, - glsl_get_explicit_stride(var->type)); - nir_def_replace(&deref->def, &deref_cast->def); - - deref = deref_cast; - return true; - } - return false; + /* We turn all deref_var into deref_cast and build a pointer value based on + * the var binding which encodes the UAV id. + */ + nir_def *ptr = nir_imm_int64(b, (uint64_t)var->data.binding << 32); + nir_deref_instr *deref_cast = + nir_build_deref_cast(b, ptr, nir_var_mem_ssbo, deref->type, + glsl_get_explicit_stride(var->type)); + return &deref_cast->def; } bool dxil_nir_lower_deref_ssbo(nir_shader *nir) { - bool progress = false; - - foreach_list_typed(nir_function, func, node, &nir->functions) { - if (!func->is_entrypoint) - continue; - assert(func->impl); - - nir_builder b = nir_builder_create(func->impl); - - nir_foreach_block(block, func->impl) { - nir_foreach_instr_safe(instr, block) { - if (instr->type != nir_instr_type_deref) - continue; - - nir_deref_instr *deref = nir_instr_as_deref(instr); - - if (!nir_deref_mode_is(deref, nir_var_mem_ssbo) || - (deref->deref_type != nir_deref_type_var && - deref->deref_type != nir_deref_type_cast)) - continue; - - progress |= lower_deref_ssbo(&b, deref); - } - } - } - - return progress; + return nir_shader_lower_instructions(nir, is_deref_ssbo, lower_deref_ssbo, NULL); } static bool @@ -2043,7 +2019,7 @@ get_cast_type(unsigned bit_size) unreachable("Invalid bit_size"); } -static void +static nir_def * split_unaligned_load(nir_builder *b, nir_intrinsic_instr *intrin, unsigned alignment) { enum gl_access_qualifier access = nir_intrinsic_access(intrin); @@ -2064,8 +2040,7 @@ split_unaligned_load(nir_builder *b, nir_intrinsic_instr *intrin, unsigned align srcs[i] = nir_load_deref_with_access(b, elem, access); } - nir_def *new_dest = nir_extract_bits(b, srcs, num_loads, 0, num_comps, intrin->def.bit_size); - nir_def_replace(&intrin->def, new_dest); + return nir_extract_bits(b, srcs, num_loads, 0, num_comps, intrin->def.bit_size); } static void @@ -2090,70 +2065,73 @@ split_unaligned_store(nir_builder *b, nir_intrinsic_instr *intrin, unsigned alig nir_deref_instr *elem = nir_build_deref_ptr_as_array(b, cast, nir_imm_intN_t(b, i, cast->def.bit_size)); nir_store_deref_with_access(b, elem, substore_val, ~0, access); } +} - nir_instr_remove(&intrin->instr); +static bool +is_unaligned_load_store(const nir_instr *instr, const void *state) +{ + if (instr->type != nir_instr_type_intrinsic) + return false; + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_load_deref && + intrin->intrinsic != nir_intrinsic_store_deref) + return false; + nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); + nir_variable_mode modes = *(nir_variable_mode *)state; + if (!nir_deref_mode_may_be(deref, modes)) + return false; + + unsigned align_mul = 0, align_offset = 0; + nir_get_explicit_deref_align(deref, true, &align_mul, &align_offset); + + unsigned alignment = align_offset ? 1 << (ffs(align_offset) - 1) : align_mul; + + /* We can load anything at 4-byte alignment, except for + * UBOs (AKA CBs where the granularity is 16 bytes). + */ + unsigned req_align = (nir_deref_mode_is_one_of(deref, nir_var_mem_ubo | nir_var_mem_push_const) ? 16 : 4); + if (alignment >= req_align) + return false; + + nir_def *val; + if (intrin->intrinsic == nir_intrinsic_load_deref) { + val = &intrin->def; + } else { + val = intrin->src[1].ssa; + } + + unsigned scalar_byte_size = glsl_type_is_boolean(deref->type) ? 4 : glsl_get_bit_size(deref->type) / 8; + unsigned num_components = + /* If the vector stride is larger than the scalar size, lower_explicit_io will + * turn this into multiple scalar loads anyway, so we don't have to split it here. */ + glsl_get_explicit_stride(deref->type) > scalar_byte_size ? 1 : + (val->num_components == 3 ? 4 : val->num_components); + unsigned natural_alignment = scalar_byte_size * num_components; + + return alignment < natural_alignment; +} + +static nir_def * +lower_unaligned_load_store(nir_builder *b, nir_instr *instr, void *state) +{ + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); + unsigned align_mul = 0, align_offset = 0; + nir_get_explicit_deref_align(deref, true, &align_mul, &align_offset); + unsigned alignment = align_offset ? 1 << (ffs(align_offset) - 1) : align_mul; + + if (intrin->intrinsic == nir_intrinsic_load_deref) + return split_unaligned_load(b, intrin, alignment); + else { + split_unaligned_store(b, intrin, alignment); + return NIR_LOWER_INSTR_PROGRESS_REPLACE; + } } bool dxil_nir_split_unaligned_loads_stores(nir_shader *shader, nir_variable_mode modes) { - bool progress = false; - - nir_foreach_function_impl(impl, shader) { - nir_builder b = nir_builder_create(impl); - - nir_foreach_block(block, impl) { - nir_foreach_instr_safe(instr, block) { - if (instr->type != nir_instr_type_intrinsic) - continue; - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - if (intrin->intrinsic != nir_intrinsic_load_deref && - intrin->intrinsic != nir_intrinsic_store_deref) - continue; - nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); - if (!nir_deref_mode_may_be(deref, modes)) - continue; - - unsigned align_mul = 0, align_offset = 0; - nir_get_explicit_deref_align(deref, true, &align_mul, &align_offset); - - unsigned alignment = align_offset ? 1 << (ffs(align_offset) - 1) : align_mul; - - /* We can load anything at 4-byte alignment, except for - * UBOs (AKA CBs where the granularity is 16 bytes). - */ - unsigned req_align = (nir_deref_mode_is_one_of(deref, nir_var_mem_ubo | nir_var_mem_push_const) ? 16 : 4); - if (alignment >= req_align) - continue; - - nir_def *val; - if (intrin->intrinsic == nir_intrinsic_load_deref) { - val = &intrin->def; - } else { - val = intrin->src[1].ssa; - } - - unsigned scalar_byte_size = glsl_type_is_boolean(deref->type) ? 4 : glsl_get_bit_size(deref->type) / 8; - unsigned num_components = - /* If the vector stride is larger than the scalar size, lower_explicit_io will - * turn this into multiple scalar loads anyway, so we don't have to split it here. */ - glsl_get_explicit_stride(deref->type) > scalar_byte_size ? 1 : - (val->num_components == 3 ? 4 : val->num_components); - unsigned natural_alignment = scalar_byte_size * num_components; - - if (alignment >= natural_alignment) - continue; - - if (intrin->intrinsic == nir_intrinsic_load_deref) - split_unaligned_load(&b, intrin, alignment); - else - split_unaligned_store(&b, intrin, alignment); - progress = true; - } - } - } - - return progress; + return nir_shader_lower_instructions(shader, is_unaligned_load_store, lower_unaligned_load_store, &modes); } static void diff --git a/src/microsoft/compiler/dxil_nir.h b/src/microsoft/compiler/dxil_nir.h index d0320665899..0a64633df33 100644 --- a/src/microsoft/compiler/dxil_nir.h +++ b/src/microsoft/compiler/dxil_nir.h @@ -69,7 +69,7 @@ void dxil_reassign_driver_locations(nir_shader* s, nir_variable_mode modes, uint64_t other_stage_mask, const BITSET_WORD *other_stage_frac_mask); -void dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func); +bool dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func); bool dxil_nir_fixup_tess_level_for_domain(nir_shader *nir); bool dxil_nir_set_tcs_patches_in(nir_shader *nir, unsigned num_control_points); bool dxil_nir_lower_ubo_array_one_to_static(nir_shader *s); diff --git a/src/microsoft/compiler/dxil_nir_tess.c b/src/microsoft/compiler/dxil_nir_tess.c index 96ef792dcbb..4489ba859ea 100644 --- a/src/microsoft/compiler/dxil_nir_tess.c +++ b/src/microsoft/compiler/dxil_nir_tess.c @@ -185,7 +185,7 @@ end_tcs_loop(nir_builder *b, struct tcs_patch_loop_state *state) * replace gl_InvocationID. This loop can be terminated when a barrier is hit. If * gl_InvocationID is used again after the barrier, then another loop needs to begin. */ -void +bool dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func) { assert(nir->info.stage == MESA_SHADER_TESS_CTRL); @@ -288,6 +288,10 @@ dxil_nir_split_tess_ctrl(nir_shader *nir, nir_function **patch_const_func) /* If we have more than one loop, SSA needs to be repaired for one loop to use defs from another. */ if (loop_var) nir_repair_ssa_impl(patch_const_func_impl); + + nir_progress(true, patch_const_func_impl, nir_metadata_none); + nir_progress(true, entrypoint, nir_metadata_none); + return true; } struct remove_tess_level_accesses_data { diff --git a/src/microsoft/compiler/nir_to_dxil.c b/src/microsoft/compiler/nir_to_dxil.c index 1537f3e4b58..5a10a335256 100644 --- a/src/microsoft/compiler/nir_to_dxil.c +++ b/src/microsoft/compiler/nir_to_dxil.c @@ -6317,7 +6317,7 @@ optimize_nir(struct nir_shader *s, const struct nir_to_dxil_options *opts) bool progress; do { progress = false; - NIR_PASS_V(s, nir_lower_vars_to_ssa); + NIR_PASS(progress, s, nir_lower_vars_to_ssa); NIR_PASS(progress, s, nir_lower_indirect_derefs, nir_var_function_temp, 4); NIR_PASS(progress, s, nir_lower_alu_to_scalar, NULL, NULL); NIR_PASS(progress, s, nir_copy_prop); @@ -6353,7 +6353,7 @@ optimize_nir(struct nir_shader *s, const struct nir_to_dxil_options *opts) NIR_PASS(progress, s, nir_opt_loop_unroll); NIR_PASS(progress, s, nir_lower_pack); NIR_PASS(progress, s, dxil_nir_remove_oob_array_accesses); - NIR_PASS_V(s, nir_lower_system_values); + NIR_PASS(progress, s, nir_lower_system_values); } while (progress); do { @@ -6361,7 +6361,7 @@ optimize_nir(struct nir_shader *s, const struct nir_to_dxil_options *opts) NIR_PASS(progress, s, nir_opt_algebraic_late); } while (progress); - NIR_PASS_V(s, nir_lower_undef_to_zero); + NIR_PASS(_, s, nir_lower_undef_to_zero); } static @@ -6631,16 +6631,16 @@ nir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts, ((1ull << FRAG_RESULT_STENCIL) | (1ull << FRAG_RESULT_SAMPLE_MASK)) : (VARYING_BIT_PRIMITIVE_ID | VARYING_BIT_VIEWPORT | VARYING_BIT_LAYER); - NIR_PASS_V(s, dxil_nir_fix_io_uint_type, in_mask, out_mask); + NIR_PASS(_, s, dxil_nir_fix_io_uint_type, in_mask, out_mask); } - NIR_PASS_V(s, dxil_nir_lower_fquantize2f16); - NIR_PASS_V(s, nir_lower_frexp); - NIR_PASS_V(s, nir_lower_flrp, 16 | 32 | 64, true); - NIR_PASS_V(s, nir_lower_io, nir_var_shader_in | nir_var_shader_out, type_size_vec4, nir_lower_io_lower_64bit_to_32); - NIR_PASS_V(s, dxil_nir_ensure_position_writes); - NIR_PASS_V(s, dxil_nir_lower_system_values); - NIR_PASS_V(s, nir_lower_io_to_scalar, nir_var_shader_in | nir_var_system_value | nir_var_shader_out, NULL, NULL); + NIR_PASS(_, s, dxil_nir_lower_fquantize2f16); + NIR_PASS(_, s, nir_lower_frexp); + NIR_PASS(_, s, nir_lower_flrp, 16 | 32 | 64, true); + NIR_PASS(_, s, nir_lower_io, nir_var_shader_in | nir_var_shader_out, type_size_vec4, nir_lower_io_lower_64bit_to_32); + NIR_PASS(_, s, dxil_nir_ensure_position_writes); + NIR_PASS(_, s, dxil_nir_lower_system_values); + NIR_PASS(_, s, nir_lower_io_to_scalar, nir_var_shader_in | nir_var_system_value | nir_var_shader_out, NULL, NULL); /* Do a round of optimization to try to vectorize loads/stores. Otherwise the addresses used for loads * might be too opaque for the pass to see that they're next to each other. */ @@ -6653,7 +6653,7 @@ nir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts, .callback = vectorize_filter, .modes = nir_var_mem_ubo | nir_var_mem_ssbo, }; - NIR_PASS_V(s, nir_opt_load_store_vectorize, &vectorize_opts); + NIR_PASS(_, s, nir_opt_load_store_vectorize, &vectorize_opts); /* Now that they're bloated to the max, address bit size restrictions and overall size limitations for * a single load/store op. */ @@ -6664,45 +6664,45 @@ nir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts, .may_lower_unaligned_stores_to_atomics = true, .cb_data = &mem_size_data }; - NIR_PASS_V(s, nir_lower_mem_access_bit_sizes, &mem_size_options); + NIR_PASS(_, s, nir_lower_mem_access_bit_sizes, &mem_size_options); /* Lastly, conver byte-address UBO loads to vec-addressed. This pass can also deal with selecting sub- * components from the load and dealing with vec-straddling loads. */ - NIR_PASS_V(s, nir_lower_ubo_vec4); + NIR_PASS(_, s, nir_lower_ubo_vec4); if (opts->shader_model_max < SHADER_MODEL_6_6) { /* In a later pass, load_helper_invocation will be lowered to sample mask based fallback, * so both load- and is- will be emulated eventually. */ - NIR_PASS_V(s, nir_lower_is_helper_invocation); + NIR_PASS(_, s, nir_lower_is_helper_invocation); } if (ctx->mod.shader_kind == DXIL_HULL_SHADER) - NIR_PASS_V(s, dxil_nir_split_tess_ctrl, &ctx->tess_ctrl_patch_constant_func); + NIR_PASS(_, s, dxil_nir_split_tess_ctrl, &ctx->tess_ctrl_patch_constant_func); if (ctx->mod.shader_kind == DXIL_HULL_SHADER || ctx->mod.shader_kind == DXIL_DOMAIN_SHADER) { /* Make sure any derefs are gone after lower_io before updating tess level vars */ - NIR_PASS_V(s, nir_opt_dce); - NIR_PASS_V(s, dxil_nir_fixup_tess_level_for_domain); + NIR_PASS(_, s, nir_opt_dce); + NIR_PASS(_, s, dxil_nir_fixup_tess_level_for_domain); } optimize_nir(s, opts); - NIR_PASS_V(s, nir_remove_dead_variables, + NIR_PASS(_, s, nir_remove_dead_variables, nir_var_function_temp | nir_var_mem_constant | nir_var_mem_shared, NULL); if (!allocate_sysvalues(ctx)) return false; - NIR_PASS_V(s, dxil_nir_lower_sysval_to_load_input, ctx->system_value); - NIR_PASS_V(s, nir_opt_dce); + NIR_PASS(_, s, dxil_nir_lower_sysval_to_load_input, ctx->system_value); + NIR_PASS(_, s, nir_opt_dce); /* This needs to be after any copy prop is done to prevent these movs from being erased */ - NIR_PASS_V(s, dxil_nir_move_consts); - NIR_PASS_V(s, nir_opt_dce); + NIR_PASS(_, s, dxil_nir_move_consts); + NIR_PASS(_, s, nir_opt_dce); - NIR_PASS_V(s, dxil_nir_guess_image_formats); + NIR_PASS(_, s, dxil_nir_guess_image_formats); if (debug_dxil & DXIL_DEBUG_VERBOSE) nir_print_shader(s, stderr);