return val->ssa;
case vtn_value_type_pointer:
- /* This is needed for function parameters */
- return vtn_variable_load(b, val->pointer);
+ assert(val->pointer->ptr_type && val->pointer->ptr_type->type);
+ struct vtn_ssa_value *ssa =
+ vtn_create_ssa_value(b, val->pointer->ptr_type->type);
+ ssa->def = vtn_pointer_to_ssa(b, val->pointer);
+ return ssa;
default:
unreachable("Invalid type for an SSA value");
vtn_type_copy(struct vtn_builder *b, struct vtn_type *src)
{
struct vtn_type *dest = ralloc(b, struct vtn_type);
- dest->type = src->type;
- dest->is_builtin = src->is_builtin;
- if (src->is_builtin)
- dest->builtin = src->builtin;
+ *dest = *src;
- if (!glsl_type_is_scalar(src->type)) {
- switch (glsl_get_base_type(src->type)) {
- case GLSL_TYPE_INT:
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT64:
- case GLSL_TYPE_UINT64:
- case GLSL_TYPE_BOOL:
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_DOUBLE:
- case GLSL_TYPE_ARRAY:
- dest->row_major = src->row_major;
- dest->stride = src->stride;
- dest->array_element = src->array_element;
- break;
-
- case GLSL_TYPE_STRUCT: {
- unsigned elems = glsl_get_length(src->type);
+ switch (src->base_type) {
+ case vtn_base_type_void:
+ case vtn_base_type_scalar:
+ 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 */
+ break;
- dest->members = ralloc_array(b, struct vtn_type *, elems);
- memcpy(dest->members, src->members, elems * sizeof(struct vtn_type *));
+ case vtn_base_type_struct:
+ dest->members = ralloc_array(b, struct vtn_type *, src->length);
+ memcpy(dest->members, src->members,
+ src->length * sizeof(src->members[0]));
- dest->offsets = ralloc_array(b, unsigned, elems);
- memcpy(dest->offsets, src->offsets, elems * sizeof(unsigned));
- break;
- }
+ dest->offsets = ralloc_array(b, unsigned, src->length);
+ memcpy(dest->offsets, src->offsets,
+ src->length * sizeof(src->offsets[0]));
+ break;
- default:
- unreachable("unhandled type");
- }
+ case vtn_base_type_function:
+ dest->params = ralloc_array(b, struct vtn_type *, src->length);
+ memcpy(dest->params, src->params, src->length * sizeof(src->params[0]));
+ break;
}
return dest;
ctx->type->offsets[member] = dec->literals[0];
break;
case SpvDecorationMatrixStride:
- mutable_matrix_member(b, ctx->type, member)->stride = dec->literals[0];
+ /* Handled as a second pass */
break;
case SpvDecorationColMajor:
break; /* Nothing to do here. Column-major is the default. */
}
}
+/* Matrix strides are handled as a separate pass because we need to know
+ * whether the matrix is row-major or not first.
+ */
+static void
+struct_member_matrix_stride_cb(struct vtn_builder *b,
+ struct vtn_value *val, int member,
+ const struct vtn_decoration *dec,
+ void *void_ctx)
+{
+ if (dec->decoration != SpvDecorationMatrixStride)
+ return;
+ assert(member >= 0);
+
+ struct member_decoration_ctx *ctx = void_ctx;
+
+ struct vtn_type *mat_type = mutable_matrix_member(b, ctx->type, member);
+ if (mat_type->row_major) {
+ mat_type->array_element = vtn_type_copy(b, mat_type->array_element);
+ mat_type->stride = mat_type->array_element->stride;
+ mat_type->array_element->stride = dec->literals[0];
+ } else {
+ assert(mat_type->array_element->stride > 0);
+ mat_type->stride = dec->literals[0];
+ }
+}
+
static void
type_decoration_cb(struct vtn_builder *b,
struct vtn_value *val, int member,
switch (dec->decoration) {
case SpvDecorationArrayStride:
+ assert(type->base_type == vtn_base_type_matrix ||
+ type->base_type == vtn_base_type_array ||
+ type->base_type == vtn_base_type_pointer);
type->stride = dec->literals[0];
break;
case SpvDecorationBlock:
+ assert(type->base_type == vtn_base_type_struct);
type->block = true;
break;
case SpvDecorationBufferBlock:
+ assert(type->base_type == vtn_base_type_struct);
type->buffer_block = true;
break;
case SpvDecorationGLSLShared:
case SpvImageFormatRg32ui: return 0x823C; /* GL_RG32UI */
case SpvImageFormatRg16ui: return 0x823A; /* GL_RG16UI */
case SpvImageFormatRg8ui: return 0x8238; /* GL_RG8UI */
- case SpvImageFormatR16ui: return 0x823A; /* GL_RG16UI */
+ case SpvImageFormatR16ui: return 0x8234; /* GL_R16UI */
case SpvImageFormatR8ui: return 0x8232; /* GL_R8UI */
default:
assert(!"Invalid image format");
struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_type);
val->type = rzalloc(b, struct vtn_type);
- val->type->is_builtin = false;
val->type->val = val;
switch (opcode) {
case SpvOpTypeVoid:
+ val->type->base_type = vtn_base_type_void;
val->type->type = glsl_void_type();
break;
case SpvOpTypeBool:
+ val->type->base_type = vtn_base_type_scalar;
val->type->type = glsl_bool_type();
break;
case SpvOpTypeInt: {
int bit_size = w[2];
const bool signedness = w[3];
+ val->type->base_type = vtn_base_type_scalar;
if (bit_size == 64)
val->type->type = (signedness ? glsl_int64_t_type() : glsl_uint64_t_type());
else
}
case SpvOpTypeFloat: {
int bit_size = w[2];
+ val->type->base_type = vtn_base_type_scalar;
val->type->type = bit_size == 64 ? glsl_double_type() : glsl_float_type();
break;
}
unsigned elems = w[3];
assert(glsl_type_is_scalar(base->type));
+ val->type->base_type = vtn_base_type_vector;
val->type->type = glsl_vector_type(glsl_get_base_type(base->type), elems);
-
- /* Vectors implicitly have sizeof(base_type) stride. For now, this
- * is always 4 bytes. This will have to change if we want to start
- * supporting doubles or half-floats.
- */
- val->type->stride = 4;
+ val->type->stride = glsl_get_bit_size(base->type) / 8;
val->type->array_element = base;
break;
}
unsigned columns = w[3];
assert(glsl_type_is_vector(base->type));
+ val->type->base_type = vtn_base_type_matrix;
val->type->type = glsl_matrix_type(glsl_get_base_type(base->type),
glsl_get_vector_elements(base->type),
columns);
assert(!glsl_type_is_error(val->type->type));
+ val->type->length = columns;
val->type->array_element = base;
val->type->row_major = false;
val->type->stride = 0;
struct vtn_type *array_element =
vtn_value(b, w[2], vtn_value_type_type)->type;
- unsigned length;
if (opcode == SpvOpTypeRuntimeArray) {
/* A length of 0 is used to denote unsized arrays */
- length = 0;
+ val->type->length = 0;
} else {
- length =
+ val->type->length =
vtn_value(b, w[3], vtn_value_type_constant)->constant->values[0].u32[0];
}
- val->type->type = glsl_array_type(array_element->type, length);
+ val->type->base_type = vtn_base_type_array;
+ val->type->type = glsl_array_type(array_element->type, val->type->length);
val->type->array_element = array_element;
val->type->stride = 0;
break;
case SpvOpTypeStruct: {
unsigned num_fields = count - 2;
+ val->type->base_type = vtn_base_type_struct;
+ val->type->length = num_fields;
val->type->members = ralloc_array(b, struct vtn_type *, num_fields);
val->type->offsets = ralloc_array(b, unsigned, num_fields);
};
vtn_foreach_decoration(b, val, struct_member_decoration_cb, &ctx);
+ vtn_foreach_decoration(b, val, struct_member_matrix_stride_cb, &ctx);
const char *name = val->name ? val->name : "struct";
}
case SpvOpTypeFunction: {
- const struct glsl_type *return_type =
- vtn_value(b, w[2], vtn_value_type_type)->type->type;
- NIR_VLA(struct glsl_function_param, params, count - 3);
- for (unsigned i = 0; i < count - 3; i++) {
- params[i].type = vtn_value(b, w[i + 3], vtn_value_type_type)->type->type;
+ val->type->base_type = vtn_base_type_function;
+ val->type->type = NULL;
+
+ val->type->return_type = vtn_value(b, w[2], vtn_value_type_type)->type;
- /* FIXME: */
- params[i].in = true;
- params[i].out = true;
+ const unsigned num_params = count - 3;
+ val->type->length = num_params;
+ val->type->params = ralloc_array(b, struct vtn_type *, num_params);
+ for (unsigned i = 0; i < count - 3; i++) {
+ val->type->params[i] =
+ vtn_value(b, w[i + 3], vtn_value_type_type)->type;
}
- val->type->type = glsl_function_type(return_type, params, count - 3);
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->storage_class = storage_class;
+ val->type->deref = deref_type;
+
+ if (storage_class == SpvStorageClassUniform ||
+ storage_class == SpvStorageClassStorageBuffer) {
+ /* These can actually be stored to nir_variables and used as SSA
+ * values so they need a real glsl_type.
+ */
+ val->type->type = glsl_vector_type(GLSL_TYPE_UINT, 2);
+ }
break;
+ }
case SpvOpTypeImage: {
+ val->type->base_type = vtn_base_type_image;
+
const struct glsl_type *sampled_type =
vtn_value(b, w[2], vtn_value_type_type)->type->type;
val->type->image_format = translate_image_format(format);
if (sampled == 1) {
+ val->type->sampled = true;
val->type->type = glsl_sampler_type(dim, is_shadow, is_array,
glsl_get_base_type(sampled_type));
} else if (sampled == 2) {
assert(!is_shadow);
+ val->type->sampled = false;
val->type->type = glsl_image_type(dim, is_array,
glsl_get_base_type(sampled_type));
} else {
* matters is that it's a sampler type as opposed to an integer type
* so the backend knows what to do.
*/
+ val->type->base_type = vtn_base_type_sampler;
val->type->type = glsl_bare_sampler_type();
break;
{
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:
vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
+ struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
struct nir_function *callee =
vtn_value(b, w[3], vtn_value_type_function)->func->impl->function;
for (unsigned i = 0; i < call->num_params; i++) {
unsigned arg_id = w[4 + i];
struct vtn_value *arg = vtn_untyped_value(b, arg_id);
- if (arg->value_type == vtn_value_type_pointer) {
+ if (arg->value_type == vtn_value_type_pointer &&
+ arg->pointer->ptr_type->type == NULL) {
nir_deref_var *d = vtn_pointer_to_deref(b, arg->pointer);
call->params[i] = nir_deref_var_clone(d, call);
} else {
}
nir_variable *out_tmp = NULL;
+ assert(res_type->type == callee->return_type);
if (!glsl_type_is_void(callee->return_type)) {
out_tmp = nir_local_variable_create(b->impl, callee->return_type,
"out_tmp");
if (glsl_type_is_void(callee->return_type)) {
vtn_push_value(b, w[2], vtn_value_type_undef);
} else {
- struct vtn_value *retval = vtn_push_value(b, w[2], vtn_value_type_ssa);
- retval->ssa = vtn_local_load(b, call->return_deref);
+ vtn_push_ssa(b, w[2], res_type, vtn_local_load(b, call->return_deref));
}
}
intrin->src[2] = nir_src_for_ssa(vtn_ssa_value(b, w[3])->def);
break;
+ case SpvOpAtomicCompareExchange:
case SpvOpAtomicIIncrement:
case SpvOpAtomicIDecrement:
case SpvOpAtomicExchange:
} else {
assert(ptr->mode == vtn_variable_mode_ssbo);
nir_ssa_def *offset, *index;
- struct vtn_type *type;
- offset = vtn_pointer_to_offset(b, ptr, &index, &type, NULL, false);
+ offset = vtn_pointer_to_offset(b, ptr, &index, NULL);
nir_intrinsic_op op = get_ssbo_nir_atomic_op(opcode);
spv_check_supported(multiview, cap);
break;
+ case SpvCapabilityVariablePointersStorageBuffer:
+ case SpvCapabilityVariablePointers:
+ spv_check_supported(variable_pointers, cap);
+ break;
+
default:
unreachable("Unhandled capability");
}
case SpvOpCopyMemory:
case SpvOpCopyMemorySized:
case SpvOpAccessChain:
+ case SpvOpPtrAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpArrayLength:
vtn_handle_variables(b, opcode, w, count);
break;
}
+ case SpvOpSelect: {
+ /* Handle OpSelect up-front here because it needs to be able to handle
+ * pointers and not just regular vectors and scalars.
+ */
+ struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
+ struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, res_type->type);
+ ssa->def = nir_bcsel(&b->nb, vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def,
+ vtn_ssa_value(b, w[5])->def);
+ vtn_push_ssa(b, w[2], res_type, ssa);
+ break;
+ }
+
case SpvOpSNegate:
case SpvOpFNegate:
case SpvOpNot:
case SpvOpBitwiseOr:
case SpvOpBitwiseXor:
case SpvOpBitwiseAnd:
- case SpvOpSelect:
case SpvOpIEqual:
case SpvOpFOrdEqual:
case SpvOpFUnordEqual: