From 849bfc85c97fd97b3b4f7b0cd60bdba1829343da Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Thu, 29 Jun 2017 10:33:39 -0700 Subject: [PATCH] nir/spirv: Use real pointer types Reviewed-by: Connor Abbott --- src/compiler/spirv/spirv_to_nir.c | 23 +++++++++++++++++------ src/compiler/spirv/vtn_cfg.c | 14 +++++++++++--- src/compiler/spirv/vtn_private.h | 21 ++++++++++++++++++++- src/compiler/spirv/vtn_variables.c | 17 ++++++++++++----- 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c index cc3ba0d..462b049 100644 --- a/src/compiler/spirv/spirv_to_nir.c +++ b/src/compiler/spirv/spirv_to_nir.c @@ -421,6 +421,7 @@ vtn_type_copy(struct vtn_builder *b, struct vtn_type *src) case vtn_base_type_vector: case vtn_base_type_matrix: case vtn_base_type_array: + case vtn_base_type_pointer: case vtn_base_type_image: case vtn_base_type_sampler: /* Nothing more to do */ @@ -858,13 +859,17 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, break; } - case SpvOpTypePointer: - /* FIXME: For now, we'll just do the really lame thing and return - * the same type. The validator should ensure that the proper number - * of dereferences happen - */ - val->type = vtn_value(b, w[3], vtn_value_type_type)->type; + case SpvOpTypePointer: { + 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->type = NULL; + val->type->storage_class = storage_class; + val->type->deref = deref_type; break; + } case SpvOpTypeImage: { val->type->base_type = vtn_base_type_image; @@ -956,6 +961,12 @@ vtn_null_constant(struct vtn_builder *b, const struct glsl_type *type) { nir_constant *c = rzalloc(b, nir_constant); + /* For pointers and other typeless things, we have to return something but + * it doesn't matter what. + */ + if (!type) + return c; + switch (glsl_get_base_type(type)) { case GLSL_TYPE_INT: case GLSL_TYPE_UINT: diff --git a/src/compiler/spirv/vtn_cfg.c b/src/compiler/spirv/vtn_cfg.c index 7158b32..c1677b4 100644 --- a/src/compiler/spirv/vtn_cfg.c +++ b/src/compiler/spirv/vtn_cfg.c @@ -52,7 +52,11 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode, func->num_params = func_type->length; func->params = ralloc_array(b->shader, nir_parameter, func->num_params); for (unsigned i = 0; i < func->num_params; i++) { - func->params[i].type = func_type->params[i]->type; + if (func_type->params[i]->base_type == vtn_base_type_pointer) { + func->params[i].type = func_type->params[i]->deref->type; + } else { + func->params[i].type = func_type->params[i]->type; + } /* TODO: We could do something smarter here. */ func->params[i].param_type = nir_parameter_inout; @@ -73,11 +77,15 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpFunctionParameter: { struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; + if (type->base_type == vtn_base_type_pointer) { + type = type->deref; + assert(type->base_type != vtn_base_type_pointer); + } assert(b->func_param_idx < b->func->impl->num_params); nir_variable *param = b->func->impl->params[b->func_param_idx++]; - assert(param->type == type->type); + assert(type->type == param->type); struct vtn_variable *vtn_var = rzalloc(b, struct vtn_variable); vtn_var->type = type; @@ -102,7 +110,7 @@ vtn_cfg_handle_prepass_instruction(struct vtn_builder *b, SpvOp opcode, /* Name the parameter so it shows up nicely in NIR */ param->name = ralloc_strdup(param, val->name); - val->pointer = vtn_pointer_for_variable(b, vtn_var); + val->pointer = vtn_pointer_for_variable(b, vtn_var, NULL); break; } diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h index b43b013..7cb5035 100644 --- a/src/compiler/spirv/vtn_private.h +++ b/src/compiler/spirv/vtn_private.h @@ -203,6 +203,7 @@ enum vtn_base_type { vtn_base_type_matrix, vtn_base_type_array, vtn_base_type_struct, + vtn_base_type_pointer, vtn_base_type_image, vtn_base_type_sampler, vtn_base_type_function, @@ -260,6 +261,15 @@ struct vtn_type { bool builtin_block:1; }; + /* Members for pointer types */ + struct { + /* For pointers, the vtn_type for dereferenced type */ + struct vtn_type *deref; + + /* Storage class for pointers */ + SpvStorageClass storage_class; + }; + /* Members for image types */ struct { /* For images, indicates whether it's sampled or storage */ @@ -327,6 +337,14 @@ struct vtn_pointer { /** The dereferenced type of this pointer */ struct vtn_type *type; + /** The pointer type of this pointer + * + * This may be NULL for some temporary pointers constructed as part of a + * large load, store, or copy. It MUST be valid for all pointers which are + * stored as SPIR-V SSA values. + */ + struct vtn_type *ptr_type; + /** The referenced variable, if known * * This field may be NULL if the pointer uses a (block_index, offset) pair @@ -529,7 +547,8 @@ nir_ssa_def *vtn_vector_insert_dynamic(struct vtn_builder *b, nir_ssa_def *src, nir_deref_var *vtn_nir_deref(struct vtn_builder *b, uint32_t id); struct vtn_pointer *vtn_pointer_for_variable(struct vtn_builder *b, - struct vtn_variable *var); + struct vtn_variable *var, + struct vtn_type *ptr_type); nir_deref_var *vtn_pointer_to_deref(struct vtn_builder *b, struct vtn_pointer *ptr); diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c index 1d13c77..1ff7427 100644 --- a/src/compiler/spirv/vtn_variables.c +++ b/src/compiler/spirv/vtn_variables.c @@ -227,12 +227,13 @@ rewrite_deref_types(nir_deref *deref, const struct glsl_type *type) struct vtn_pointer * vtn_pointer_for_variable(struct vtn_builder *b, - struct vtn_variable *var) + struct vtn_variable *var, struct vtn_type *ptr_type) { struct vtn_pointer *pointer = rzalloc(b, struct vtn_pointer); pointer->mode = var->mode; pointer->type = var->type; + pointer->ptr_type = ptr_type; pointer->var = var; return pointer; @@ -1470,9 +1471,13 @@ is_per_vertex_inout(const struct vtn_variable *var, gl_shader_stage stage) static void vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, - struct vtn_type *type, SpvStorageClass storage_class, + struct vtn_type *ptr_type, SpvStorageClass storage_class, nir_constant *initializer) { + assert(ptr_type->base_type == vtn_base_type_pointer); + struct vtn_type *type = ptr_type->deref; + assert(type->base_type != vtn_base_type_pointer); + struct vtn_type *without_array = type; while(glsl_type_is_array(without_array->type)) without_array = without_array->array_element; @@ -1507,7 +1512,7 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, var->mode = mode; assert(val->value_type == vtn_value_type_pointer); - val->pointer = vtn_pointer_for_variable(b, var); + val->pointer = vtn_pointer_for_variable(b, var, ptr_type); switch (var->mode) { case vtn_variable_mode_local: @@ -1674,7 +1679,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } case SpvOpVariable: { - struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; + struct vtn_type *ptr_type = vtn_value(b, w[1], vtn_value_type_type)->type; struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer); @@ -1683,7 +1688,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, if (count > 4) initializer = vtn_value(b, w[4], vtn_value_type_constant)->constant; - vtn_create_variable(b, val, type, storage_class, initializer); + vtn_create_variable(b, val, ptr_type, storage_class, initializer); break; } @@ -1705,6 +1710,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, idx++; } + struct vtn_type *ptr_type = vtn_value(b, w[1], vtn_value_type_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 @@ -1725,6 +1731,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer); val->pointer = vtn_pointer_dereference(b, base_val->pointer, chain); + val->pointer->ptr_type = ptr_type; } break; } -- 2.7.4