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:
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;
}
case SpvOpTypeStruct:
case SpvOpTypeOpaque:
case SpvOpTypePointer:
+ case SpvOpTypeForwardPointer:
case SpvOpTypeFunction:
case SpvOpTypeEvent:
case SpvOpTypeDeviceEvent: