spirv: Emit NIR deref instructions on-the-fly
This simplifies our deref handling by emitting the actual NIR deref instructions on-the-fly instead of of building up a deref chain and then emitting them at the last moment. In order for this to work with the parts of the compiler that assume they can chase deref chains, we have to run nir_rematerialize_derefs_in_use_blocks_impl to put the derefs back in the right places. Otherwise, in cases such as loop continues where the SPIR-V blocks are not in the same order as the NIR blocks, we may end up with a deref chain with a parent that does not dominate it's child and nir_repair_ssa_impl will insert phis in the deref chain. Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com> Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
This commit is contained in:

committed by
Jason Ekstrand

parent
c59f07684c
commit
639c236e74
@@ -1053,6 +1053,8 @@ vtn_function_emit(struct vtn_builder *b, struct vtn_function *func,
|
|||||||
vtn_foreach_instruction(b, func->start_block->label, func->end,
|
vtn_foreach_instruction(b, func->start_block->label, func->end,
|
||||||
vtn_handle_phi_second_pass);
|
vtn_handle_phi_second_pass);
|
||||||
|
|
||||||
|
nir_rematerialize_derefs_in_use_blocks_impl(func->impl);
|
||||||
|
|
||||||
/* Continue blocks for loops get inserted before the body of the loop
|
/* Continue blocks for loops get inserted before the body of the loop
|
||||||
* but instructions in the continue may use SSA defs in the loop body.
|
* but instructions in the continue may use SSA defs in the loop body.
|
||||||
* Therefore, we need to repair SSA to insert the needed phi nodes.
|
* Therefore, we need to repair SSA to insert the needed phi nodes.
|
||||||
|
@@ -443,20 +443,9 @@ struct vtn_pointer {
|
|||||||
*/
|
*/
|
||||||
struct vtn_variable *var;
|
struct vtn_variable *var;
|
||||||
|
|
||||||
/** The deref at the base of the chain
|
/** The NIR deref corresponding to this pointer */
|
||||||
*
|
|
||||||
* This field may be NULL if the pointer uses a (block_index, offset) pair
|
|
||||||
* instead of an access chain or if the access chain starts at a variable.
|
|
||||||
*/
|
|
||||||
nir_deref_instr *deref;
|
nir_deref_instr *deref;
|
||||||
|
|
||||||
/** An access chain describing how to get from var to the referenced data
|
|
||||||
*
|
|
||||||
* This field may be NULL if the pointer references the entire variable or
|
|
||||||
* if a (block_index, offset) pair is used instead of an access chain.
|
|
||||||
*/
|
|
||||||
struct vtn_access_chain *chain;
|
|
||||||
|
|
||||||
/** A (block_index, offset) pair representing a UBO or SSBO position. */
|
/** A (block_index, offset) pair representing a UBO or SSBO position. */
|
||||||
struct nir_ssa_def *block_index;
|
struct nir_ssa_def *block_index;
|
||||||
struct nir_ssa_def *offset;
|
struct nir_ssa_def *offset;
|
||||||
|
@@ -43,21 +43,6 @@ vtn_access_chain_create(struct vtn_builder *b, unsigned length)
|
|||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct vtn_access_chain *
|
|
||||||
vtn_access_chain_extend(struct vtn_builder *b, struct vtn_access_chain *old,
|
|
||||||
unsigned new_ids)
|
|
||||||
{
|
|
||||||
struct vtn_access_chain *chain;
|
|
||||||
|
|
||||||
unsigned old_len = old ? old->length : 0;
|
|
||||||
chain = vtn_access_chain_create(b, old_len + new_ids);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < old_len; i++)
|
|
||||||
chain->link[i] = old->link[i];
|
|
||||||
|
|
||||||
return chain;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
vtn_pointer_uses_ssa_offset(struct vtn_builder *b,
|
vtn_pointer_uses_ssa_offset(struct vtn_builder *b,
|
||||||
struct vtn_pointer *ptr)
|
struct vtn_pointer *ptr)
|
||||||
@@ -82,29 +67,42 @@ vtn_pointer_is_external_block(struct vtn_builder *b,
|
|||||||
|
|
||||||
/* Dereference the given base pointer by the access chain */
|
/* Dereference the given base pointer by the access chain */
|
||||||
static struct vtn_pointer *
|
static struct vtn_pointer *
|
||||||
vtn_access_chain_pointer_dereference(struct vtn_builder *b,
|
vtn_nir_deref_pointer_dereference(struct vtn_builder *b,
|
||||||
struct vtn_pointer *base,
|
struct vtn_pointer *base,
|
||||||
struct vtn_access_chain *deref_chain)
|
struct vtn_access_chain *deref_chain)
|
||||||
{
|
{
|
||||||
struct vtn_access_chain *chain =
|
|
||||||
vtn_access_chain_extend(b, base->chain, deref_chain->length);
|
|
||||||
struct vtn_type *type = base->type;
|
struct vtn_type *type = base->type;
|
||||||
enum gl_access_qualifier access = base->access;
|
enum gl_access_qualifier access = base->access;
|
||||||
|
|
||||||
|
nir_deref_instr *tail;
|
||||||
|
if (base->deref) {
|
||||||
|
tail = base->deref;
|
||||||
|
} else {
|
||||||
|
assert(base->var && base->var->var);
|
||||||
|
tail = nir_build_deref_var(&b->nb, base->var->var);
|
||||||
|
}
|
||||||
|
|
||||||
/* OpPtrAccessChain is only allowed on things which support variable
|
/* OpPtrAccessChain is only allowed on things which support variable
|
||||||
* pointers. For everything else, the client is expected to just pass us
|
* pointers. For everything else, the client is expected to just pass us
|
||||||
* the right access chain.
|
* the right access chain.
|
||||||
*/
|
*/
|
||||||
vtn_assert(!deref_chain->ptr_as_array);
|
vtn_assert(!deref_chain->ptr_as_array);
|
||||||
|
|
||||||
unsigned start = base->chain ? base->chain->length : 0;
|
|
||||||
for (unsigned i = 0; i < deref_chain->length; i++) {
|
for (unsigned i = 0; i < deref_chain->length; i++) {
|
||||||
chain->link[start + i] = deref_chain->link[i];
|
|
||||||
|
|
||||||
if (glsl_type_is_struct(type->type)) {
|
if (glsl_type_is_struct(type->type)) {
|
||||||
vtn_assert(deref_chain->link[i].mode == vtn_access_mode_literal);
|
vtn_assert(deref_chain->link[i].mode == vtn_access_mode_literal);
|
||||||
type = type->members[deref_chain->link[i].id];
|
unsigned idx = deref_chain->link[i].id;
|
||||||
|
tail = nir_build_deref_struct(&b->nb, tail, idx);
|
||||||
|
type = type->members[idx];
|
||||||
} else {
|
} else {
|
||||||
|
nir_ssa_def *index;
|
||||||
|
if (deref_chain->link[i].mode == vtn_access_mode_literal) {
|
||||||
|
index = nir_imm_int(&b->nb, deref_chain->link[i].id);
|
||||||
|
} else {
|
||||||
|
vtn_assert(deref_chain->link[i].mode == vtn_access_mode_id);
|
||||||
|
index = vtn_ssa_value(b, deref_chain->link[i].id)->def;
|
||||||
|
}
|
||||||
|
tail = nir_build_deref_array(&b->nb, tail, index);
|
||||||
type = type->array_element;
|
type = type->array_element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,8 +113,7 @@ vtn_access_chain_pointer_dereference(struct vtn_builder *b,
|
|||||||
ptr->mode = base->mode;
|
ptr->mode = base->mode;
|
||||||
ptr->type = type;
|
ptr->type = type;
|
||||||
ptr->var = base->var;
|
ptr->var = base->var;
|
||||||
ptr->deref = base->deref;
|
ptr->deref = tail;
|
||||||
ptr->chain = chain;
|
|
||||||
ptr->access = access;
|
ptr->access = access;
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
@@ -362,7 +359,7 @@ vtn_pointer_dereference(struct vtn_builder *b,
|
|||||||
if (vtn_pointer_uses_ssa_offset(b, base)) {
|
if (vtn_pointer_uses_ssa_offset(b, base)) {
|
||||||
return vtn_ssa_offset_pointer_dereference(b, base, deref_chain);
|
return vtn_ssa_offset_pointer_dereference(b, base, deref_chain);
|
||||||
} else {
|
} else {
|
||||||
return vtn_access_chain_pointer_dereference(b, base, deref_chain);
|
return vtn_nir_deref_pointer_dereference(b, base, deref_chain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,39 +409,15 @@ vtn_pointer_to_deref(struct vtn_builder *b, struct vtn_pointer *ptr)
|
|||||||
if (ptr->var && ptr->var->copy_prop_sampler)
|
if (ptr->var && ptr->var->copy_prop_sampler)
|
||||||
return vtn_pointer_to_deref(b, ptr->var->copy_prop_sampler);
|
return vtn_pointer_to_deref(b, ptr->var->copy_prop_sampler);
|
||||||
|
|
||||||
nir_deref_instr *tail;
|
vtn_assert(!vtn_pointer_uses_ssa_offset(b, ptr));
|
||||||
if (ptr->deref) {
|
if (!ptr->deref) {
|
||||||
tail = ptr->deref;
|
struct vtn_access_chain chain = {
|
||||||
} else {
|
.length = 0,
|
||||||
assert(ptr->var && ptr->var->var);
|
};
|
||||||
tail = nir_build_deref_var(&b->nb, ptr->var->var);
|
ptr = vtn_nir_deref_pointer_dereference(b, ptr, &chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Raw variable access */
|
return ptr->deref;
|
||||||
if (!ptr->chain)
|
|
||||||
return tail;
|
|
||||||
|
|
||||||
struct vtn_access_chain *chain = ptr->chain;
|
|
||||||
vtn_assert(chain);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < chain->length; i++) {
|
|
||||||
if (glsl_type_is_struct(tail->type)) {
|
|
||||||
vtn_assert(chain->link[i].mode == vtn_access_mode_literal);
|
|
||||||
unsigned idx = chain->link[i].id;
|
|
||||||
tail = nir_build_deref_struct(&b->nb, tail, idx);
|
|
||||||
} else {
|
|
||||||
nir_ssa_def *index;
|
|
||||||
if (chain->link[i].mode == vtn_access_mode_literal) {
|
|
||||||
index = nir_imm_int(&b->nb, chain->link[i].id);
|
|
||||||
} else {
|
|
||||||
vtn_assert(chain->link[i].mode == vtn_access_mode_id);
|
|
||||||
index = vtn_ssa_value(b, chain->link[i].id)->def;
|
|
||||||
}
|
|
||||||
tail = nir_build_deref_array(&b->nb, tail, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1447,7 +1420,6 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
|
|||||||
|
|
||||||
if (val->value_type == vtn_value_type_pointer) {
|
if (val->value_type == vtn_value_type_pointer) {
|
||||||
assert(val->pointer->var == void_var);
|
assert(val->pointer->var == void_var);
|
||||||
assert(val->pointer->chain == NULL);
|
|
||||||
assert(member == -1);
|
assert(member == -1);
|
||||||
} else {
|
} else {
|
||||||
assert(val->value_type == vtn_value_type_type);
|
assert(val->value_type == vtn_value_type_type);
|
||||||
|
Reference in New Issue
Block a user