X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fopt_dead_code_local.cpp;h=4770fcff2ea90bfb0684d52b8a3e74ee221043f2;hb=0779f37e1589b0ba4f1443a889f34dd83607c117;hp=5689e7d20db70f5a1a4ba628ec3f350122f409fc;hpb=b2ddb93ff3b8c88682634ccdef247967e31fab84;p=mesa.git diff --git a/src/glsl/opt_dead_code_local.cpp b/src/glsl/opt_dead_code_local.cpp index 5689e7d20db..4770fcff2ea 100644 --- a/src/glsl/opt_dead_code_local.cpp +++ b/src/glsl/opt_dead_code_local.cpp @@ -40,19 +40,25 @@ static bool debug = false; +namespace { + class assignment_entry : public exec_node { public: - assignment_entry(ir_variable *lhs, ir_instruction *ir) + assignment_entry(ir_variable *lhs, ir_assignment *ir) { assert(lhs); assert(ir); this->lhs = lhs; this->ir = ir; + this->unused = ir->write_mask; } ir_variable *lhs; - ir_instruction *ir; + ir_assignment *ir; + + /* bitmask of xyzw channels written that haven't been used so far. */ + int unused; }; class kill_for_derefs_visitor : public ir_hierarchical_visitor { @@ -62,18 +68,61 @@ public: this->assignments = assignments; } + void use_channels(ir_variable *const var, int used) + { + foreach_in_list_safe(assignment_entry, entry, this->assignments) { + if (entry->lhs == var) { + if (var->type->is_scalar() || var->type->is_vector()) { + if (debug) + printf("used %s (0x%01x - 0x%01x)\n", entry->lhs->name, + entry->unused, used & 0xf); + entry->unused &= ~used; + if (!entry->unused) + entry->remove(); + } else { + if (debug) + printf("used %s\n", entry->lhs->name); + entry->remove(); + } + } + } + } + virtual ir_visitor_status visit(ir_dereference_variable *ir) { - ir_variable *const var = ir->variable_referenced(); + use_channels(ir->var, ~0); - foreach_iter(exec_list_iterator, iter, *this->assignments) { - assignment_entry *entry = (assignment_entry *)iter.get(); + return visit_continue; + } - if (entry->lhs == var) { - if (debug) - printf("kill %s\n", entry->lhs->name); - entry->remove(); - } + virtual ir_visitor_status visit(ir_swizzle *ir) + { + ir_dereference_variable *deref = ir->val->as_dereference_variable(); + if (!deref) + return visit_continue; + + int used = 0; + used |= 1 << ir->mask.x; + used |= 1 << ir->mask.y; + used |= 1 << ir->mask.z; + used |= 1 << ir->mask.w; + + use_channels(deref->var, used); + + return visit_continue_with_parent; + } + + virtual ir_visitor_status visit_leave(ir_emit_vertex *) + { + /* For the purpose of dead code elimination, emitting a vertex counts as + * "reading" all of the currently assigned output variables. + */ + foreach_in_list_safe(assignment_entry, entry, this->assignments) { + if (entry->lhs->data.mode == ir_var_shader_out) { + if (debug) + printf("kill %s\n", entry->lhs->name); + entry->remove(); + } } return visit_continue; @@ -105,6 +154,7 @@ public: ir_hierarchical_visitor *visitor; }; +} /* unnamed namespace */ /** * Adds an entry to the available copy list if it's a plain assignment @@ -129,39 +179,93 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments) var = ir->lhs->variable_referenced(); assert(var); - bool always_assign = true; - if (ir->condition) { - ir_constant *condition = ir->condition->as_constant(); - if (!condition || !condition->value.b[0]) - always_assign = false; - } - /* Now, check if we did a whole-variable assignment. */ - if (always_assign && (ir->whole_variable_written() != NULL)) { - /* We did a whole-variable assignment. So, any instruction in - * the assignment list with the same LHS is dead. - */ - if (debug) - printf("looking for %s to remove\n", var->name); - foreach_iter(exec_list_iterator, iter, *assignments) { - assignment_entry *entry = (assignment_entry *)iter.get(); + if (!ir->condition) { + ir_dereference_variable *deref_var = ir->lhs->as_dereference_variable(); - if (entry->lhs == var) { - if (debug) - printf("removing %s\n", var->name); - entry->ir->remove(); - entry->remove(); - progress = true; + /* If it's a vector type, we can do per-channel elimination of + * use of the RHS. + */ + if (deref_var && (deref_var->var->type->is_scalar() || + deref_var->var->type->is_vector())) { + + if (debug) + printf("looking for %s.0x%01x to remove\n", var->name, + ir->write_mask); + + foreach_in_list_safe(assignment_entry, entry, assignments) { + if (entry->lhs != var) + continue; + + int remove = entry->unused & ir->write_mask; + if (debug) { + printf("%s 0x%01x - 0x%01x = 0x%01x\n", + var->name, + entry->ir->write_mask, + remove, entry->ir->write_mask & ~remove); + } + if (remove) { + progress = true; + + if (debug) { + printf("rewriting:\n "); + entry->ir->print(); + printf("\n"); + } + + entry->ir->write_mask &= ~remove; + entry->unused &= ~remove; + if (entry->ir->write_mask == 0) { + /* Delete the dead assignment. */ + entry->ir->remove(); + entry->remove(); + } else { + void *mem_ctx = ralloc_parent(entry->ir); + /* Reswizzle the RHS arguments according to the new + * write_mask. + */ + unsigned components[4]; + unsigned channels = 0; + unsigned next = 0; + + for (int i = 0; i < 4; i++) { + if ((entry->ir->write_mask | remove) & (1 << i)) { + if (!(remove & (1 << i))) + components[channels++] = next; + next++; + } + } + + entry->ir->rhs = new(mem_ctx) ir_swizzle(entry->ir->rhs, + components, + channels); + if (debug) { + printf("to:\n "); + entry->ir->print(); + printf("\n"); + } + } + } + } + } else if (ir->whole_variable_written() != NULL) { + /* We did a whole-variable assignment. So, any instruction in + * the assignment list with the same LHS is dead. + */ + if (debug) + printf("looking for %s to remove\n", var->name); + foreach_in_list_safe(assignment_entry, entry, assignments) { + if (entry->lhs == var) { + if (debug) + printf("removing %s\n", var->name); + entry->ir->remove(); + entry->remove(); + progress = true; + } } } } - /* Add this instruction to the assignment list available to be removed. - * But not if the assignment has other side effects. - */ - if (ir_has_call(ir)) - return progress; - + /* Add this instruction to the assignment list available to be removed. */ assignment_entry *entry = new(ctx) assignment_entry(var, ir); assignments->push_tail(entry); @@ -169,10 +273,8 @@ process_assignment(void *ctx, ir_assignment *ir, exec_list *assignments) printf("add %s\n", var->name); printf("current entries\n"); - foreach_iter(exec_list_iterator, iter, *assignments) { - assignment_entry *entry = (assignment_entry *)iter.get(); - - printf(" %s\n", entry->lhs->name); + foreach_in_list(assignment_entry, entry, assignments) { + printf(" %s (0x%01x)\n", entry->lhs->name, entry->unused); } } @@ -190,7 +292,7 @@ dead_code_local_basic_block(ir_instruction *first, bool *out_progress = (bool *)data; bool progress = false; - void *ctx = talloc_new(NULL); + void *ctx = ralloc_context(NULL); /* Safe looping, since process_assignment */ for (ir = first, ir_next = (ir_instruction *)first->next;; ir = ir_next, ir_next = (ir_instruction *)ir->next) { @@ -212,7 +314,7 @@ dead_code_local_basic_block(ir_instruction *first, break; } *out_progress = progress; - talloc_free(ctx); + ralloc_free(ctx); } /**