From: Ian Romanick <ian.d.roman...@intel.com> Three parts to the fix:
1. If the array dereference is a constant index, figure out the real write mask. 2. If the array dereference not is a constant index, assume the assignment may generate any component. 3. If the array dereference not is a constant index, assume the assigment will not kill any previous component write. v2: Fix accidental setting of debug flag (noticed by Aras Pranckevičius). Fix idiotic typo added after last build. Signed-off-by: Ian Romanick <ian.d.roman...@intel.com> Cc: Chris Wolfe <cwo...@chromium.org> Cc: Eric Anholt <e...@anholt.net> Cc: Kenneth Graunke <kenn...@whitecape.org> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=53256 --- src/glsl/opt_dead_code_local.cpp | 80 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/src/glsl/opt_dead_code_local.cpp b/src/glsl/opt_dead_code_local.cpp index 8c31802..7d51f0e 100644 --- a/src/glsl/opt_dead_code_local.cpp +++ b/src/glsl/opt_dead_code_local.cpp @@ -42,6 +42,69 @@ static bool debug = false; namespace { +static bool +is_array_deref_of_vector(ir_rvalue *ir) +{ + if (ir->ir_type == ir_type_dereference_array) { + ir_dereference_array *const d = ir->as_dereference_array(); + + assert(d != NULL); + return d->array->type->is_vector(); + } + + return false; +} + +/** + * Get the mask that may be generated by an assignment + * + * If the LHS of the assignment is anything other than an array dereference of + * a vector, the \c write_mask of the assignment is returned. If the LHS of + * the assignment is an array dereference, the write mask is a lie. The + * actual write mask is determined by the array index. If the array index is + * a constant, calculate the mask from that constant. + * + * If the index is not a constant, the function can operation in one of two + * modes. In the first mode, when \c want_availability_mask is \c true, it is + * assumed that any field of the vector may be written. This is used when + * adding an assignment to the assignment list. In the second mode, when + * \c want_availability_mask is \c false, it is assumed that no fields of the + * vector are written. This is used when trying to remove earlier assignments + * from the list. + */ +static int +may_set_mask(ir_assignment *ir, bool want_availability_mask) +{ + int mask = ir->write_mask; + + /* If the LHS is an array derefernce of a vector, try to figure out what + * the real write mask is. If the index is not a constant, assume that any + * element may be written. + */ + if (is_array_deref_of_vector(ir->lhs)) { + ir_dereference_array *const d = ir->lhs->as_dereference_array(); + ir_constant *const c = d->array_index->as_constant(); + + if (c != NULL) { + const int idx = (c != NULL) ? c->get_uint_component(0) : -1; + + if (idx >= 0 && idx <= 3) + mask = 1U << idx; + else + mask = 0; + } else { + /* Set the write-mask depending on the size of the vector. + */ + if (want_availability_mask) + mask = (1U << d->array->type->vector_elements) - 1; + else + mask = 0; + } + } + + return mask; +} + class assignment_entry : public exec_node { public: @@ -51,7 +114,7 @@ public: assert(ir); this->lhs = lhs; this->ir = ir; - this->available = ir->write_mask; + this->available = may_set_mask(ir, true); } ir_variable *lhs; @@ -185,7 +248,7 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments) if (entry->lhs != var) continue; - int remove = entry->available & ir->write_mask; + int remove = entry->available & may_set_mask(ir, false); if (debug) { printf("%s 0x%01x - 0x%01x = 0x%01x\n", var->name, @@ -201,13 +264,22 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments) printf("\n"); } - entry->ir->write_mask &= ~remove; entry->available &= ~remove; - if (entry->ir->write_mask == 0) { + if (entry->available == 0) { /* Delete the dead assignment. */ entry->ir->remove(); entry->remove(); } else { + /* If the LHS of the assignment is an array dereference of a + * vector, give up. It's either a constant index (that will + * be lowered to a regular write-mask before trying this + * optimization pass again), or it's a variable index (that + * can't have its write-mask reduced). + */ + if (is_array_deref_of_vector(entry->ir->lhs)) + continue; + + entry->ir->write_mask &= ~remove; void *mem_ctx = ralloc_parent(entry->ir); /* Reswizzle the RHS arguments according to the new * write_mask. -- 1.7.11.7 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev