[Mesa-dev] [PATCH v2] glsl: Fix handling of array dereferences of vectors in opt_dead_code_local
Ian Romanick
idr at freedesktop.org
Wed Jan 30 15:00:46 PST 2013
From: Ian Romanick <ian.d.romanick at 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.romanick at intel.com>
Cc: Chris Wolfe <cwolfe at chromium.org>
Cc: Eric Anholt <eric at anholt.net>
Cc: Kenneth Graunke <kenneth at 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
More information about the mesa-dev
mailing list