glsl: Replace atomic_ssbo and ssbo_atomic with atomic
[mesa.git] / src / glsl / opt_constant_variable.cpp
index 8068d0c1435fba86a2e09f2f48249a05285419d1..cdfbc34024379d4f1f390f87cc0687f9c04137d9 100644 (file)
 #include "ir_visitor.h"
 #include "ir_optimization.h"
 #include "glsl_types.h"
+#include "util/hash_table.h"
+
+namespace {
 
 struct assignment_entry {
-   exec_node link;
    int assignment_count;
    ir_variable *var;
    ir_constant *constval;
@@ -52,29 +54,32 @@ public:
    virtual ir_visitor_status visit_enter(ir_assignment *);
    virtual ir_visitor_status visit_enter(ir_call *);
 
-   exec_list list;
+   struct hash_table *ht;
 };
 
+} /* unnamed namespace */
+
 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;
 
-   foreach_list_typed(struct assignment_entry, entry, link, list) {
-      if (entry->var == var)
-        return entry;
+   if (hte) {
+      entry = (struct assignment_entry *) hte->data;
+   } 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;
 }
 
 ir_visitor_status
 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;
    return visit_continue;
 }
@@ -93,7 +98,7 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
    ir_constant *constval;
    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);
    entry->assignment_count++;
 
@@ -104,16 +109,20 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
    /* OK, now find if we actually have all the right conditions for
     * this to be a constant value assigned to the var.
     */
-   if (ir->condition) {
-      constval = ir->condition->constant_expression_value();
-      if (!constval || !constval->value.b[0])
-        return visit_continue;
-   }
+   if (ir->condition)
+      return visit_continue;
 
    ir_variable *var = ir->whole_variable_written();
    if (!var)
       return visit_continue;
 
+   /* Ignore buffer variables, since the underlying storage is shared
+    * and we can't be sure that this variable won't be written by another
+    * thread.
+    */
+   if (var->data.mode == ir_var_shader_storage)
+      return visit_continue;
+
    constval = ir->rhs->constant_expression_value();
    if (!constval)
       return visit_continue;
@@ -130,22 +139,33 @@ ir_constant_variable_visitor::visit_enter(ir_assignment *ir)
 ir_visitor_status
 ir_constant_variable_visitor::visit_enter(ir_call *ir)
 {
-   exec_list_iterator sig_iter = ir->get_callee()->parameters.iterator();
-   foreach_iter(exec_list_iterator, iter, *ir) {
-      ir_rvalue *param_rval = (ir_rvalue *)iter.get();
-      ir_variable *param = (ir_variable *)sig_iter.get();
-
-      if (param->mode == ir_var_out ||
-         param->mode == ir_var_inout) {
+   /* Mark any out parameters as assigned to */
+   foreach_two_lists(formal_node, &ir->callee->parameters,
+                     actual_node, &ir->actual_parameters) {
+      ir_rvalue *param_rval = (ir_rvalue *) actual_node;
+      ir_variable *param = (ir_variable *) formal_node;
+
+      if (param->data.mode == ir_var_function_out ||
+         param->data.mode == ir_var_function_inout) {
         ir_variable *var = param_rval->variable_referenced();
         struct assignment_entry *entry;
 
         assert(var);
-        entry = get_assignment_entry(var, &this->list);
+        entry = get_assignment_entry(var, this->ht);
         entry->assignment_count++;
       }
-      sig_iter.next();
    }
+
+   /* Mark the return storage as having been assigned to */
+   if (ir->return_deref != NULL) {
+      ir_variable *var = ir->return_deref->variable_referenced();
+      struct assignment_entry *entry;
+
+      assert(var);
+      entry = get_assignment_entry(var, this->ht);
+      entry->assignment_count++;
+   }
+
    return visit_continue;
 }
 
@@ -158,20 +178,22 @@ do_constant_variable(exec_list *instructions)
    bool progress = false;
    ir_constant_variable_visitor v;
 
+   v.ht = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+                                  _mesa_key_pointer_equal);
    v.run(instructions);
 
-   while (!v.list.is_empty()) {
-
-      struct assignment_entry *entry;
-      entry = exec_node_data(struct assignment_entry, v.list.head, link);
+   struct hash_entry *hte;
+   hash_table_foreach(v.ht, hte) {
+      struct assignment_entry *entry = (struct assignment_entry *) hte->data;
 
       if (entry->assignment_count == 1 && entry->constval && entry->our_scope) {
         entry->var->constant_value = entry->constval;
         progress = true;
       }
-      entry->link.remove();
+      hte->data = NULL;
       free(entry);
    }
+   _mesa_hash_table_destroy(v.ht, NULL);
 
    return progress;
 }
@@ -181,13 +203,10 @@ do_constant_variable_unlinked(exec_list *instructions)
 {
    bool progress = false;
 
-   foreach_iter(exec_list_iterator, iter, *instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
+   foreach_in_list(ir_instruction, ir, instructions) {
       ir_function *f = ir->as_function();
       if (f) {
-        foreach_iter(exec_list_iterator, sigiter, *f) {
-           ir_function_signature *sig =
-              (ir_function_signature *) sigiter.get();
+        foreach_in_list(ir_function_signature, sig, &f->signatures) {
            if (do_constant_variable(&sig->body))
               progress = true;
         }