*/
#include "nir.h"
+#include "nir_builder.h"
/*
* Implements a simple pass that lowers vecN instructions to a series of
}
static bool
-lower_vec_to_movs_block(nir_block *block, nir_function_impl *impl)
+nir_lower_vec_to_movs_instr(nir_builder *b, nir_instr *instr, void *data)
{
- bool progress = false;
- nir_shader *shader = impl->function->shader;
-
- nir_foreach_instr_safe(instr, block) {
- if (instr->type != nir_instr_type_alu)
- continue;
-
- nir_alu_instr *vec = nir_instr_as_alu(instr);
-
- switch (vec->op) {
- case nir_op_vec2:
- case nir_op_vec3:
- case nir_op_vec4:
- break;
- default:
- continue; /* The loop */
- }
-
- bool vec_had_ssa_dest = vec->dest.dest.is_ssa;
- if (vec->dest.dest.is_ssa) {
- /* Since we insert multiple MOVs, we have a register destination. */
- nir_register *reg = nir_local_reg_create(impl);
- reg->num_components = vec->dest.dest.ssa.num_components;
- reg->bit_size = vec->dest.dest.ssa.bit_size;
+ if (instr->type != nir_instr_type_alu)
+ return false;
- nir_ssa_def_rewrite_uses(&vec->dest.dest.ssa, nir_src_for_reg(reg));
+ nir_alu_instr *vec = nir_instr_as_alu(instr);
- nir_instr_rewrite_dest(&vec->instr, &vec->dest.dest,
- nir_dest_for_reg(reg));
- }
+ switch (vec->op) {
+ case nir_op_vec2:
+ case nir_op_vec3:
+ case nir_op_vec4:
+ break;
+ default:
+ return false;
+ }
- unsigned finished_write_mask = 0;
+ bool vec_had_ssa_dest = vec->dest.dest.is_ssa;
+ if (vec->dest.dest.is_ssa) {
+ /* Since we insert multiple MOVs, we have a register destination. */
+ nir_register *reg = nir_local_reg_create(b->impl);
+ reg->num_components = vec->dest.dest.ssa.num_components;
+ reg->bit_size = vec->dest.dest.ssa.bit_size;
- /* First, emit a MOV for all the src channels that are in the
- * destination reg, in case other values we're populating in the dest
- * might overwrite them.
- */
- for (unsigned i = 0; i < 4; i++) {
- if (!(vec->dest.write_mask & (1 << i)))
- continue;
+ nir_ssa_def_rewrite_uses(&vec->dest.dest.ssa, nir_src_for_reg(reg));
- if (src_matches_dest_reg(&vec->dest.dest, &vec->src[i].src)) {
- finished_write_mask |= insert_mov(vec, i, shader);
- break;
- }
- }
+ nir_instr_rewrite_dest(&vec->instr, &vec->dest.dest,
+ nir_dest_for_reg(reg));
+ }
- /* Now, emit MOVs for all the other src channels. */
- for (unsigned i = 0; i < 4; i++) {
- if (!(vec->dest.write_mask & (1 << i)))
- continue;
+ unsigned finished_write_mask = 0;
- /* Coalescing moves the register writes from the vec up to the ALU
- * instruction in the source. We can only do this if the original
- * vecN had an SSA destination.
- */
- if (vec_had_ssa_dest && !(finished_write_mask & (1 << i)))
- finished_write_mask |= try_coalesce(vec, i);
+ /* First, emit a MOV for all the src channels that are in the
+ * destination reg, in case other values we're populating in the dest
+ * might overwrite them.
+ */
+ for (unsigned i = 0; i < 4; i++) {
+ if (!(vec->dest.write_mask & (1 << i)))
+ continue;
- if (!(finished_write_mask & (1 << i)))
- finished_write_mask |= insert_mov(vec, i, shader);
+ if (src_matches_dest_reg(&vec->dest.dest, &vec->src[i].src)) {
+ finished_write_mask |= insert_mov(vec, i, b->shader);
+ break;
}
-
- nir_instr_remove(&vec->instr);
- ralloc_free(vec);
- progress = true;
}
- return progress;
-}
+ /* Now, emit MOVs for all the other src channels. */
+ for (unsigned i = 0; i < 4; i++) {
+ if (!(vec->dest.write_mask & (1 << i)))
+ continue;
-static bool
-nir_lower_vec_to_movs_impl(nir_function_impl *impl)
-{
- bool progress = false;
+ /* Coalescing moves the register writes from the vec up to the ALU
+ * instruction in the source. We can only do this if the original
+ * vecN had an SSA destination.
+ */
+ if (vec_had_ssa_dest && !(finished_write_mask & (1 << i)))
+ finished_write_mask |= try_coalesce(vec, i);
- nir_foreach_block(block, impl) {
- progress |= lower_vec_to_movs_block(block, impl);
+ if (!(finished_write_mask & (1 << i)))
+ finished_write_mask |= insert_mov(vec, i, b->shader);
}
- if (progress) {
- nir_metadata_preserve(impl, nir_metadata_block_index |
- nir_metadata_dominance);
- } else {
- nir_metadata_preserve(impl, nir_metadata_all);
- }
+ nir_instr_remove(&vec->instr);
+ ralloc_free(vec);
- return progress;
+ return true;
}
bool
nir_lower_vec_to_movs(nir_shader *shader)
{
- bool progress = false;
-
- nir_foreach_function(function, shader) {
- if (function->impl)
- progress = nir_lower_vec_to_movs_impl(function->impl) || progress;
- }
-
- return progress;
+ return nir_shader_instructions_pass(shader,
+ nir_lower_vec_to_movs_instr,
+ nir_metadata_block_index |
+ nir_metadata_dominance,
+ NULL);
}