On Wed, Dec 17, 2014 at 5:20 PM, Jason Ekstrand <ja...@jlekstrand.net> wrote: > > > On Wed, Dec 17, 2014 at 1:10 PM, Jason Ekstrand <ja...@jlekstrand.net> > wrote: >> >> >> >> On Wed, Dec 17, 2014 at 12:07 PM, Connor Abbott <cwabbo...@gmail.com> >> wrote: >>> >>> 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. >> >> >> Easy enough to do. > > > Wait, I just remembered that I left them in intentionally. We may want to > run copy prop after lowering to source mods. In fact, when I wrote > lower_to_source_mods, I was lazy and just changed sat instructions to mov > and trusted in copy prop to clan up the swizzles for me. If anything, we > may want to make copy prop simply handle them correctly. > --Jason
Ok, that's fine. In that case, we should probably have a separate pass to move sat/abs/neg out of moves like the comment mentions, similar to what we do in i965 fs. Or did you already write one? > >> >> >>> >>> >>> > + >>> > + 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