nir: Handle array-deref-of-vec in vars_to_ssa
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/7746 Reviewed-by: Karol Herbst <kherbst@redhat.com> Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22580>
This commit is contained in:

committed by
Marge Bot

parent
68c54c994a
commit
6bc8567bb9
@@ -173,7 +173,11 @@ get_deref_node_recur(nir_deref_instr *deref,
|
|||||||
return parent->children[deref->strct.index];
|
return parent->children[deref->strct.index];
|
||||||
|
|
||||||
case nir_deref_type_array: {
|
case nir_deref_type_array: {
|
||||||
if (nir_src_is_const(deref->arr.index)) {
|
if (glsl_type_is_vector_or_scalar(parent->type)) {
|
||||||
|
/* For an array deref of a vector, return the vector */
|
||||||
|
assert(glsl_type_is_vector(parent->type));
|
||||||
|
return parent;
|
||||||
|
} else if (nir_src_is_const(deref->arr.index)) {
|
||||||
uint32_t index = nir_src_as_uint(deref->arr.index);
|
uint32_t index = nir_src_as_uint(deref->arr.index);
|
||||||
/* This is possible if a loop unrolls and generates an
|
/* This is possible if a loop unrolls and generates an
|
||||||
* out-of-bounds offset. We need to handle this at least
|
* out-of-bounds offset. We need to handle this at least
|
||||||
@@ -252,7 +256,8 @@ foreach_deref_node_worker(struct deref_node *node, nir_deref_instr **path,
|
|||||||
struct lower_variables_state *state),
|
struct lower_variables_state *state),
|
||||||
struct lower_variables_state *state)
|
struct lower_variables_state *state)
|
||||||
{
|
{
|
||||||
if (*path == NULL) {
|
if (glsl_type_is_vector_or_scalar(node->type)) {
|
||||||
|
assert(*path == NULL || (*path)->deref_type == nir_deref_type_array);
|
||||||
cb(node, state);
|
cb(node, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -266,6 +271,9 @@ foreach_deref_node_worker(struct deref_node *node, nir_deref_instr **path,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case nir_deref_type_array: {
|
case nir_deref_type_array: {
|
||||||
|
if (glsl_type_is_vector_or_scalar(node->type))
|
||||||
|
return;
|
||||||
|
|
||||||
uint32_t index = nir_src_as_uint((*path)->arr.index);
|
uint32_t index = nir_src_as_uint((*path)->arr.index);
|
||||||
|
|
||||||
if (node->children[index]) {
|
if (node->children[index]) {
|
||||||
@@ -330,6 +338,13 @@ path_may_be_aliased_node(struct deref_node *node, nir_deref_instr **path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case nir_deref_type_array: {
|
case nir_deref_type_array: {
|
||||||
|
/* If the node is a vector, we consider it to not be aliased by any
|
||||||
|
* indirects for the purposes of this pass. We'll insert a pile of
|
||||||
|
* bcsel if needed to resolve indirects.
|
||||||
|
*/
|
||||||
|
if (glsl_type_is_vector_or_scalar(node->type))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!nir_src_is_const((*path)->arr.index))
|
if (!nir_src_is_const((*path)->arr.index))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -357,6 +372,10 @@ path_may_be_aliased_node(struct deref_node *node, nir_deref_instr **path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true if there are no indirects that can ever touch this deref.
|
/* Returns true if there are no indirects that can ever touch this deref.
|
||||||
|
*
|
||||||
|
* The one exception here is that we allow indirects which select components
|
||||||
|
* of vectors. These are handled by this pass by inserting the requisite
|
||||||
|
* pile of bcsel().
|
||||||
*
|
*
|
||||||
* For example, if the given deref is a[6].foo, then any uses of a[i].foo
|
* For example, if the given deref is a[6].foo, then any uses of a[i].foo
|
||||||
* would cause this to return false, but a[i].bar would not affect it
|
* would cause this to return false, but a[i].bar would not affect it
|
||||||
@@ -563,6 +582,24 @@ lower_copies_to_load_store(struct deref_node *node,
|
|||||||
node->copies = NULL;
|
node->copies = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nir_def *
|
||||||
|
deref_vec_component(nir_deref_instr *deref)
|
||||||
|
{
|
||||||
|
if (deref->deref_type != nir_deref_type_array) {
|
||||||
|
assert(glsl_type_is_vector_or_scalar(deref->type));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nir_deref_instr *parent = nir_deref_instr_parent(deref);
|
||||||
|
if (glsl_type_is_vector_or_scalar(parent->type)) {
|
||||||
|
assert(glsl_type_is_scalar(deref->type));
|
||||||
|
return deref->arr.index.ssa;
|
||||||
|
} else {
|
||||||
|
assert(glsl_type_is_vector_or_scalar(deref->type));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Performs variable renaming
|
/* Performs variable renaming
|
||||||
*
|
*
|
||||||
* This algorithm is very similar to the one outlined in "Efficiently
|
* This algorithm is very similar to the one outlined in "Efficiently
|
||||||
@@ -621,7 +658,15 @@ rename_variables(struct lower_variables_state *state)
|
|||||||
val = nir_mov(&b, val);
|
val = nir_mov(&b, val);
|
||||||
|
|
||||||
assert(val->bit_size == intrin->def.bit_size);
|
assert(val->bit_size == intrin->def.bit_size);
|
||||||
assert(val->num_components == intrin->def.num_components);
|
|
||||||
|
nir_def *comp = deref_vec_component(deref);
|
||||||
|
if (comp == NULL) {
|
||||||
|
assert(val->num_components == intrin->def.num_components);
|
||||||
|
} else {
|
||||||
|
assert(intrin->def.num_components == 1);
|
||||||
|
b.cursor = nir_before_instr(&intrin->instr);
|
||||||
|
val = nir_vector_extract(&b, val, comp);
|
||||||
|
}
|
||||||
|
|
||||||
nir_def_rewrite_uses(&intrin->def, val);
|
nir_def_rewrite_uses(&intrin->def, val);
|
||||||
nir_instr_remove(&intrin->instr);
|
nir_instr_remove(&intrin->instr);
|
||||||
@@ -646,13 +691,19 @@ rename_variables(struct lower_variables_state *state)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
assert(intrin->num_components ==
|
assert(intrin->num_components ==
|
||||||
glsl_get_vector_elements(node->type));
|
glsl_get_vector_elements(deref->type));
|
||||||
|
|
||||||
nir_def *new_def;
|
nir_def *new_def;
|
||||||
b.cursor = nir_before_instr(&intrin->instr);
|
b.cursor = nir_before_instr(&intrin->instr);
|
||||||
|
|
||||||
|
nir_def *comp = deref_vec_component(deref);
|
||||||
unsigned wrmask = nir_intrinsic_write_mask(intrin);
|
unsigned wrmask = nir_intrinsic_write_mask(intrin);
|
||||||
if (wrmask == (1 << intrin->num_components) - 1) {
|
if (comp != NULL) {
|
||||||
|
assert(wrmask == 1 && intrin->num_components == 1);
|
||||||
|
nir_def *old_def =
|
||||||
|
nir_phi_builder_value_get_block_def(node->pb_value, block);
|
||||||
|
new_def = nir_vector_insert(&b, old_def, value, comp);
|
||||||
|
} else if (wrmask == (1 << intrin->num_components) - 1) {
|
||||||
/* Whole variable store - just copy the source. Note that
|
/* Whole variable store - just copy the source. Note that
|
||||||
* intrin->num_components and value->num_components
|
* intrin->num_components and value->num_components
|
||||||
* may differ.
|
* may differ.
|
||||||
@@ -681,8 +732,6 @@ rename_variables(struct lower_variables_state *state)
|
|||||||
new_def = nir_vec_scalars(&b, srcs, intrin->num_components);
|
new_def = nir_vec_scalars(&b, srcs, intrin->num_components);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(new_def->num_components == intrin->num_components);
|
|
||||||
|
|
||||||
nir_phi_builder_value_set_block_def(node->pb_value, block, new_def);
|
nir_phi_builder_value_set_block_def(node->pb_value, block, new_def);
|
||||||
nir_instr_remove(&intrin->instr);
|
nir_instr_remove(&intrin->instr);
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user