microsoft/compiler: Use NIR_PASS instead of NIR_PASS_V

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36299>
This commit is contained in:
Jesse Natalie
2025-07-22 13:35:42 -07:00
parent f7db71949e
commit 2ca10a854f
4 changed files with 128 additions and 146 deletions
+98 -120
View File
@@ -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
+1 -1
View File
@@ -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);
+5 -1
View File
@@ -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 {
+24 -24
View File
@@ -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);