Module: Mesa Branch: main Commit: d94e23d7bd516988df3aafbe1438f89d6121e254 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=d94e23d7bd516988df3aafbe1438f89d6121e254
Author: Jesse Natalie <[email protected]> Date: Thu May 11 10:58:25 2023 -0700 microsoft/compiler: Duplicate some SSA values to simplify SSA typing For each phi src, ensure that it's only used as a phi src. This lets us give each phi their own unique types without worrying about them stomping on each other. Also scalarize phis. For each constant, ensure that it's only used once. The DXIL backend will already dedupe these consts within the module, but this lets a single load_const have multiple types depending on how it's used. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22972> --- src/microsoft/compiler/dxil_nir.c | 58 ++++++++++++++++++++++++++++++++++++ src/microsoft/compiler/dxil_nir.h | 1 + src/microsoft/compiler/nir_to_dxil.c | 11 +++++-- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/microsoft/compiler/dxil_nir.c b/src/microsoft/compiler/dxil_nir.c index 39abd52268e..370889fab43 100644 --- a/src/microsoft/compiler/dxil_nir.c +++ b/src/microsoft/compiler/dxil_nir.c @@ -2410,6 +2410,64 @@ dxil_nir_forward_front_face(nir_shader *nir) var); } +static bool +split_phi_and_const_srcs(nir_builder *b, nir_instr *instr, void *data) +{ + bool progress = false; + switch (instr->type) { + case nir_instr_type_phi: { + /* Ensure each phi src is used only as a phi src and is not also a phi dest */ + nir_phi_instr *phi = nir_instr_as_phi(instr); + nir_foreach_phi_src(src, phi) { + assert(src->src.is_ssa); + if (!list_is_singular(&src->src.use_link) || + (src->src.is_ssa && src->src.parent_instr->type == nir_instr_type_phi)) { + b->cursor = nir_after_instr_and_phis(src->src.ssa->parent_instr); + nir_ssa_def *new_phi_src = nir_mov(b, src->src.ssa); + nir_src_rewrite_ssa(&src->src, new_phi_src); + progress = true; + } + } + return progress; + } + case nir_instr_type_load_const: { + /* Sink load_const to their uses if there's multiple */ + nir_load_const_instr *load_const = nir_instr_as_load_const(instr); + if (!list_is_singular(&load_const->def.uses)) { + nir_foreach_use_safe(src, &load_const->def) { + b->cursor = nir_before_src(src); + nir_load_const_instr *new_load = nir_load_const_instr_create(b->shader, + load_const->def.num_components, + load_const->def.bit_size); + memcpy(new_load->value, load_const->value, sizeof(load_const->value[0]) * load_const->def.num_components); + nir_builder_instr_insert(b, &new_load->instr); + nir_src_rewrite_ssa(src, &new_load->def); + progress = true; + } + } + return progress; + } + default: + return false; + } +} + +/* If a value is used by a phi and another instruction (e.g. another phi), + * copy the value with a mov and use that as the phi source. If the types + * of the uses are compatible, then the two phi sources will use the same + * DXIL SSA value, but if the types are not, then the mov provides an opportunity + * to insert a bitcast. Similarly, sink all consts so that they have only have + * a single use. The DXIL backend will already de-dupe the constants to the + * same dxil_value if they have the same type, but this allows a single constant + * to have different types without bitcasts. */ +bool +dxil_nir_split_phis_and_const_srcs(nir_shader *s) +{ + return nir_shader_instructions_pass(s, split_phi_and_const_srcs, + nir_metadata_block_index | nir_metadata_dominance, + NULL); +} + static void clear_pass_flags(nir_function_impl *impl) { diff --git a/src/microsoft/compiler/dxil_nir.h b/src/microsoft/compiler/dxil_nir.h index 9c9d3408588..5b38a873bbc 100644 --- a/src/microsoft/compiler/dxil_nir.h +++ b/src/microsoft/compiler/dxil_nir.h @@ -84,6 +84,7 @@ bool dxil_nir_lower_num_subgroups(nir_shader *s); bool dxil_nir_split_unaligned_loads_stores(nir_shader *shader, nir_variable_mode modes); bool dxil_nir_lower_unsupported_subgroup_scan(nir_shader *s); bool dxil_nir_forward_front_face(nir_shader *s); +bool dxil_nir_split_phis_and_const_srcs(nir_shader *s); struct dxil_module; bool dxil_nir_analyze_io_dependencies(struct dxil_module *mod, nir_shader *s); diff --git a/src/microsoft/compiler/nir_to_dxil.c b/src/microsoft/compiler/nir_to_dxil.c index e9e8731a44b..9612868dd12 100644 --- a/src/microsoft/compiler/nir_to_dxil.c +++ b/src/microsoft/compiler/nir_to_dxil.c @@ -2740,9 +2740,9 @@ emit_alu(struct ntd_context *ctx, nir_alu_instr *alu) case nir_op_vec16: return emit_vec(ctx, alu, nir_op_infos[alu->op].num_inputs); case nir_op_mov: { - assert(nir_dest_num_components(alu->dest.dest) == 1); - store_ssa_def(ctx, &alu->dest.dest.ssa, 0, get_src_ssa(ctx, - alu->src->src.ssa, alu->src->swizzle[0])); + for (uint32_t i = 0; i < alu->dest.dest.ssa.num_components; ++i) + store_ssa_def(ctx, &alu->dest.dest.ssa, i, get_src_ssa(ctx, + alu->src->src.ssa, alu->src->swizzle[i])); return true; } case nir_op_pack_double_2x32_dxil: @@ -6477,6 +6477,7 @@ optimize_nir(struct nir_shader *s, const struct nir_to_dxil_options *opts) NIR_PASS(progress, s, nir_opt_deref); NIR_PASS(progress, s, dxil_nir_lower_upcast_phis, opts->lower_int16 ? 32 : 16); NIR_PASS(progress, s, nir_lower_64bit_phis); + NIR_PASS(progress, s, nir_lower_phis_to_scalar, true); NIR_PASS(progress, s, nir_opt_loop_unroll); NIR_PASS_V(s, nir_lower_system_values); } while (progress); @@ -6775,6 +6776,10 @@ nir_to_dxil(struct nir_shader *s, const struct nir_to_dxil_options *opts, NIR_PASS_V(s, dxil_nir_lower_sysval_to_load_input, ctx->system_value); NIR_PASS_V(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_split_phis_and_const_srcs); + NIR_PASS_V(s, nir_opt_dce); + if (debug_dxil & DXIL_DEBUG_VERBOSE) nir_print_shader(s, stderr);
