free_entry(struct hash_entry *entry)
{
ir_variable_refcount_entry *ivre = (ir_variable_refcount_entry *) entry->data;
+
+ /* Free assignment list */
+ exec_node *n;
+ while ((n = ivre->assign_list.pop_head()) != NULL) {
+ struct assignment_entry *assignment_entry =
+ exec_node_data(struct assignment_entry, n, link);
+ free(assignment_entry);
+ }
+
delete ivre;
}
ir_variable_refcount_entry::ir_variable_refcount_entry(ir_variable *var)
{
this->var = var;
- assign = NULL;
assigned_count = 0;
declaration = false;
referenced_count = 0;
entry = this->get_variable_entry(ir->lhs->variable_referenced());
if (entry) {
entry->assigned_count++;
- if (entry->assign == NULL)
- entry->assign = ir;
+
+ /* Build a list for dead code optimisation. Don't add assignment if it
+ * was declared out of scope (outside the instruction stream). Also don't
+ * bother adding any more to the list if there are more references than
+ * assignments as this means the variable is used and won't be optimised
+ * out.
+ */
+ assert(entry->referenced_count >= entry->assigned_count);
+ if (entry->referenced_count == entry->assigned_count) {
+ struct assignment_entry *assignment_entry =
+ (struct assignment_entry *)calloc(1, sizeof(*assignment_entry));
+ assignment_entry->assign = ir;
+ entry->assign_list.push_head(&assignment_entry->link);
+ }
}
return visit_continue;
#include "ir_visitor.h"
#include "glsl_types.h"
+struct assignment_entry {
+ exec_node link;
+ ir_assignment *assign;
+};
+
class ir_variable_refcount_entry
{
public:
ir_variable_refcount_entry(ir_variable *var);
ir_variable *var; /* The key: the variable's pointer. */
- ir_assignment *assign; /* An assignment to the variable, if any */
+
+ /**
+ * List of assignments to the variable, if any.
+ * This is intended to be used for dead code optimisation and may
+ * not be a complete list.
+ */
+ exec_list assign_list;
/** Number of times the variable is referenced, including assignments. */
unsigned referenced_count;
|| !entry->declaration)
continue;
- if (entry->assign) {
- /* Remove a single dead assignment to the variable we found.
- * Don't do so if it's a shader or function output or a shader
- * storage variable though.
+ if (!entry->assign_list.is_empty()) {
+ /* Remove all the dead assignments to the variable we found.
+ * Don't do so if it's a shader or function output, though.
*/
if (entry->var->data.mode != ir_var_function_out &&
entry->var->data.mode != ir_var_function_inout &&
entry->var->data.mode != ir_var_shader_out &&
entry->var->data.mode != ir_var_shader_storage) {
- entry->assign->remove();
- progress = true;
- if (debug) {
- printf("Removed assignment to %s@%p\n",
- entry->var->name, (void *) entry->var);
- }
+ while (!entry->assign_list.is_empty()) {
+ struct assignment_entry *assignment_entry =
+ exec_node_data(struct assignment_entry,
+ entry->assign_list.head, link);
+
+ assignment_entry->assign->remove();
+
+ if (debug) {
+ printf("Removed assignment to %s@%p\n",
+ entry->var->name, (void *) entry->var);
+ }
+
+ assignment_entry->link.remove();
+ free(assignment_entry);
+ }
+ progress = true;
}
- } else {
+ }
+
+ if (entry->assign_list.is_empty()) {
/* If there are no assignments or references to the variable left,
* then we can remove its declaration.
*/
entry->referenced_count != 2)
continue;
- assert(assign == entry->assign);
-
/* Found a possibly graftable assignment. Now, walk through the
* rest of the BB seeing if the deref is here, and if nothing interfered with
* pasting its expression's values in between.