Mesa (shader-work): glsl: teach structure splitting to split arrays, and never split in/outs
Luca Barbieri
lb at kemper.freedesktop.org
Wed Sep 8 02:42:16 UTC 2010
Module: Mesa
Branch: shader-work
Commit: 277312e184ebb54f4c5f119d199bf906fed0b8dc
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=277312e184ebb54f4c5f119d199bf906fed0b8dc
Author: Luca Barbieri <luca at luca-barbieri.com>
Date: Wed Sep 8 03:47:58 2010 +0200
glsl: teach structure splitting to split arrays, and never split in/outs
Currently structure splitting cannot split arrays, which makes
do_array_index_to_cond_assign useless.
This commit adds that capability.
Also, it prevents it from splitting in/out/inout variables, which were
incorrectly split.
It may be possible to split them if user-defined, but that will need
further changes and some way to make sure we link stages correctly.
---
src/glsl/ir_array_index_to_cond_assign.cpp | 2 +-
src/glsl/ir_structure_splitting.cpp | 149 ++++++++++++++++++++++------
src/glsl/ir_validate.cpp | 23 +++--
src/glsl/main.cpp | 3 +
4 files changed, 137 insertions(+), 40 deletions(-)
diff --git a/src/glsl/ir_array_index_to_cond_assign.cpp b/src/glsl/ir_array_index_to_cond_assign.cpp
index 641168a..517c4c0 100644
--- a/src/glsl/ir_array_index_to_cond_assign.cpp
+++ b/src/glsl/ir_array_index_to_cond_assign.cpp
@@ -80,7 +80,7 @@ struct switch_generator
test_indices = new(index) ir_constant(broadcast_index->type, &test_indices_data);
ir_rvalue* condition_val = new(index) ir_expression(ir_binop_equal,
- &glsl_type::bool_type[comps],
+ &glsl_type::bool_type[comps - 1],
broadcast_index,
test_indices);
ir_variable* condition = new(index) ir_variable(&glsl_type::bool_type[comps], "dereference_array_condition", ir_var_temporary);
diff --git a/src/glsl/ir_structure_splitting.cpp b/src/glsl/ir_structure_splitting.cpp
index ff3ec93..1925067 100644
--- a/src/glsl/ir_structure_splitting.cpp
+++ b/src/glsl/ir_structure_splitting.cpp
@@ -86,6 +86,7 @@ public:
virtual ir_visitor_status visit(ir_variable *);
virtual ir_visitor_status visit(ir_dereference_variable *);
virtual ir_visitor_status visit_enter(ir_dereference_record *);
+ virtual ir_visitor_status visit_enter(ir_dereference_array *);
virtual ir_visitor_status visit_enter(ir_assignment *);
virtual ir_visitor_status visit_enter(ir_function_signature *);
@@ -102,7 +103,9 @@ ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
{
assert(var);
- if (!var->type->is_record() || var->mode == ir_var_uniform)
+ printf("stru %s\n", var->name);
+ if ((!var->type->is_record() && !var->type->is_array())
+ || (var->mode != ir_var_auto && var->mode != ir_var_temporary))
return NULL;
foreach_iter(exec_list_iterator, iter, this->variable_list) {
@@ -149,6 +152,25 @@ ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
}
ir_visitor_status
+ir_structure_reference_visitor::visit_enter(ir_dereference_array *ir)
+{
+ ir->array_index->accept(this);
+ if(!ir->array_index->as_constant())
+ {
+ /* FINISHME: could produce and make use of information
+ * about possible values of the index
+ */
+ ir_variable *const var = ir->array->variable_referenced();
+ variable_entry2 *entry = this->get_variable_entry2(var);
+
+ if (entry)
+ entry->whole_structure_access++;
+ }
+
+ /* Don't descend into the ir_dereference_variable below. */
+ return visit_continue_with_parent;
+}
+ir_visitor_status
ir_structure_reference_visitor::visit_enter(ir_assignment *ir)
{
if (ir->lhs->as_dereference_variable() &&
@@ -198,7 +220,7 @@ ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
{
assert(var);
- if (!var->type->is_record())
+ if (!var->type->is_record() && !var->type->is_array())
return NULL;
foreach_iter(exec_list_iterator, iter, *this->variable_list) {
@@ -214,27 +236,62 @@ ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
void
ir_structure_splitting_visitor::split_deref(ir_dereference **deref)
{
- if ((*deref)->ir_type != ir_type_dereference_record)
- return;
-
- ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
- ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
- if (!deref_var)
- return;
-
- variable_entry2 *entry = get_splitting_entry(deref_var->var);
- if (!entry)
- return;
+ if ((*deref)->ir_type == ir_type_dereference_record)
+ {
+ ir_dereference_record *deref_record = (ir_dereference_record *)*deref;
+ ir_dereference_variable *deref_var = deref_record->record->as_dereference_variable();
+ if (!deref_var)
+ return;
+
+ variable_entry2 *entry = get_splitting_entry(deref_var->var);
+ if (!entry)
+ return;
+
+ unsigned int i;
+ for (i = 0; i < entry->var->type->length; i++) {
+ if (strcmp(deref_record->field,
+ entry->var->type->fields.structure[i].name) == 0)
+ break;
+ }
+ assert(i != entry->var->type->length);
- unsigned int i;
- for (i = 0; i < entry->var->type->length; i++) {
- if (strcmp(deref_record->field,
- entry->var->type->fields.structure[i].name) == 0)
- break;
+ *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
+ }
+ else if ((*deref)->ir_type == ir_type_dereference_array)
+ {
+ ir_dereference_array *deref_array = (ir_dereference_array*)*deref;
+ ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable();
+ if (!deref_var)
+ return;
+
+ variable_entry2 *entry = get_splitting_entry(deref_var->var);
+ if (!entry)
+ return;
+
+ ir_constant* index = deref_array->array_index->as_constant();
+ assert(index);
+ assert(index->type->is_scalar());
+ assert(index->type->base_type == GLSL_TYPE_INT || index->type->base_type == GLSL_TYPE_UINT);
+
+ unsigned i = index->value.u[0];
+ if(i < (unsigned)deref_var->var->type->length)
+ {
+ *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
+ }
+ else
+ {
+ ir_variable* undef = new(entry->mem_ctx) ir_variable((*deref)->type, "undef", ir_var_temporary);
+ base_ir->insert_before(undef);
+ *deref = new(entry->mem_ctx) ir_dereference_variable(undef);
+#if 0
+ /* FINISHME: add an "undef" value to the ir and use it, or perhaps just kill base_ir directly */
+ if(type->is_numeric() || type->is_boolean())
+ *deref = ir_constant::zero(entry->mem_ctx, (*deref)->type);
+ else
+ *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[0]);
+#endif
+ }
}
- assert(i != entry->var->type->length);
-
- *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
}
void
@@ -268,19 +325,30 @@ ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
if (lhs_entry) {
new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
- } else {
+ } else if(type->is_record()) {
new_lhs = new(mem_ctx)
ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
type->fields.structure[i].name);
- }
+ } else if(type->is_array()) {
+ new_lhs = new(mem_ctx)
+ ir_dereference_array(ir->lhs->clone(mem_ctx, NULL),
+ new(mem_ctx) ir_constant((int)i));
+ } else
+ assert(0);
if (rhs_entry) {
new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
- } else {
+ } else if(type->is_record()){
new_rhs = new(mem_ctx)
ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
type->fields.structure[i].name);
- }
+ } else if(type->is_array()) {
+ new_rhs = new(mem_ctx)
+ ir_dereference_array(ir->rhs->clone(mem_ctx, NULL),
+ new(mem_ctx) ir_constant((int)i));
+ } else
+ assert(0);
+
ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
new_rhs,
@@ -337,18 +405,39 @@ do_structure_splitting(exec_list *instructions)
ir_variable *,
type->length);
+ /* FINISHME: create these on demand */
for (unsigned int i = 0; i < entry->var->type->length; i++) {
- const char *name = talloc_asprintf(mem_ctx, "%s_%s",
+ const char *name;
+
+ if(type->is_record())
+ {
+ name = talloc_asprintf(mem_ctx, "%s_%s",
entry->var->name,
type->fields.structure[i].name);
- entry->components[i] =
- new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
- name,
- ir_var_temporary);
+ entry->components[i] =
+ new(entry->mem_ctx) ir_variable(type->fields.structure[i].type,
+ name,
+ ir_var_temporary);
+ }
+ else if(type->is_array())
+ {
+ name = talloc_asprintf(mem_ctx, "%s_%i",
+ entry->var->name,
+ i);
+
+ entry->components[i] =
+ new(entry->mem_ctx) ir_variable(type->fields.array,
+ name,
+ ir_var_temporary);
+ }
+ else
+ assert(0);
+
entry->var->insert_before(entry->components[i]);
}
+ printf("SPLIT %s\n", entry->var->name);
entry->var->remove();
}
diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp
index b3ea566..de31ad7 100644
--- a/src/glsl/ir_validate.cpp
+++ b/src/glsl/ir_validate.cpp
@@ -283,6 +283,17 @@ ir_validate::visit_leave(ir_expression *ir)
case ir_binop_min:
case ir_binop_max:
case ir_binop_pow:
+ if (ir->operands[0]->type->is_scalar())
+ assert(ir->operands[1]->type == ir->type);
+ else if (ir->operands[1]->type->is_scalar())
+ assert(ir->operands[0]->type == ir->type);
+ else if (ir->operands[0]->type->is_vector() &&
+ ir->operands[1]->type->is_vector()) {
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ assert(ir->operands[0]->type == ir->type);
+ }
+ break;
+
case ir_binop_less:
case ir_binop_greater:
case ir_binop_lequal:
@@ -293,15 +304,9 @@ ir_validate::visit_leave(ir_expression *ir)
* IR we want to do them for vectors instead to support the
* lessEqual() and friends builtins, and Mesa IR constructs
*/
- if (ir->operands[0]->type->is_scalar())
- assert(ir->operands[1]->type == ir->type);
- else if (ir->operands[1]->type->is_scalar())
- assert(ir->operands[0]->type == ir->type);
- else if (ir->operands[0]->type->is_vector() &&
- ir->operands[1]->type->is_vector()) {
- assert(ir->operands[0]->type == ir->operands[1]->type);
- assert(ir->operands[0]->type == ir->type);
- }
+ assert(ir->type->base_type == GLSL_TYPE_BOOL);
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ assert(ir->type->components() == ir->operands[0]->type->components());
break;
case ir_binop_all_equal:
diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp
index 8e73eb8..40c9781 100644
--- a/src/glsl/main.cpp
+++ b/src/glsl/main.cpp
@@ -180,6 +180,9 @@ compile_shader(struct gl_shader *shader)
progress = set_loop_controls(shader->ir, ls) || progress;
progress = unroll_loops(shader->ir, ls, 32) || progress;
delete ls;
+
+ progress = do_array_index_to_cond_assign(shader->ir) || progress;
+ progress = do_structure_splitting(shader->ir) || progress;
} while (progress);
validate_ir_tree(shader->ir);
More information about the mesa-commit
mailing list