From: Jason Ekstrand Date: Sat, 19 Jan 2019 16:21:28 +0000 (-0600) Subject: spirv: Handle OpTypeForwardPointer X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=837ed2ba51b55598ca0d9d1e6b21c6a83fca6833;p=mesa.git spirv: Handle OpTypeForwardPointer We handle forward declarations by creating the pointer type with it's storage type based on storage class and just waiting to fill out the actual deref type until we get the OpTypePointer. Because any composites using the forward declared type only care about the storage type (i.e. uint64_t, uvec2, etc.) when creating their glsl_type, this works fine and we can defer the actual deref_type as far as we need. Reviewed-by: Bas Nieuwenhuizen Reviewed-by: Karol Herbst --- diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c index b54d259e14b..8c85eac5875 100644 --- a/src/compiler/spirv/spirv_to_nir.c +++ b/src/compiler/spirv/spirv_to_nir.c @@ -1101,10 +1101,18 @@ static void vtn_handle_type(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { - struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_type); + struct vtn_value *val = NULL; - val->type = rzalloc(b, struct vtn_type); - val->type->id = w[1]; + /* In order to properly handle forward declarations, we have to defer + * allocation for pointer types. + */ + if (opcode != SpvOpTypePointer && opcode != SpvOpTypeForwardPointer) { + val = vtn_push_value(b, w[1], vtn_value_type_type); + vtn_fail_if(val->type != NULL, + "Only pointers can have forward declarations"); + val->type = rzalloc(b, struct vtn_type); + val->type->id = w[1]; + } switch (opcode) { case SpvOpTypeVoid: @@ -1274,46 +1282,70 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, break; } - case SpvOpTypePointer: { + case SpvOpTypePointer: + case SpvOpTypeForwardPointer: { + /* We can't blindly push the value because it might be a forward + * declaration. + */ + val = vtn_untyped_value(b, w[1]); + SpvStorageClass storage_class = w[2]; - struct vtn_type *deref_type = - vtn_value(b, w[3], vtn_value_type_type)->type; - val->type->base_type = vtn_base_type_pointer; - val->type->storage_class = storage_class; - val->type->deref = deref_type; + if (val->value_type == vtn_value_type_invalid) { + val->value_type = vtn_value_type_type; + val->type = rzalloc(b, struct vtn_type); + val->type->id = w[1]; + val->type->base_type = vtn_base_type_pointer; + val->type->storage_class = storage_class; - vtn_foreach_decoration(b, val, array_stride_decoration_cb, NULL); + /* These can actually be stored to nir_variables and used as SSA + * values so they need a real glsl_type. + */ + switch (storage_class) { + case SpvStorageClassUniform: + val->type->type = b->options->ubo_ptr_type; + break; + case SpvStorageClassStorageBuffer: + val->type->type = b->options->ssbo_ptr_type; + break; + case SpvStorageClassPushConstant: + val->type->type = b->options->push_const_ptr_type; + break; + case SpvStorageClassWorkgroup: + val->type->type = b->options->shared_ptr_type; + break; + default: + /* In this case, no variable pointers are allowed so all deref + * chains are complete back to the variable and it doesn't matter + * what type gets used so we leave it NULL. + */ + break; + } + } else { + vtn_fail_if(val->type->storage_class != storage_class, + "The storage classes of an OpTypePointer and any " + "OpTypeForwardPointers that provide forward " + "declarations of it must match."); + } - /* These can actually be stored to nir_variables and used as SSA - * values so they need a real glsl_type. - */ - switch (storage_class) { - case SpvStorageClassUniform: - val->type->type = b->options->ubo_ptr_type; - break; - case SpvStorageClassStorageBuffer: - val->type->type = b->options->ssbo_ptr_type; - break; - case SpvStorageClassPushConstant: - val->type->type = b->options->push_const_ptr_type; - break; - case SpvStorageClassWorkgroup: - val->type->type = b->options->shared_ptr_type; - if (b->options->lower_workgroup_access_to_offsets) { + if (opcode == SpvOpTypePointer) { + vtn_fail_if(val->type->deref != NULL, + "While OpTypeForwardPointer can be used to provide a " + "forward declaration of a pointer, OpTypePointer can " + "only be used once for a given id."); + + val->type->deref = vtn_value(b, w[3], vtn_value_type_type)->type; + + vtn_foreach_decoration(b, val, array_stride_decoration_cb, NULL); + + if (storage_class == SpvStorageClassWorkgroup && + b->options->lower_workgroup_access_to_offsets) { uint32_t size, align; val->type->deref = vtn_type_layout_std430(b, val->type->deref, &size, &align); val->type->length = size; val->type->align = align; } - break; - default: - /* In this case, no variable pointers are allowed so all deref chains - * are complete back to the variable and it doesn't matter what type - * gets used so we leave it NULL. - */ - break; } break; } @@ -3931,6 +3963,7 @@ vtn_handle_variable_or_type_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpTypeStruct: case SpvOpTypeOpaque: case SpvOpTypePointer: + case SpvOpTypeForwardPointer: case SpvOpTypeFunction: case SpvOpTypeEvent: case SpvOpTypeDeviceEvent: