glsl: Use hash tables in opt_constant_variable().

Cuts compile/link time of the fragment shader in bug #91857 by 31%
(31.79 -> 21.64).  It has over 8,000 variables so linked lists are
terrible.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91857
Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Thomas Helland <thomashelland90@gmail.com>
Reviewed-by: Timothy Arceri <t_arceri@yahoo.com.au>
Tested-by: Tapani Pälli <tapani.palli@intel.com>
This commit is contained in:
Kenneth Graunke 2015-09-05 00:22:57 -07:00
parent 4603723722
commit 2fc0ce293a

View file

@ -36,11 +36,11 @@
#include "ir_visitor.h" #include "ir_visitor.h"
#include "ir_optimization.h" #include "ir_optimization.h"
#include "glsl_types.h" #include "glsl_types.h"
#include "util/hash_table.h"
namespace { namespace {
struct assignment_entry { struct assignment_entry {
exec_node link;
int assignment_count; int assignment_count;
ir_variable *var; ir_variable *var;
ir_constant *constval; ir_constant *constval;
@ -54,31 +54,32 @@ public:
virtual ir_visitor_status visit_enter(ir_assignment *); virtual ir_visitor_status visit_enter(ir_assignment *);
virtual ir_visitor_status visit_enter(ir_call *); virtual ir_visitor_status visit_enter(ir_call *);
exec_list list; struct hash_table *ht;
}; };
} /* unnamed namespace */ } /* unnamed namespace */
static struct assignment_entry * static struct assignment_entry *
get_assignment_entry(ir_variable *var, exec_list *list) get_assignment_entry(ir_variable *var, struct hash_table *ht)
{ {
struct hash_entry *hte = _mesa_hash_table_search(ht, var);
struct assignment_entry *entry; struct assignment_entry *entry;
foreach_list_typed(struct assignment_entry, entry, link, list) { if (hte) {
if (entry->var == var) entry = (struct assignment_entry *) hte->data;
return entry; } else {
entry = (struct assignment_entry *) calloc(1, sizeof(*entry));
entry->var = var;
_mesa_hash_table_insert(ht, var, entry);
} }
entry = (struct assignment_entry *)calloc(1, sizeof(*entry));
entry->var = var;
list->push_head(&entry->link);
return entry; return entry;
} }
ir_visitor_status ir_visitor_status
ir_constant_variable_visitor::visit(ir_variable *ir) ir_constant_variable_visitor::visit(ir_variable *ir)
{ {
struct assignment_entry *entry = get_assignment_entry(ir, &this->list); struct assignment_entry *entry = get_assignment_entry(ir, this->ht);
entry->our_scope = true; entry->our_scope = true;
return visit_continue; return visit_continue;
} }
@ -97,7 +98,7 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
ir_constant *constval; ir_constant *constval;
struct assignment_entry *entry; struct assignment_entry *entry;
entry = get_assignment_entry(ir->lhs->variable_referenced(), &this->list); entry = get_assignment_entry(ir->lhs->variable_referenced(), this->ht);
assert(entry); assert(entry);
entry->assignment_count++; entry->assignment_count++;
@ -150,7 +151,7 @@ ir_constant_variable_visitor::visit_enter(ir_call *ir)
struct assignment_entry *entry; struct assignment_entry *entry;
assert(var); assert(var);
entry = get_assignment_entry(var, &this->list); entry = get_assignment_entry(var, this->ht);
entry->assignment_count++; entry->assignment_count++;
} }
} }
@ -161,7 +162,7 @@ ir_constant_variable_visitor::visit_enter(ir_call *ir)
struct assignment_entry *entry; struct assignment_entry *entry;
assert(var); assert(var);
entry = get_assignment_entry(var, &this->list); entry = get_assignment_entry(var, this->ht);
entry->assignment_count++; entry->assignment_count++;
} }
@ -177,20 +178,22 @@ do_constant_variable(exec_list *instructions)
bool progress = false; bool progress = false;
ir_constant_variable_visitor v; ir_constant_variable_visitor v;
v.ht = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
v.run(instructions); v.run(instructions);
while (!v.list.is_empty()) { struct hash_entry *hte;
hash_table_foreach(v.ht, hte) {
struct assignment_entry *entry; struct assignment_entry *entry = (struct assignment_entry *) hte->data;
entry = exec_node_data(struct assignment_entry, v.list.head, link);
if (entry->assignment_count == 1 && entry->constval && entry->our_scope) { if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
entry->var->constant_value = entry->constval; entry->var->constant_value = entry->constval;
progress = true; progress = true;
} }
entry->link.remove(); hte->data = NULL;
free(entry); free(entry);
} }
_mesa_hash_table_destroy(v.ht, NULL);
return progress; return progress;
} }