diff options
-rw-r--r-- | src/glsl/nir/nir_lower_variables.c | 95 |
1 files changed, 69 insertions, 26 deletions
diff --git a/src/glsl/nir/nir_lower_variables.c b/src/glsl/nir/nir_lower_variables.c index 2609fbe138..bae10b0d4e 100644 --- a/src/glsl/nir/nir_lower_variables.c +++ b/src/glsl/nir/nir_lower_variables.c @@ -751,32 +751,37 @@ def_stack_push(struct deref_node *node, nir_ssa_def *def, *(++node->def_stack_tail) = def; } -/** Retrieves the SSA definition associated with the given node that - * reaches the current point in the program - * - * If the SSA def on the top of the stack is in the given block or some - * other block that dominates the given block, then the top of the stack is - * returned. Otherwise, the stack is popped until we get to an SSA - * definition that dominates the given block and that is returned. If we - * pop the stack all the way to empty, then we return the constant +/* Pop the top of the def stack if it's in the given block */ +static void +def_stack_pop_if_in_block(struct deref_node *node, nir_block *block) +{ + /* If we're popping, then we have presumably pushed at some time in the + * past so this should exist. + */ + assert(node->def_stack != NULL); + + /* The stack is already empty. Do nothing. */ + if (node->def_stack_tail < node->def_stack) + return; + + nir_ssa_def *def = *node->def_stack_tail; + if (def->parent_instr->block == block) + node->def_stack_tail--; +} + +/** Retrieves the SSA definition on the top of the stack for the given + * node, if one exists. If the stack is empty, then we return the constant * initializer (if it exists) or an SSA undef. */ static nir_ssa_def * get_ssa_def_for_block(struct deref_node *node, nir_block *block, struct lower_variables_state *state) { - if (node->def_stack) { - while (node->def_stack_tail >= node->def_stack) { - nir_ssa_def *def = *node->def_stack_tail; - - for (nir_block *dom = block; dom != NULL; dom = dom->imm_dom) { - if (def->parent_instr->block == dom) - return def; - } - - node->def_stack_tail--; - } - } + /* If we have something on the stack, go ahead and return it. We're + * assuming that the top of the stack dominates the given block. + */ + if (node->def_stack && node->def_stack_tail >= node->def_stack) + return *node->def_stack_tail; /* If we got here then we don't have a definition that dominates the * given block. This means that we need to add an undef and use that. @@ -825,11 +830,8 @@ add_phi_sources(nir_block *block, nir_block *pred, * * This algorithm is very similar to the one outlined in "Efficiently * Computing Static Single Assignment Form and the Control Dependence - * Graph" by Cytron et. al. The primary difference is in how the stacks of - * SSA definitions are handled. In the Cytron paper, they explicitly pop - * the old elements off the stack after visiting the dominance children. - * In our algorithm, popping old elements off the stack is implicitly - * handled by get_ssa_def_for_block. + * Graph" by Cytron et. al. The primary difference is that we only put one + * SSA def on the stack per block. */ static bool rename_variables_block(nir_block *block, struct lower_variables_state *state) @@ -943,9 +945,12 @@ rename_variables_block(nir_block *block, struct lower_variables_state *state) intrin->num_components, NULL); nir_instr_insert_before(&intrin->instr, &mov->instr); - nir_instr_remove(&intrin->instr); def_stack_push(node, &mov->dest.dest.ssa, state); + + /* We'll wait to remove the unstruction until the next pass + * where we pop the node we just pushed back off the stack. + */ break; } @@ -963,6 +968,44 @@ rename_variables_block(nir_block *block, struct lower_variables_state *state) for (unsigned i = 0; i < block->num_dom_children; ++i) rename_variables_block(block->dom_children[i], state); + /* Now we iterate over the instructions and pop off any SSA defs that we + * pushed in the first loop. + */ + nir_foreach_instr_safe(block, instr) { + if (instr->type == nir_instr_type_phi) { + nir_phi_instr *phi = nir_instr_as_phi(instr); + + struct hash_entry *entry = + _mesa_hash_table_search(state->phi_table, phi); + + /* This can happen if we already have phi nodes in the program + * that were not created in this pass. + */ + if (!entry) + continue; + + struct deref_node *node = entry->data; + + def_stack_pop_if_in_block(node, block); + } else if (instr->type == nir_instr_type_intrinsic) { + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + + if (intrin->intrinsic != nir_intrinsic_store_var) + continue; + + struct deref_node *node = get_deref_node(intrin->variables[0], + false, state); + if (!node) + continue; + + if (!node->lower_to_ssa) + continue; + + def_stack_pop_if_in_block(node, block); + nir_instr_remove(&intrin->instr); + } + } + return true; } |