nir/spirv: Rework the way pointers get dereferenced
This has the advantage of moving all of the "extend an access chain" code into one place. Reviewed-by: Connor Abbott <cwabbott0@gmail.com>
This commit is contained in:

committed by
Jason Ekstrand

parent
4c21e6b7f8
commit
604eda3712
@@ -255,8 +255,12 @@ struct vtn_access_link {
|
|||||||
struct vtn_access_chain {
|
struct vtn_access_chain {
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
|
|
||||||
/* Struct elements and array offsets */
|
/** Struct elements and array offsets.
|
||||||
struct vtn_access_link link[0];
|
*
|
||||||
|
* This is an array of 1 so that it can conveniently be created on the
|
||||||
|
* stack but the real length is given by the length field.
|
||||||
|
*/
|
||||||
|
struct vtn_access_link link[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum vtn_variable_mode {
|
enum vtn_variable_mode {
|
||||||
|
@@ -28,6 +28,20 @@
|
|||||||
#include "vtn_private.h"
|
#include "vtn_private.h"
|
||||||
#include "spirv_info.h"
|
#include "spirv_info.h"
|
||||||
|
|
||||||
|
static struct vtn_access_chain *
|
||||||
|
vtn_access_chain_create(struct vtn_builder *b, unsigned length)
|
||||||
|
{
|
||||||
|
struct vtn_access_chain *chain;
|
||||||
|
|
||||||
|
/* Subtract 1 from the length since there's already one built in */
|
||||||
|
size_t size = sizeof(*chain) +
|
||||||
|
(MAX2(length, 1) - 1) * sizeof(chain->link[0]);
|
||||||
|
chain = rzalloc_size(b, size);
|
||||||
|
chain->length = length;
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
static struct vtn_access_chain *
|
static struct vtn_access_chain *
|
||||||
vtn_access_chain_extend(struct vtn_builder *b, struct vtn_access_chain *old,
|
vtn_access_chain_extend(struct vtn_builder *b, struct vtn_access_chain *old,
|
||||||
unsigned new_ids)
|
unsigned new_ids)
|
||||||
@@ -35,11 +49,7 @@ vtn_access_chain_extend(struct vtn_builder *b, struct vtn_access_chain *old,
|
|||||||
struct vtn_access_chain *chain;
|
struct vtn_access_chain *chain;
|
||||||
|
|
||||||
unsigned old_len = old ? old->length : 0;
|
unsigned old_len = old ? old->length : 0;
|
||||||
unsigned new_len = old_len + new_ids;
|
chain = vtn_access_chain_create(b, old_len + new_ids);
|
||||||
/* TODO: don't use rzalloc */
|
|
||||||
chain = rzalloc_size(b, sizeof(*chain) + new_len * sizeof(chain->link[0]));
|
|
||||||
|
|
||||||
chain->length = new_len;
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < old_len; i++)
|
for (unsigned i = 0; i < old_len; i++)
|
||||||
chain->link[i] = old->link[i];
|
chain->link[i] = old->link[i];
|
||||||
@@ -47,6 +57,37 @@ vtn_access_chain_extend(struct vtn_builder *b, struct vtn_access_chain *old,
|
|||||||
return chain;
|
return chain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dereference the given base pointer by the access chain */
|
||||||
|
static struct vtn_pointer *
|
||||||
|
vtn_pointer_dereference(struct vtn_builder *b,
|
||||||
|
struct vtn_pointer *base,
|
||||||
|
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;
|
||||||
|
|
||||||
|
unsigned start = base->chain ? base->chain->length : 0;
|
||||||
|
for (unsigned i = 0; i < deref_chain->length; i++) {
|
||||||
|
chain->link[start + i] = deref_chain->link[i];
|
||||||
|
|
||||||
|
if (glsl_type_is_struct(type->type)) {
|
||||||
|
assert(deref_chain->link[i].mode == vtn_access_mode_literal);
|
||||||
|
type = type->members[deref_chain->link[i].id];
|
||||||
|
} else {
|
||||||
|
type = type->array_element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vtn_pointer *ptr = rzalloc(b, struct vtn_pointer);
|
||||||
|
ptr->mode = base->mode;
|
||||||
|
ptr->type = type;
|
||||||
|
ptr->var = base->var;
|
||||||
|
ptr->chain = chain;
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
static nir_ssa_def *
|
static nir_ssa_def *
|
||||||
vtn_access_link_as_ssa(struct vtn_builder *b, struct vtn_access_link link,
|
vtn_access_link_as_ssa(struct vtn_builder *b, struct vtn_access_link link,
|
||||||
unsigned stride)
|
unsigned stride)
|
||||||
@@ -730,15 +771,16 @@ _vtn_variable_load_store(struct vtn_builder *b, bool load,
|
|||||||
(*inout)->elems = rzalloc_array(b, struct vtn_ssa_value *, elems);
|
(*inout)->elems = rzalloc_array(b, struct vtn_ssa_value *, elems);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vtn_pointer elem = *ptr;
|
struct vtn_access_chain chain = {
|
||||||
elem.chain = vtn_access_chain_extend(b, ptr->chain, 1);
|
.length = 1,
|
||||||
unsigned link_idx = ptr->chain ? ptr->chain->length : 0;
|
.link = {
|
||||||
elem.chain->link[link_idx].mode = vtn_access_mode_literal;
|
{ .mode = vtn_access_mode_literal, },
|
||||||
|
}
|
||||||
|
};
|
||||||
for (unsigned i = 0; i < elems; i++) {
|
for (unsigned i = 0; i < elems; i++) {
|
||||||
elem.chain->link[link_idx].id = i;
|
chain.link[0].id = i;
|
||||||
elem.type = (base_type == GLSL_TYPE_ARRAY) ? ptr->type->array_element :
|
struct vtn_pointer *elem = vtn_pointer_dereference(b, ptr, &chain);
|
||||||
ptr->type->members[i];
|
_vtn_variable_load_store(b, load, elem, &(*inout)->elems[i]);
|
||||||
_vtn_variable_load_store(b, load, &elem, &(*inout)->elems[i]);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -797,24 +839,21 @@ _vtn_variable_copy(struct vtn_builder *b, struct vtn_pointer *dest,
|
|||||||
|
|
||||||
case GLSL_TYPE_ARRAY:
|
case GLSL_TYPE_ARRAY:
|
||||||
case GLSL_TYPE_STRUCT: {
|
case GLSL_TYPE_STRUCT: {
|
||||||
struct vtn_pointer src_elem = *src, dest_elem = *dest;
|
struct vtn_access_chain chain = {
|
||||||
src_elem.chain = vtn_access_chain_extend(b, src->chain, 1);
|
.length = 1,
|
||||||
dest_elem.chain = vtn_access_chain_extend(b, dest->chain, 1);
|
.link = {
|
||||||
src_elem.chain->link[src_elem.chain->length - 1].mode = vtn_access_mode_literal;
|
{ .mode = vtn_access_mode_literal, },
|
||||||
dest_elem.chain->link[dest_elem.chain->length - 1].mode = vtn_access_mode_literal;
|
}
|
||||||
|
};
|
||||||
unsigned elems = glsl_get_length(src->type->type);
|
unsigned elems = glsl_get_length(src->type->type);
|
||||||
for (unsigned i = 0; i < elems; i++) {
|
for (unsigned i = 0; i < elems; i++) {
|
||||||
src_elem.chain->link[src_elem.chain->length - 1].id = i;
|
chain.link[0].id = i;
|
||||||
dest_elem.chain->link[dest_elem.chain->length - 1].id = i;
|
struct vtn_pointer *src_elem =
|
||||||
if (base_type == GLSL_TYPE_STRUCT) {
|
vtn_pointer_dereference(b, src, &chain);
|
||||||
src_elem.type = src->type->members[i];
|
struct vtn_pointer *dest_elem =
|
||||||
dest_elem.type = dest->type->members[i];
|
vtn_pointer_dereference(b, dest, &chain);
|
||||||
} else {
|
|
||||||
src_elem.type = src->type->array_element;
|
_vtn_variable_copy(b, dest_elem, src_elem);
|
||||||
dest_elem.type = dest->type->array_element;
|
|
||||||
}
|
|
||||||
_vtn_variable_copy(b, &dest_elem, &src_elem);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1548,7 +1587,22 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
|
|||||||
|
|
||||||
case SpvOpAccessChain:
|
case SpvOpAccessChain:
|
||||||
case SpvOpInBoundsAccessChain: {
|
case SpvOpInBoundsAccessChain: {
|
||||||
struct vtn_pointer *base, *ptr;
|
struct vtn_access_chain *chain = vtn_access_chain_create(b, count - 4);
|
||||||
|
|
||||||
|
unsigned idx = 0;
|
||||||
|
for (int i = 4; i < count; i++) {
|
||||||
|
struct vtn_value *link_val = vtn_untyped_value(b, w[i]);
|
||||||
|
if (link_val->value_type == vtn_value_type_constant) {
|
||||||
|
chain->link[idx].mode = vtn_access_mode_literal;
|
||||||
|
chain->link[idx].id = link_val->constant->values[0].u32[0];
|
||||||
|
} else {
|
||||||
|
chain->link[idx].mode = vtn_access_mode_id;
|
||||||
|
chain->link[idx].id = w[i];
|
||||||
|
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
struct vtn_value *base_val = vtn_untyped_value(b, w[3]);
|
struct vtn_value *base_val = vtn_untyped_value(b, w[3]);
|
||||||
if (base_val->value_type == vtn_value_type_sampled_image) {
|
if (base_val->value_type == vtn_value_type_sampled_image) {
|
||||||
/* This is rather insane. SPIR-V allows you to use OpSampledImage
|
/* This is rather insane. SPIR-V allows you to use OpSampledImage
|
||||||
@@ -1558,51 +1612,17 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
|
|||||||
* sampler when crawling the access chain, but it does leave us
|
* sampler when crawling the access chain, but it does leave us
|
||||||
* with this rather awkward little special-case.
|
* with this rather awkward little special-case.
|
||||||
*/
|
*/
|
||||||
base = base_val->sampled_image->image;
|
|
||||||
} else {
|
|
||||||
assert(base_val->value_type == vtn_value_type_pointer);
|
|
||||||
base = base_val->pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct vtn_access_chain *chain =
|
|
||||||
vtn_access_chain_extend(b, base->chain, count - 4);
|
|
||||||
struct vtn_type *type = base->type;
|
|
||||||
|
|
||||||
unsigned idx = base->chain ? base->chain->length : 0;
|
|
||||||
for (int i = 4; i < count; i++) {
|
|
||||||
struct vtn_value *link_val = vtn_untyped_value(b, w[i]);
|
|
||||||
if (link_val->value_type == vtn_value_type_constant) {
|
|
||||||
chain->link[idx].mode = vtn_access_mode_literal;
|
|
||||||
chain->link[idx].id = link_val->constant->values[0].u32[0];
|
|
||||||
} else {
|
|
||||||
chain->link[idx].mode = vtn_access_mode_id;
|
|
||||||
chain->link[idx].id = w[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glsl_type_is_struct(type->type)) {
|
|
||||||
assert(chain->link[idx].mode == vtn_access_mode_literal);
|
|
||||||
type = type->members[chain->link[idx].id];
|
|
||||||
} else {
|
|
||||||
type = type->array_element;
|
|
||||||
}
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr = ralloc(b, struct vtn_pointer);
|
|
||||||
*ptr = *base;
|
|
||||||
ptr->chain = chain;
|
|
||||||
ptr->type = type;
|
|
||||||
|
|
||||||
if (base_val->value_type == vtn_value_type_sampled_image) {
|
|
||||||
struct vtn_value *val =
|
struct vtn_value *val =
|
||||||
vtn_push_value(b, w[2], vtn_value_type_sampled_image);
|
vtn_push_value(b, w[2], vtn_value_type_sampled_image);
|
||||||
val->sampled_image = ralloc(b, struct vtn_sampled_image);
|
val->sampled_image = ralloc(b, struct vtn_sampled_image);
|
||||||
val->sampled_image->image = ptr;
|
val->sampled_image->image =
|
||||||
|
vtn_pointer_dereference(b, base_val->sampled_image->image, chain);
|
||||||
val->sampled_image->sampler = base_val->sampled_image->sampler;
|
val->sampled_image->sampler = base_val->sampled_image->sampler;
|
||||||
} else {
|
} else {
|
||||||
|
assert(base_val->value_type == vtn_value_type_pointer);
|
||||||
struct vtn_value *val =
|
struct vtn_value *val =
|
||||||
vtn_push_value(b, w[2], vtn_value_type_pointer);
|
vtn_push_value(b, w[2], vtn_value_type_pointer);
|
||||||
val->pointer = ptr;
|
val->pointer = vtn_pointer_dereference(b, base_val->pointer, chain);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user