diff options
Diffstat (limited to 'mesalib/src/glsl/opt_structure_splitting.cpp')
-rw-r--r-- | mesalib/src/glsl/opt_structure_splitting.cpp | 739 |
1 files changed, 372 insertions, 367 deletions
diff --git a/mesalib/src/glsl/opt_structure_splitting.cpp b/mesalib/src/glsl/opt_structure_splitting.cpp index d08a5cee1..6dd228e4e 100644 --- a/mesalib/src/glsl/opt_structure_splitting.cpp +++ b/mesalib/src/glsl/opt_structure_splitting.cpp @@ -1,367 +1,372 @@ -/*
- * Copyright © 2010 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.
- */
-
-/**
- * \file opt_structure_splitting.cpp
- *
- * If a structure is only ever referenced by its components, then
- * split those components out to individual variables so they can be
- * handled normally by other optimization passes.
- *
- * This skips structures like uniforms, which need to be accessible as
- * structures for their access by the GL.
- */
-
-#include "ir.h"
-#include "ir_visitor.h"
-#include "ir_print_visitor.h"
-#include "ir_rvalue_visitor.h"
-#include "glsl_types.h"
-
-static bool debug = false;
-
-// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined
-// function) with the variable_entry class seen in ir_variable_refcount.h
-// Perhaps we can use the one in ir_variable_refcount.h and make this class
-// here go away?
-class variable_entry2 : public exec_node
-{
-public:
- variable_entry2(ir_variable *var)
- {
- this->var = var;
- this->whole_structure_access = 0;
- this->declaration = false;
- this->components = NULL;
- this->mem_ctx = NULL;
- }
-
- ir_variable *var; /* The key: the variable's pointer. */
-
- /** Number of times the variable is referenced, including assignments. */
- unsigned whole_structure_access;
-
- bool declaration; /* If the variable had a decl in the instruction stream */
-
- ir_variable **components;
-
- /** ralloc_parent(this->var) -- the shader's ralloc context. */
- void *mem_ctx;
-};
-
-
-class ir_structure_reference_visitor : public ir_hierarchical_visitor {
-public:
- ir_structure_reference_visitor(void)
- {
- this->mem_ctx = ralloc_context(NULL);
- this->variable_list.make_empty();
- }
-
- ~ir_structure_reference_visitor(void)
- {
- ralloc_free(mem_ctx);
- }
-
- 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_assignment *);
- virtual ir_visitor_status visit_enter(ir_function_signature *);
-
- variable_entry2 *get_variable_entry2(ir_variable *var);
-
- /* List of variable_entry */
- exec_list variable_list;
-
- void *mem_ctx;
-};
-
-variable_entry2 *
-ir_structure_reference_visitor::get_variable_entry2(ir_variable *var)
-{
- assert(var);
-
- if (!var->type->is_record() || var->mode == ir_var_uniform)
- return NULL;
-
- foreach_iter(exec_list_iterator, iter, this->variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
- if (entry->var == var)
- return entry;
- }
-
- variable_entry2 *entry = new(mem_ctx) variable_entry2(var);
- this->variable_list.push_tail(entry);
- return entry;
-}
-
-
-ir_visitor_status
-ir_structure_reference_visitor::visit(ir_variable *ir)
-{
- variable_entry2 *entry = this->get_variable_entry2(ir);
-
- if (entry)
- entry->declaration = true;
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit(ir_dereference_variable *ir)
-{
- ir_variable *const var = ir->variable_referenced();
- variable_entry2 *entry = this->get_variable_entry2(var);
-
- if (entry)
- entry->whole_structure_access++;
-
- return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir)
-{
- (void) ir;
- /* 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 there are no structure references yet, no need to bother with
- * processing the expression tree.
- */
- if (this->variable_list.is_empty())
- return visit_continue_with_parent;
-
- if (ir->lhs->as_dereference_variable() &&
- ir->rhs->as_dereference_variable() &&
- !ir->condition) {
- /* We'll split copies of a structure to copies of components, so don't
- * descend to the ir_dereference_variables.
- */
- return visit_continue_with_parent;
- }
- return visit_continue;
-}
-
-ir_visitor_status
-ir_structure_reference_visitor::visit_enter(ir_function_signature *ir)
-{
- /* We don't want to descend into the function parameters and
- * dead-code eliminate them, so just accept the body here.
- */
- visit_list_elements(this, &ir->body);
- return visit_continue_with_parent;
-}
-
-class ir_structure_splitting_visitor : public ir_rvalue_visitor {
-public:
- ir_structure_splitting_visitor(exec_list *vars)
- {
- this->variable_list = vars;
- }
-
- virtual ~ir_structure_splitting_visitor()
- {
- }
-
- virtual ir_visitor_status visit_leave(ir_assignment *);
-
- void split_deref(ir_dereference **deref);
- void handle_rvalue(ir_rvalue **rvalue);
- variable_entry2 *get_splitting_entry(ir_variable *var);
-
- exec_list *variable_list;
- void *mem_ctx;
-};
-
-variable_entry2 *
-ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var)
-{
- assert(var);
-
- if (!var->type->is_record())
- return NULL;
-
- foreach_iter(exec_list_iterator, iter, *this->variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
- if (entry->var == var) {
- return entry;
- }
- }
-
- return NULL;
-}
-
-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;
-
- 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);
-
- *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]);
-}
-
-void
-ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
-{
- if (!*rvalue)
- return;
-
- ir_dereference *deref = (*rvalue)->as_dereference();
-
- if (!deref)
- return;
-
- split_deref(&deref);
- *rvalue = deref;
-}
-
-ir_visitor_status
-ir_structure_splitting_visitor::visit_leave(ir_assignment *ir)
-{
- ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
- ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
- variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
- variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
- const glsl_type *type = ir->rhs->type;
-
- if ((lhs_entry || rhs_entry) && !ir->condition) {
- for (unsigned int i = 0; i < type->length; i++) {
- ir_dereference *new_lhs, *new_rhs;
- void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx;
-
- if (lhs_entry) {
- new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]);
- } else {
- new_lhs = new(mem_ctx)
- ir_dereference_record(ir->lhs->clone(mem_ctx, NULL),
- type->fields.structure[i].name);
- }
-
- if (rhs_entry) {
- new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]);
- } else {
- new_rhs = new(mem_ctx)
- ir_dereference_record(ir->rhs->clone(mem_ctx, NULL),
- type->fields.structure[i].name);
- }
-
- ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
- new_rhs,
- NULL));
- }
- ir->remove();
- } else {
- handle_rvalue(&ir->rhs);
- split_deref(&ir->lhs);
- }
-
- handle_rvalue(&ir->condition);
-
- return visit_continue;
-}
-
-bool
-do_structure_splitting(exec_list *instructions)
-{
- ir_structure_reference_visitor refs;
-
- visit_list_elements(&refs, instructions);
-
- /* Trim out variables we can't split. */
- foreach_iter(exec_list_iterator, iter, refs.variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
-
- if (debug) {
- printf("structure %s@%p: decl %d, whole_access %d\n",
- entry->var->name, (void *) entry->var, entry->declaration,
- entry->whole_structure_access);
- }
-
- if (!entry->declaration || entry->whole_structure_access) {
- entry->remove();
- }
- }
-
- if (refs.variable_list.is_empty())
- return false;
-
- void *mem_ctx = ralloc_context(NULL);
-
- /* Replace the decls of the structures to be split with their split
- * components.
- */
- foreach_iter(exec_list_iterator, iter, refs.variable_list) {
- variable_entry2 *entry = (variable_entry2 *)iter.get();
- const struct glsl_type *type = entry->var->type;
-
- entry->mem_ctx = ralloc_parent(entry->var);
-
- entry->components = ralloc_array(mem_ctx,
- ir_variable *,
- type->length);
-
- for (unsigned int i = 0; i < entry->var->type->length; i++) {
- const char *name = ralloc_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->var->insert_before(entry->components[i]);
- }
-
- entry->var->remove();
- }
-
- ir_structure_splitting_visitor split(&refs.variable_list);
- visit_list_elements(&split, instructions);
-
- ralloc_free(mem_ctx);
-
- return true;
-}
+/* + * Copyright © 2010 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. + */ + +/** + * \file opt_structure_splitting.cpp + * + * If a structure is only ever referenced by its components, then + * split those components out to individual variables so they can be + * handled normally by other optimization passes. + * + * This skips structures like uniforms, which need to be accessible as + * structures for their access by the GL. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_print_visitor.h" +#include "ir_rvalue_visitor.h" +#include "glsl_types.h" + +static bool debug = false; + +// XXX using variable_entry2 here to avoid collision (MSVC multiply-defined +// function) with the variable_entry class seen in ir_variable_refcount.h +// Perhaps we can use the one in ir_variable_refcount.h and make this class +// here go away? +class variable_entry2 : public exec_node +{ +public: + variable_entry2(ir_variable *var) + { + this->var = var; + this->whole_structure_access = 0; + this->declaration = false; + this->components = NULL; + this->mem_ctx = NULL; + } + + ir_variable *var; /* The key: the variable's pointer. */ + + /** Number of times the variable is referenced, including assignments. */ + unsigned whole_structure_access; + + /* If the variable had a decl we can work with in the instruction + * stream. We can't do splitting on function arguments, which + * don't get this variable set. + */ + bool declaration; + + ir_variable **components; + + /** ralloc_parent(this->var) -- the shader's ralloc context. */ + void *mem_ctx; +}; + + +class ir_structure_reference_visitor : public ir_hierarchical_visitor { +public: + ir_structure_reference_visitor(void) + { + this->mem_ctx = ralloc_context(NULL); + this->variable_list.make_empty(); + } + + ~ir_structure_reference_visitor(void) + { + ralloc_free(mem_ctx); + } + + 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_assignment *); + virtual ir_visitor_status visit_enter(ir_function_signature *); + + variable_entry2 *get_variable_entry2(ir_variable *var); + + /* List of variable_entry */ + exec_list variable_list; + + void *mem_ctx; +}; + +variable_entry2 * +ir_structure_reference_visitor::get_variable_entry2(ir_variable *var) +{ + assert(var); + + if (!var->type->is_record() || var->mode == ir_var_uniform) + return NULL; + + foreach_iter(exec_list_iterator, iter, this->variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + if (entry->var == var) + return entry; + } + + variable_entry2 *entry = new(mem_ctx) variable_entry2(var); + this->variable_list.push_tail(entry); + return entry; +} + + +ir_visitor_status +ir_structure_reference_visitor::visit(ir_variable *ir) +{ + variable_entry2 *entry = this->get_variable_entry2(ir); + + if (entry) + entry->declaration = true; + + return visit_continue; +} + +ir_visitor_status +ir_structure_reference_visitor::visit(ir_dereference_variable *ir) +{ + ir_variable *const var = ir->variable_referenced(); + variable_entry2 *entry = this->get_variable_entry2(var); + + if (entry) + entry->whole_structure_access++; + + return visit_continue; +} + +ir_visitor_status +ir_structure_reference_visitor::visit_enter(ir_dereference_record *ir) +{ + (void) ir; + /* 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 there are no structure references yet, no need to bother with + * processing the expression tree. + */ + if (this->variable_list.is_empty()) + return visit_continue_with_parent; + + if (ir->lhs->as_dereference_variable() && + ir->rhs->as_dereference_variable() && + !ir->condition) { + /* We'll split copies of a structure to copies of components, so don't + * descend to the ir_dereference_variables. + */ + return visit_continue_with_parent; + } + return visit_continue; +} + +ir_visitor_status +ir_structure_reference_visitor::visit_enter(ir_function_signature *ir) +{ + /* We don't have logic for structure-splitting function arguments, + * so just look at the body instructions and not the parameter + * declarations. + */ + visit_list_elements(this, &ir->body); + return visit_continue_with_parent; +} + +class ir_structure_splitting_visitor : public ir_rvalue_visitor { +public: + ir_structure_splitting_visitor(exec_list *vars) + { + this->variable_list = vars; + } + + virtual ~ir_structure_splitting_visitor() + { + } + + virtual ir_visitor_status visit_leave(ir_assignment *); + + void split_deref(ir_dereference **deref); + void handle_rvalue(ir_rvalue **rvalue); + variable_entry2 *get_splitting_entry(ir_variable *var); + + exec_list *variable_list; + void *mem_ctx; +}; + +variable_entry2 * +ir_structure_splitting_visitor::get_splitting_entry(ir_variable *var) +{ + assert(var); + + if (!var->type->is_record()) + return NULL; + + foreach_iter(exec_list_iterator, iter, *this->variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + if (entry->var == var) { + return entry; + } + } + + return NULL; +} + +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; + + 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); + + *deref = new(entry->mem_ctx) ir_dereference_variable(entry->components[i]); +} + +void +ir_structure_splitting_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_dereference *deref = (*rvalue)->as_dereference(); + + if (!deref) + return; + + split_deref(&deref); + *rvalue = deref; +} + +ir_visitor_status +ir_structure_splitting_visitor::visit_leave(ir_assignment *ir) +{ + ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable(); + ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable(); + variable_entry2 *lhs_entry = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL; + variable_entry2 *rhs_entry = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL; + const glsl_type *type = ir->rhs->type; + + if ((lhs_entry || rhs_entry) && !ir->condition) { + for (unsigned int i = 0; i < type->length; i++) { + ir_dereference *new_lhs, *new_rhs; + void *mem_ctx = lhs_entry ? lhs_entry->mem_ctx : rhs_entry->mem_ctx; + + if (lhs_entry) { + new_lhs = new(mem_ctx) ir_dereference_variable(lhs_entry->components[i]); + } else { + new_lhs = new(mem_ctx) + ir_dereference_record(ir->lhs->clone(mem_ctx, NULL), + type->fields.structure[i].name); + } + + if (rhs_entry) { + new_rhs = new(mem_ctx) ir_dereference_variable(rhs_entry->components[i]); + } else { + new_rhs = new(mem_ctx) + ir_dereference_record(ir->rhs->clone(mem_ctx, NULL), + type->fields.structure[i].name); + } + + ir->insert_before(new(mem_ctx) ir_assignment(new_lhs, + new_rhs, + NULL)); + } + ir->remove(); + } else { + handle_rvalue(&ir->rhs); + split_deref(&ir->lhs); + } + + handle_rvalue(&ir->condition); + + return visit_continue; +} + +bool +do_structure_splitting(exec_list *instructions) +{ + ir_structure_reference_visitor refs; + + visit_list_elements(&refs, instructions); + + /* Trim out variables we can't split. */ + foreach_iter(exec_list_iterator, iter, refs.variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + + if (debug) { + printf("structure %s@%p: decl %d, whole_access %d\n", + entry->var->name, (void *) entry->var, entry->declaration, + entry->whole_structure_access); + } + + if (!entry->declaration || entry->whole_structure_access) { + entry->remove(); + } + } + + if (refs.variable_list.is_empty()) + return false; + + void *mem_ctx = ralloc_context(NULL); + + /* Replace the decls of the structures to be split with their split + * components. + */ + foreach_iter(exec_list_iterator, iter, refs.variable_list) { + variable_entry2 *entry = (variable_entry2 *)iter.get(); + const struct glsl_type *type = entry->var->type; + + entry->mem_ctx = ralloc_parent(entry->var); + + entry->components = ralloc_array(mem_ctx, + ir_variable *, + type->length); + + for (unsigned int i = 0; i < entry->var->type->length; i++) { + const char *name = ralloc_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->var->insert_before(entry->components[i]); + } + + entry->var->remove(); + } + + ir_structure_splitting_visitor split(&refs.variable_list); + visit_list_elements(&split, instructions); + + ralloc_free(mem_ctx); + + return true; +} |