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);