From 604eda3712879ae21c56336fe890092732afebc6 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Thu, 29 Jun 2017 10:33:33 -0700 Subject: [PATCH] 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 --- src/compiler/spirv/vtn_private.h | 8 +- src/compiler/spirv/vtn_variables.c | 144 ++++++++++++++++------------- 2 files changed, 88 insertions(+), 64 deletions(-) diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h index 603cfc2b6e3..4426c957c30 100644 --- a/src/compiler/spirv/vtn_private.h +++ b/src/compiler/spirv/vtn_private.h @@ -255,8 +255,12 @@ struct vtn_access_link { struct vtn_access_chain { uint32_t length; - /* Struct elements and array offsets */ - struct vtn_access_link link[0]; + /** Struct elements and array offsets. + * + * 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 { diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c index cc3ae0a2d5f..724ca048a05 100644 --- a/src/compiler/spirv/vtn_variables.c +++ b/src/compiler/spirv/vtn_variables.c @@ -28,6 +28,20 @@ #include "vtn_private.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 * vtn_access_chain_extend(struct vtn_builder *b, struct vtn_access_chain *old, 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; unsigned old_len = old ? old->length : 0; - unsigned new_len = 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; + chain = vtn_access_chain_create(b, old_len + new_ids); for (unsigned i = 0; i < old_len; 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; } +/* 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 * vtn_access_link_as_ssa(struct vtn_builder *b, struct vtn_access_link link, 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); } - struct vtn_pointer elem = *ptr; - elem.chain = vtn_access_chain_extend(b, ptr->chain, 1); - unsigned link_idx = ptr->chain ? ptr->chain->length : 0; - elem.chain->link[link_idx].mode = vtn_access_mode_literal; + struct vtn_access_chain chain = { + .length = 1, + .link = { + { .mode = vtn_access_mode_literal, }, + } + }; for (unsigned i = 0; i < elems; i++) { - elem.chain->link[link_idx].id = i; - elem.type = (base_type == GLSL_TYPE_ARRAY) ? ptr->type->array_element : - ptr->type->members[i]; - _vtn_variable_load_store(b, load, &elem, &(*inout)->elems[i]); + chain.link[0].id = i; + struct vtn_pointer *elem = vtn_pointer_dereference(b, ptr, &chain); + _vtn_variable_load_store(b, load, elem, &(*inout)->elems[i]); } return; } @@ -797,24 +839,21 @@ _vtn_variable_copy(struct vtn_builder *b, struct vtn_pointer *dest, case GLSL_TYPE_ARRAY: case GLSL_TYPE_STRUCT: { - struct vtn_pointer src_elem = *src, dest_elem = *dest; - src_elem.chain = vtn_access_chain_extend(b, src->chain, 1); - dest_elem.chain = vtn_access_chain_extend(b, dest->chain, 1); - src_elem.chain->link[src_elem.chain->length - 1].mode = vtn_access_mode_literal; - dest_elem.chain->link[dest_elem.chain->length - 1].mode = vtn_access_mode_literal; - + struct vtn_access_chain chain = { + .length = 1, + .link = { + { .mode = vtn_access_mode_literal, }, + } + }; unsigned elems = glsl_get_length(src->type->type); for (unsigned i = 0; i < elems; i++) { - src_elem.chain->link[src_elem.chain->length - 1].id = i; - dest_elem.chain->link[dest_elem.chain->length - 1].id = i; - if (base_type == GLSL_TYPE_STRUCT) { - src_elem.type = src->type->members[i]; - dest_elem.type = dest->type->members[i]; - } else { - src_elem.type = src->type->array_element; - dest_elem.type = dest->type->array_element; - } - _vtn_variable_copy(b, &dest_elem, &src_elem); + chain.link[0].id = i; + struct vtn_pointer *src_elem = + vtn_pointer_dereference(b, src, &chain); + struct vtn_pointer *dest_elem = + vtn_pointer_dereference(b, dest, &chain); + + _vtn_variable_copy(b, dest_elem, src_elem); } return; } @@ -1548,27 +1587,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, case SpvOpAccessChain: case SpvOpInBoundsAccessChain: { - struct vtn_pointer *base, *ptr; - struct vtn_value *base_val = vtn_untyped_value(b, w[3]); - if (base_val->value_type == vtn_value_type_sampled_image) { - /* This is rather insane. SPIR-V allows you to use OpSampledImage - * to combine an array of images with a single sampler to get an - * array of sampled images that all share the same sampler. - * Fortunately, this means that we can more-or-less ignore the - * sampler when crawling the access chain, but it does leave us - * 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_create(b, count - 4); - 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; + 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) { @@ -1577,32 +1598,31 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } 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; - + struct vtn_value *base_val = vtn_untyped_value(b, w[3]); if (base_val->value_type == vtn_value_type_sampled_image) { + /* This is rather insane. SPIR-V allows you to use OpSampledImage + * to combine an array of images with a single sampler to get an + * array of sampled images that all share the same sampler. + * Fortunately, this means that we can more-or-less ignore the + * sampler when crawling the access chain, but it does leave us + * with this rather awkward little special-case. + */ struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_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; } else { + assert(base_val->value_type == vtn_value_type_pointer); struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer); - val->pointer = ptr; + val->pointer = vtn_pointer_dereference(b, base_val->pointer, chain); } break; } -- 2.30.2