On Tue, Dec 16, 2014 at 1:04 AM, Jason Ekstrand <ja...@jlekstrand.net> wrote: > From: Connor Abbott <connor.abb...@intel.com> > > --- > src/glsl/Makefile.sources | 1 + > src/glsl/nir/nir.h | 3 + > src/glsl/nir/nir_opt_copy_propagate.c | 313 > ++++++++++++++++++++++++++++++++++ > 3 files changed, 317 insertions(+) > create mode 100644 src/glsl/nir/nir_opt_copy_propagate.c > > diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources > index 0aaea58..556648b 100644 > --- a/src/glsl/Makefile.sources > +++ b/src/glsl/Makefile.sources > @@ -25,6 +25,7 @@ NIR_FILES = \ > $(GLSL_SRCDIR)/nir/nir_lower_variables_scalar.c \ > $(GLSL_SRCDIR)/nir/nir_opcodes.c \ > $(GLSL_SRCDIR)/nir/nir_opcodes.h \ > + $(GLSL_SRCDIR)/nir/nir_opt_copy_propagate.c \ > $(GLSL_SRCDIR)/nir/nir_opt_global_to_local.c \ > $(GLSL_SRCDIR)/nir/nir_print.c \ > $(GLSL_SRCDIR)/nir/nir_remove_dead_variables.c \ > diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h > index c2b4724..a5cb5ed 100644 > --- a/src/glsl/nir/nir.h > +++ b/src/glsl/nir/nir.h > @@ -1293,6 +1293,9 @@ void nir_convert_to_ssa(nir_shader *shader); > > bool nir_opt_global_to_local(nir_shader *shader); > > +bool nir_copy_prop_impl(nir_function_impl *impl); > +bool nir_copy_prop(nir_shader *shader); > + > #ifdef __cplusplus > } /* extern "C" */ > #endif > diff --git a/src/glsl/nir/nir_opt_copy_propagate.c > b/src/glsl/nir/nir_opt_copy_propagate.c > new file mode 100644 > index 0000000..a2be047 > --- /dev/null > +++ b/src/glsl/nir/nir_opt_copy_propagate.c > @@ -0,0 +1,313 @@ > +/* > + * Copyright © 2014 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > DEALINGS > + * IN THE SOFTWARE. > + * > + * Authors: > + * Connor Abbott (cwabbo...@gmail.com) > + * > + */ > + > +#include "nir.h" > +#include <main/imports.h> > + > +/** > + * SSA-based copy propagation > + */ > + > +static bool is_move(nir_alu_instr *instr) > +{ > + if (instr->op != nir_op_fmov && > + instr->op != nir_op_imov) > + return false; > + > + if (instr->dest.saturate) > + return false; > + > + /* we handle modifiers in a separate pass */
This comment is stale now, since this pass should never see modifiers... maybe we should replace those if's with asserts to make that clear. > + > + if (instr->src[0].abs || instr->src[0].negate) > + return false; > + > + if (!instr->src[0].src.is_ssa) > + return false; > + > + return true; > + > +} > + > +static bool > +is_swizzleless_move(nir_alu_instr *instr) > +{ > + if (!is_move(instr)) > + return false; > + > + for (unsigned i = 0; i < 4; i++) { > + if (!((instr->dest.write_mask >> i) & 1)) > + break; > + if (instr->src[0].swizzle[i] != i) > + return false; > + } > + > + return true; > +} > + > +static bool is_vec(nir_alu_instr *instr) > +{ > + for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) > + if (!instr->src[i].src.is_ssa) > + return false; > + > + return instr->op == nir_op_vec2 || > + instr->op == nir_op_vec3 || > + instr->op == nir_op_vec4; > +} > + > +typedef struct { > + nir_ssa_def *def; > + bool found; > +} search_def_state; > + > +static bool > +search_def(nir_src *src, void *_state) > +{ > + search_def_state *state = (search_def_state *) _state; > + > + if (src->is_ssa && src->ssa == state->def) > + state->found = true; > + > + return true; > +} > + > +static void > +rewrite_src_instr(nir_src *src, nir_ssa_def *new_def, nir_instr > *parent_instr) > +{ > + nir_ssa_def *old_def = src->ssa; > + > + src->ssa = new_def; > + > + /* > + * The instruction could still use the old definition in one of its other > + * sources, so only remove the instruction from the uses if there are no > + * more uses left. > + */ > + > + search_def_state search_state; > + search_state.def = old_def; > + search_state.found = false; > + nir_foreach_src(parent_instr, search_def, &search_state); > + if (!search_state.found) { > + struct set_entry *entry = > + _mesa_set_search(old_def->uses, _mesa_hash_pointer(parent_instr), > + parent_instr); > + assert(entry); > + _mesa_set_remove(old_def->uses, entry); > + } > + > + _mesa_set_add(new_def->uses, _mesa_hash_pointer(parent_instr), > + parent_instr); > +} > + > +static void > +rewrite_src_if(nir_if *if_stmt, nir_ssa_def *new_def) > +{ > + nir_ssa_def *old_def = if_stmt->condition.ssa; > + > + if_stmt->condition.ssa = new_def; > + > + struct set_entry *entry = > + _mesa_set_search(old_def->if_uses, _mesa_hash_pointer(if_stmt), > if_stmt); > + assert(entry); > + _mesa_set_remove(old_def->if_uses, entry); > + > + _mesa_set_add(new_def->if_uses, _mesa_hash_pointer(if_stmt), if_stmt); > +} > + > +static bool > +copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if) > +{ > + if (!src->is_ssa) { > + if (src->reg.indirect) > + return copy_prop_src(src, parent_instr, parent_if); > + return false; > + } > + > + nir_instr *src_instr = src->ssa->parent_instr; > + if (src_instr->type != nir_instr_type_alu) > + return false; > + > + nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr); > + if (!is_swizzleless_move(alu_instr)) > + return false; > + > + if (parent_instr) > + rewrite_src_instr(src, alu_instr->src[0].src.ssa, parent_instr); > + else > + rewrite_src_if(parent_if, alu_instr->src[0].src.ssa); > + > + return true; > +} > + > +static bool > +copy_prop_alu_src(nir_alu_instr *parent_alu_instr, unsigned index) > +{ > + nir_alu_src *src = &parent_alu_instr->src[index]; > + if (!src->src.is_ssa) { > + if (src->src.reg.indirect) > + return copy_prop_src(src->src.reg.indirect, > &parent_alu_instr->instr, > + NULL); > + return false; > + } > + > + nir_instr *src_instr = src->src.ssa->parent_instr; > + if (src_instr->type != nir_instr_type_alu) > + return false; > + > + nir_alu_instr *alu_instr = nir_instr_as_alu(src_instr); > + if (!is_move(alu_instr) && !is_vec(alu_instr)) > + return false; > + > + nir_ssa_def *def; > + unsigned new_swizzle[4] = {0, 0, 0, 0}; > + > + if (alu_instr->op == nir_op_fmov || > + alu_instr->op == nir_op_imov) { > + for (unsigned i = 0; i < 4; i++) > + new_swizzle[i] = alu_instr->src[0].swizzle[src->swizzle[i]]; > + def = alu_instr->src[0].src.ssa; > + } else { > + def = NULL; > + > + for (unsigned i = 0; i < 4; i++) { > + if (!nir_alu_instr_channel_used(parent_alu_instr, index, i)) > + continue; > + > + nir_ssa_def *new_def = alu_instr->src[src->swizzle[i]].src.ssa; > + if (def == NULL) > + def = new_def; > + else { > + if (def != new_def) > + return false; > + } > + new_swizzle[i] = alu_instr->src[src->swizzle[i]].swizzle[0]; > + } > + } > + > + for (unsigned i = 0; i < 4; i++) > + src->swizzle[i] = new_swizzle[i]; > + > + rewrite_src_instr(&src->src, def, &parent_alu_instr->instr); > + > + return true; > +} > + > +typedef struct { > + nir_instr *parent_instr; > + bool progress; > +} copy_prop_state; > + > +static bool > +copy_prop_src_cb(nir_src *src, void *_state) > +{ > + copy_prop_state *state = (copy_prop_state *) _state; > + while (copy_prop_src(src, state->parent_instr, NULL)) > + state->progress = true; > + > + return true; > +} > + > +static bool > +copy_prop_instr(nir_instr *instr) > +{ > + if (instr->type == nir_instr_type_alu) { > + nir_alu_instr *alu_instr = nir_instr_as_alu(instr); > + bool progress = false; > + > + for (unsigned i = 0; i < nir_op_infos[alu_instr->op].num_inputs; i++) > + while (copy_prop_alu_src(alu_instr, i)) > + progress = true; > + > + if (alu_instr->has_predicate) > + while (copy_prop_src(&alu_instr->predicate, instr, NULL)) > + progress = true; > + > + if (!alu_instr->dest.dest.is_ssa && alu_instr->dest.dest.reg.indirect) > + while (copy_prop_src(alu_instr->dest.dest.reg.indirect, instr, > NULL)) > + progress = true; > + > + return progress; > + } > + > + copy_prop_state state; > + state.parent_instr = instr; > + state.progress = false; > + nir_foreach_src(instr, copy_prop_src_cb, &state); > + > + return state.progress; > +} > + > +static bool > +copy_prop_if(nir_if *if_stmt) > +{ > + return copy_prop_src(&if_stmt->condition, NULL, if_stmt); > +} > + > +static bool > +copy_prop_block(nir_block *block, void *_state) > +{ > + bool *progress = (bool *) _state; > + > + nir_foreach_instr(block, instr) { > + if (copy_prop_instr(instr)) > + *progress = true; > + } > + > + if (block->cf_node.node.next != NULL && /* check that we aren't the end > node */ > + !nir_cf_node_is_last(&block->cf_node) && > + nir_cf_node_next(&block->cf_node)->type == nir_cf_node_if) { > + nir_if *if_stmt = nir_cf_node_as_if(nir_cf_node_next(&block->cf_node)); > + if (copy_prop_if(if_stmt)) > + *progress = true; > + } > + > + return true; > +} > + > +bool > +nir_copy_prop_impl(nir_function_impl *impl) > +{ > + bool progress = false; > + > + nir_foreach_block(impl, copy_prop_block, &progress); > + return progress; > +} > + > +bool > +nir_copy_prop(nir_shader *shader) > +{ > + bool progress = false; > + > + nir_foreach_overload(shader, overload) { > + if (overload->impl && nir_copy_prop_impl(overload->impl)) > + progress = true; > + } > + > + return progress; > +} > -- > 2.2.0 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev