nir_load_const_instr *load =
nir_load_const_instr_create(b->shader, num_components, bit_size);
- memcpy(load->value, constant->values[0],
+ memcpy(load->value, constant->values,
sizeof(nir_const_value) * load->def.num_components);
nir_instr_insert_before_cf_list(&b->nb.impl->body, &load->instr);
val->def = &load->def;
} else {
assert(glsl_type_is_matrix(type));
- unsigned rows = glsl_get_vector_elements(val->type);
unsigned columns = glsl_get_matrix_columns(val->type);
val->elems = ralloc_array(b, struct vtn_ssa_value *, columns);
-
- for (unsigned i = 0; i < columns; i++) {
- struct vtn_ssa_value *col_val = rzalloc(b, struct vtn_ssa_value);
- col_val->type = glsl_get_column_type(val->type);
- nir_load_const_instr *load =
- nir_load_const_instr_create(b->shader, rows, bit_size);
-
- memcpy(load->value, constant->values[i],
- sizeof(nir_const_value) * load->def.num_components);
-
- nir_instr_insert_before_cf_list(&b->nb.impl->body, &load->instr);
- col_val->def = &load->def;
-
- val->elems[i] = col_val;
- }
+ const struct glsl_type *column_type = glsl_get_column_type(val->type);
+ for (unsigned i = 0; i < columns; i++)
+ val->elems[i] = vtn_const_ssa_value(b, constant->elements[i],
+ column_type);
}
break;
}
if (strcmp(ext, "GLSL.std.450") == 0) {
val->ext_handler = vtn_handle_glsl450_instruction;
} else if ((strcmp(ext, "SPV_AMD_gcn_shader") == 0)
- && (b->options && b->options->caps.gcn_shader)) {
+ && (b->options && b->options->caps.amd_gcn_shader)) {
val->ext_handler = vtn_handle_amd_gcn_shader_instruction;
+ } else if ((strcmp(ext, "SPV_AMD_shader_ballot") == 0)
+ && (b->options && b->options->caps.amd_shader_ballot)) {
+ val->ext_handler = vtn_handle_amd_shader_ballot_instruction;
} else if ((strcmp(ext, "SPV_AMD_shader_trinary_minmax") == 0)
- && (b->options && b->options->caps.trinary_minmax)) {
+ && (b->options && b->options->caps.amd_trinary_minmax)) {
val->ext_handler = vtn_handle_amd_shader_trinary_minmax_instruction;
} else if (strcmp(ext, "OpenCL.std") == 0) {
val->ext_handler = vtn_handle_opencl_instruction;
case SpvOpDecorate:
case SpvOpDecorateId:
case SpvOpMemberDecorate:
- case SpvOpDecorateStringGOOGLE:
- case SpvOpMemberDecorateStringGOOGLE:
+ case SpvOpDecorateString:
+ case SpvOpMemberDecorateString:
case SpvOpExecutionMode:
case SpvOpExecutionModeId: {
struct vtn_value *val = vtn_untyped_value(b, target);
switch (opcode) {
case SpvOpDecorate:
case SpvOpDecorateId:
- case SpvOpDecorateStringGOOGLE:
+ case SpvOpDecorateString:
dec->scope = VTN_DEC_DECORATION;
break;
case SpvOpMemberDecorate:
- case SpvOpMemberDecorateStringGOOGLE:
+ case SpvOpMemberDecorateString:
dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(w++);
vtn_fail_if(dec->scope < VTN_DEC_STRUCT_MEMBER0, /* overflow */
"Member argument of OpMemberDecorate too large");
struct vtn_type *type = val->type;
if (dec->decoration == SpvDecorationArrayStride) {
- vtn_fail_if(dec->operands[0] == 0, "ArrayStride must be non-zero");
- type->stride = dec->operands[0];
+ if (vtn_type_contains_block(b, type)) {
+ vtn_warn("The ArrayStride decoration cannot be applied to an array "
+ "type which contains a structure type decorated Block "
+ "or BufferBlock");
+ /* Ignore the decoration */
+ } else {
+ vtn_fail_if(dec->operands[0] == 0, "ArrayStride must be non-zero");
+ type->stride = dec->operands[0];
+ }
}
}
switch (dec->decoration) {
case SpvDecorationRelaxedPrecision:
case SpvDecorationUniform:
+ case SpvDecorationUniformId:
break; /* FIXME: Do nothing with this for now. */
case SpvDecorationNonWritable:
vtn_handle_access_qualifier(b, ctx->type, member, ACCESS_NON_WRITEABLE);
}
break;
- case SpvDecorationHlslSemanticGOOGLE:
- /* HLSL semantic decorations can safely be ignored by the driver. */
+ case SpvDecorationUserSemantic:
+ /* User semantic decorations can safely be ignored by the driver. */
break;
default:
case SpvDecorationNonWritable:
case SpvDecorationNonReadable:
case SpvDecorationUniform:
+ case SpvDecorationUniformId:
case SpvDecorationLocation:
case SpvDecorationComponent:
case SpvDecorationOffset:
case SpvDecorationXfbBuffer:
case SpvDecorationXfbStride:
- case SpvDecorationHlslSemanticGOOGLE:
+ case SpvDecorationUserSemantic:
vtn_warn("Decoration only allowed for struct members: %s",
spirv_decoration_to_string(dec->decoration));
break;
}
}
-static struct vtn_type *
-vtn_type_layout_std430(struct vtn_builder *b, struct vtn_type *type,
- uint32_t *size_out, uint32_t *align_out)
-{
- switch (type->base_type) {
- case vtn_base_type_scalar: {
- uint32_t comp_size = glsl_type_is_boolean(type->type)
- ? 4 : glsl_get_bit_size(type->type) / 8;
- *size_out = comp_size;
- *align_out = comp_size;
- return type;
- }
-
- case vtn_base_type_vector: {
- uint32_t comp_size = glsl_type_is_boolean(type->type)
- ? 4 : glsl_get_bit_size(type->type) / 8;
- unsigned align_comps = type->length == 3 ? 4 : type->length;
- *size_out = comp_size * type->length,
- *align_out = comp_size * align_comps;
- return type;
- }
-
- case vtn_base_type_matrix:
- case vtn_base_type_array: {
- /* We're going to add an array stride */
- type = vtn_type_copy(b, type);
- uint32_t elem_size, elem_align;
- type->array_element = vtn_type_layout_std430(b, type->array_element,
- &elem_size, &elem_align);
- type->stride = vtn_align_u32(elem_size, elem_align);
- *size_out = type->stride * type->length;
- *align_out = elem_align;
- return type;
- }
-
- case vtn_base_type_struct: {
- /* We're going to add member offsets */
- type = vtn_type_copy(b, type);
- uint32_t offset = 0;
- uint32_t align = 0;
- for (unsigned i = 0; i < type->length; i++) {
- uint32_t mem_size, mem_align;
- type->members[i] = vtn_type_layout_std430(b, type->members[i],
- &mem_size, &mem_align);
- offset = vtn_align_u32(offset, mem_align);
- type->offsets[i] = offset;
- offset += mem_size;
- align = MAX2(align, mem_align);
- }
- *size_out = offset;
- *align_out = align;
- return type;
- }
-
- default:
- unreachable("Invalid SPIR-V type for std430");
- }
-}
-
static void
vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
/* A length of 0 is used to denote unsized arrays */
val->type->length = 0;
} else {
- val->type->length =
- vtn_value(b, w[3], vtn_value_type_constant)->constant->values[0][0].u32;
+ val->type->length = vtn_constant_uint(b, w[3]);
}
val->type->base_type = vtn_base_type_array;
/* These can actually be stored to nir_variables and used as SSA
* values so they need a real glsl_type.
*/
- nir_address_format addr_format = nir_address_format_logical;
- switch (storage_class) {
- case SpvStorageClassUniform:
- addr_format = b->options->ubo_addr_format;
- break;
- case SpvStorageClassStorageBuffer:
- addr_format = b->options->ssbo_addr_format;
- break;
- case SpvStorageClassPhysicalStorageBufferEXT:
- addr_format = b->options->phys_ssbo_addr_format;
- break;
- case SpvStorageClassPushConstant:
- addr_format = b->options->push_const_addr_format;
- break;
- case SpvStorageClassWorkgroup:
- addr_format = b->options->shared_addr_format;
- break;
- case SpvStorageClassCrossWorkgroup:
- addr_format = b->options->global_addr_format;
- break;
- case SpvStorageClassFunction:
- if (b->physical_ptrs)
- addr_format = b->options->temp_addr_format;
- 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.
- */
- break;
- }
- val->type->type = nir_address_format_to_glsl_type(addr_format);
+ enum vtn_variable_mode mode = vtn_storage_class_to_mode(
+ b, storage_class, NULL, NULL);
+ val->type->type = nir_address_format_to_glsl_type(
+ vtn_mode_to_address_format(b, mode));
} else {
vtn_fail_if(val->type->storage_class != storage_class,
"The storage classes of an OpTypePointer and any "
val->type->deref = vtn_value(b, w[3], vtn_value_type_type)->type;
- vtn_foreach_decoration(b, val, array_stride_decoration_cb, NULL);
+ /* Only certain storage classes use ArrayStride. The others (in
+ * particular Workgroup) are expected to be laid out by the driver.
+ */
+ switch (storage_class) {
+ case SpvStorageClassUniform:
+ case SpvStorageClassPushConstant:
+ case SpvStorageClassStorageBuffer:
+ case SpvStorageClassPhysicalStorageBufferEXT:
+ vtn_foreach_decoration(b, val, array_stride_decoration_cb, NULL);
+ break;
+ default:
+ /* Nothing to do. */
+ break;
+ }
if (b->physical_ptrs) {
switch (storage_class) {
break;
}
}
-
- 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;
}
/* Nothing to do here. It's already initialized to zero */
break;
- case vtn_base_type_pointer:
+ case vtn_base_type_pointer: {
+ enum vtn_variable_mode mode = vtn_storage_class_to_mode(
+ b, type->storage_class, type->deref, NULL);
+ nir_address_format addr_format = vtn_mode_to_address_format(b, mode);
+
+ const nir_const_value *null_value = nir_address_format_null_value(addr_format);
+ memcpy(c->values, null_value,
+ sizeof(nir_const_value) * nir_address_format_num_components(addr_format));
+ break;
+ }
+
case vtn_base_type_void:
case vtn_base_type_image:
case vtn_base_type_sampler:
case vtn_base_type_sampled_image:
case vtn_base_type_function:
- /* For pointers and other things, we have to return something but it
- * doesn't matter what.
- */
+ /* For those we have to return something but it doesn't matter what. */
break;
case vtn_base_type_matrix:
opcode == SpvOpSpecConstantFalse)
int_val = get_specialization(b, val, int_val);
- val->constant->values[0][0].b = int_val != 0;
+ val->constant->values[0].b = int_val != 0;
break;
}
int bit_size = glsl_get_bit_size(val->type->type);
switch (bit_size) {
case 64:
- val->constant->values[0][0].u64 = vtn_u64_literal(&w[3]);
+ val->constant->values[0].u64 = vtn_u64_literal(&w[3]);
break;
case 32:
- val->constant->values[0][0].u32 = w[3];
+ val->constant->values[0].u32 = w[3];
break;
case 16:
- val->constant->values[0][0].u16 = w[3];
+ val->constant->values[0].u16 = w[3];
break;
case 8:
- val->constant->values[0][0].u8 = w[3];
+ val->constant->values[0].u8 = w[3];
break;
default:
vtn_fail("Unsupported SpvOpConstant bit size: %u", bit_size);
int bit_size = glsl_get_bit_size(val->type->type);
switch (bit_size) {
case 64:
- val->constant->values[0][0].u64 =
+ val->constant->values[0].u64 =
get_specialization64(b, val, vtn_u64_literal(&w[3]));
break;
case 32:
- val->constant->values[0][0].u32 = get_specialization(b, val, w[3]);
+ val->constant->values[0].u32 = get_specialization(b, val, w[3]);
break;
case 16:
- val->constant->values[0][0].u16 = get_specialization(b, val, w[3]);
+ val->constant->values[0].u16 = get_specialization(b, val, w[3]);
break;
case 8:
- val->constant->values[0][0].u8 = get_specialization(b, val, w[3]);
+ val->constant->values[0].u8 = get_specialization(b, val, w[3]);
break;
default:
vtn_fail("Unsupported SpvOpSpecConstant bit size");
case vtn_base_type_vector: {
assert(glsl_type_is_vector(val->type->type));
for (unsigned i = 0; i < elem_count; i++)
- val->constant->values[0][i] = elems[i]->values[0][0];
+ val->constant->values[i] = elems[i]->values[0];
break;
}
case vtn_base_type_matrix:
- assert(glsl_type_is_matrix(val->type->type));
- for (unsigned i = 0; i < elem_count; i++) {
- unsigned components =
- glsl_get_components(glsl_get_column_type(val->type->type));
- memcpy(val->constant->values[i], elems[i]->values,
- sizeof(nir_const_value) * components);
- }
- break;
-
case vtn_base_type_struct:
case vtn_base_type_array:
ralloc_steal(val->constant, elems);
vtn_assert(bit_size == bit_size0 && bit_size == bit_size1);
(void)bit_size0; (void)bit_size1;
- if (bit_size == 64) {
- uint64_t u64[8];
- if (v0->value_type == vtn_value_type_constant) {
- for (unsigned i = 0; i < len0; i++)
- u64[i] = v0->constant->values[0][i].u64;
- }
- if (v1->value_type == vtn_value_type_constant) {
- for (unsigned i = 0; i < len1; i++)
- u64[len0 + i] = v1->constant->values[0][i].u64;
- }
+ nir_const_value undef = { .u64 = 0xdeadbeefdeadbeef };
+ nir_const_value combined[NIR_MAX_VEC_COMPONENTS * 2];
- for (unsigned i = 0, j = 0; i < count - 6; i++, j++) {
- uint32_t comp = w[i + 6];
- /* If component is not used, set the value to a known constant
- * to detect if it is wrongly used.
- */
- if (comp == (uint32_t)-1)
- val->constant->values[0][j].u64 = 0xdeadbeefdeadbeef;
- else
- val->constant->values[0][j].u64 = u64[comp];
- }
- } else {
- /* This is for both 32-bit and 16-bit values */
- uint32_t u32[8];
- if (v0->value_type == vtn_value_type_constant) {
- for (unsigned i = 0; i < len0; i++)
- u32[i] = v0->constant->values[0][i].u32;
- }
- if (v1->value_type == vtn_value_type_constant) {
- for (unsigned i = 0; i < len1; i++)
- u32[len0 + i] = v1->constant->values[0][i].u32;
- }
+ if (v0->value_type == vtn_value_type_constant) {
+ for (unsigned i = 0; i < len0; i++)
+ combined[i] = v0->constant->values[i];
+ }
+ if (v1->value_type == vtn_value_type_constant) {
+ for (unsigned i = 0; i < len1; i++)
+ combined[len0 + i] = v1->constant->values[i];
+ }
- for (unsigned i = 0, j = 0; i < count - 6; i++, j++) {
- uint32_t comp = w[i + 6];
+ for (unsigned i = 0, j = 0; i < count - 6; i++, j++) {
+ uint32_t comp = w[i + 6];
+ if (comp == (uint32_t)-1) {
/* If component is not used, set the value to a known constant
* to detect if it is wrongly used.
*/
- if (comp == (uint32_t)-1)
- val->constant->values[0][j].u32 = 0xdeadbeef;
- else
- val->constant->values[0][j].u32 = u32[comp];
+ val->constant->values[j] = undef;
+ } else {
+ vtn_fail_if(comp >= len0 + len1,
+ "All Component literals must either be FFFFFFFF "
+ "or in [0, N - 1] (inclusive).");
+ val->constant->values[j] = combined[comp];
}
}
break;
}
int elem = -1;
- int col = 0;
const struct vtn_type *type = comp->type;
for (unsigned i = deref_start; i < count; i++) {
vtn_fail_if(w[i] > type->length,
break;
case vtn_base_type_matrix:
- assert(col == 0 && elem == -1);
- col = w[i];
- elem = 0;
- type = type->array_element;
- break;
-
case vtn_base_type_array:
c = &(*c)->elements[w[i]];
type = type->array_element;
} else {
unsigned num_components = type->length;
for (unsigned i = 0; i < num_components; i++)
- val->constant->values[0][i] = (*c)->values[col][elem + i];
+ val->constant->values[i] = (*c)->values[elem + i];
}
} else {
struct vtn_value *insert =
} else {
unsigned num_components = type->length;
for (unsigned i = 0; i < num_components; i++)
- (*c)->values[col][elem + i] = insert->constant->values[0][i];
+ (*c)->values[elem + i] = insert->constant->values[i];
}
}
break;
switch (opcode) {
case SpvOpSConvert:
case SpvOpFConvert:
+ case SpvOpUConvert:
/* We have a source in a conversion */
src_alu_type =
nir_get_nir_type_for_glsl_type(
if (!nir_alu_type_get_type_size(nir_op_infos[op].input_types[i]))
bit_size = glsl_get_bit_size(src_val->type->type);
+ unsigned src_comps = nir_op_infos[op].input_sizes[i] ?
+ nir_op_infos[op].input_sizes[i] :
+ num_components;
+
unsigned j = swap ? 1 - i : i;
- memcpy(src[j], src_val->constant->values[0], sizeof(src[j]));
+ for (unsigned c = 0; c < src_comps; c++)
+ src[j][c] = src_val->constant->values[c];
}
/* fix up fixed size sources */
nir_const_value *srcs[3] = {
src[0], src[1], src[2],
};
- nir_eval_const_opcode(op, val->constant->values[0], num_components, bit_size, srcs);
+ nir_eval_const_opcode(op, val->constant->values, num_components, bit_size, srcs);
break;
} /* default */
}
vtn_value(b, w[4], vtn_value_type_pointer)->pointer;
return;
} else if (opcode == SpvOpImage) {
- struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_pointer);
struct vtn_value *src_val = vtn_untyped_value(b, w[3]);
if (src_val->value_type == vtn_value_type_sampled_image) {
- val->pointer = src_val->sampled_image->image;
+ vtn_push_value_pointer(b, w[2], src_val->sampled_image->image);
} else {
vtn_assert(src_val->value_type == vtn_value_type_pointer);
- val->pointer = src_val->pointer;
+ vtn_push_value_pointer(b, w[2], src_val->pointer);
}
return;
}
struct vtn_type *ret_type = vtn_value(b, w[1], vtn_value_type_type)->type;
- struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
struct vtn_sampled_image sampled;
struct vtn_value *sampled_val = vtn_untyped_value(b, w[3]);
case SpvOpImageGather:
/* This has a component as its next source */
- gather_component =
- vtn_value(b, w[idx++], vtn_value_type_constant)->constant->values[0][0].u32;
+ gather_component = vtn_constant_uint(b, w[idx++]);
break;
default:
unsigned bit_size = glsl_get_bit_size(vec_type->type);
for (uint32_t i = 0; i < 4; i++) {
const nir_const_value *cvec =
- gather_offsets->constant->elements[i]->values[0];
+ gather_offsets->constant->elements[i]->values;
for (uint32_t j = 0; j < 2; j++) {
switch (bit_size) {
case 8: instr->tg4_offsets[i][j] = cvec[j].i8; break;
}
}
- val->ssa = vtn_create_ssa_value(b, ret_type->type);
- val->ssa->def = &instr->dest.ssa;
+ struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, ret_type->type);
+ ssa->def = &instr->dest.ssa;
+ vtn_push_ssa(b, w[2], ret_type, ssa);
nir_builder_instr_insert(&b->nb, &instr->instr);
}
for (unsigned i = 0; i < 4; i++)
swizzle[i] = MIN2(i, dim - 1);
- return nir_swizzle(&b->nb, coord->def, swizzle, 4, false);
+ return nir_swizzle(&b->nb, coord->def, swizzle, 4);
}
static nir_ssa_def *
unsigned swiz[4];
for (unsigned i = 0; i < 4; i++)
swiz[i] = i < value->num_components ? i : 0;
- return nir_swizzle(b, value, swiz, 4, false);
+ return nir_swizzle(b, value, swiz, 4);
}
static void
OP(AtomicIDecrement, atomic_add)
OP(AtomicIAdd, atomic_add)
OP(AtomicISub, atomic_add)
- OP(AtomicSMin, atomic_min)
- OP(AtomicUMin, atomic_min)
- OP(AtomicSMax, atomic_max)
- OP(AtomicUMax, atomic_max)
+ OP(AtomicSMin, atomic_imin)
+ OP(AtomicUMin, atomic_umin)
+ OP(AtomicSMax, atomic_imax)
+ OP(AtomicUMax, atomic_umax)
OP(AtomicAnd, atomic_and)
OP(AtomicOr, atomic_or)
OP(AtomicXor, atomic_xor)
intrin->src[2] = nir_src_for_ssa(image.sample);
}
+ nir_intrinsic_set_access(intrin, image.image->access);
+
switch (opcode) {
case SpvOpAtomicLoad:
case SpvOpImageQuerySize:
}
if (opcode != SpvOpImageWrite && opcode != SpvOpAtomicStore) {
- struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type;
unsigned dest_components = glsl_get_vector_elements(type->type);
if (intrin->num_components != dest_components)
result = nir_channels(&b->nb, result, (1 << dest_components) - 1);
- val->ssa = vtn_create_ssa_value(b, type->type);
+ struct vtn_value *val =
+ vtn_push_ssa(b, w[2], type, vtn_create_ssa_value(b, type->type));
val->ssa->def = result;
} else {
nir_builder_instr_insert(&b->nb, &intrin->instr);
}
}
-static nir_intrinsic_op
-get_shared_nir_atomic_op(struct vtn_builder *b, SpvOp opcode)
-{
- switch (opcode) {
- case SpvOpAtomicLoad: return nir_intrinsic_load_shared;
- case SpvOpAtomicStore: return nir_intrinsic_store_shared;
-#define OP(S, N) case SpvOp##S: return nir_intrinsic_shared_##N;
- OP(AtomicExchange, atomic_exchange)
- OP(AtomicCompareExchange, atomic_comp_swap)
- OP(AtomicCompareExchangeWeak, atomic_comp_swap)
- OP(AtomicIIncrement, atomic_add)
- OP(AtomicIDecrement, atomic_add)
- OP(AtomicIAdd, atomic_add)
- OP(AtomicISub, atomic_add)
- OP(AtomicSMin, atomic_imin)
- OP(AtomicUMin, atomic_umin)
- OP(AtomicSMax, atomic_imax)
- OP(AtomicUMax, atomic_umax)
- OP(AtomicAnd, atomic_and)
- OP(AtomicOr, atomic_or)
- OP(AtomicXor, atomic_xor)
-#undef OP
- default:
- vtn_fail_with_opcode("Invalid shared atomic", opcode);
- }
-}
-
static nir_intrinsic_op
get_deref_nir_atomic_op(struct vtn_builder *b, SpvOp opcode)
{
nir_ssa_def *offset, *index;
offset = vtn_pointer_to_offset(b, ptr, &index);
- nir_intrinsic_op op;
- if (ptr->mode == vtn_variable_mode_ssbo) {
- op = get_ssbo_nir_atomic_op(b, opcode);
- } else {
- vtn_assert(ptr->mode == vtn_variable_mode_workgroup &&
- b->options->lower_workgroup_access_to_offsets);
- op = get_shared_nir_atomic_op(b, opcode);
- }
+ assert(ptr->mode == vtn_variable_mode_ssbo);
+ nir_intrinsic_op op = get_ssbo_nir_atomic_op(b, opcode);
atomic = nir_intrinsic_instr_create(b->nb.shader, op);
int src = 0;
glsl_get_vector_elements(type->type),
glsl_get_bit_size(type->type), NULL);
- struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
- val->ssa = rzalloc(b, struct vtn_ssa_value);
- val->ssa->def = &atomic->dest.ssa;
- val->ssa->type = type->type;
+ struct vtn_ssa_value *ssa = rzalloc(b, struct vtn_ssa_value);
+ ssa->def = &atomic->dest.ssa;
+ ssa->type = type->type;
+ vtn_push_ssa(b, w[2], type, ssa);
}
nir_builder_instr_insert(&b->nb, &atomic->instr);
vtn_handle_composite(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
- struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
- const struct glsl_type *type =
- vtn_value(b, w[1], vtn_value_type_type)->type->type;
- val->ssa = vtn_create_ssa_value(b, type);
+ struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type;
+ struct vtn_ssa_value *ssa = vtn_create_ssa_value(b, type->type);
switch (opcode) {
case SpvOpVectorExtractDynamic:
- val->ssa->def = vtn_vector_extract_dynamic(b, vtn_ssa_value(b, w[3])->def,
- vtn_ssa_value(b, w[4])->def);
+ ssa->def = vtn_vector_extract_dynamic(b, vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def);
break;
case SpvOpVectorInsertDynamic:
- val->ssa->def = vtn_vector_insert_dynamic(b, vtn_ssa_value(b, w[3])->def,
- vtn_ssa_value(b, w[4])->def,
- vtn_ssa_value(b, w[5])->def);
+ ssa->def = vtn_vector_insert_dynamic(b, vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def,
+ vtn_ssa_value(b, w[5])->def);
break;
case SpvOpVectorShuffle:
- val->ssa->def = vtn_vector_shuffle(b, glsl_get_vector_elements(type),
- vtn_ssa_value(b, w[3])->def,
- vtn_ssa_value(b, w[4])->def,
- w + 5);
+ ssa->def = vtn_vector_shuffle(b, glsl_get_vector_elements(type->type),
+ vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def,
+ w + 5);
break;
case SpvOpCompositeConstruct: {
unsigned elems = count - 3;
assume(elems >= 1);
- if (glsl_type_is_vector_or_scalar(type)) {
+ if (glsl_type_is_vector_or_scalar(type->type)) {
nir_ssa_def *srcs[NIR_MAX_VEC_COMPONENTS];
for (unsigned i = 0; i < elems; i++)
srcs[i] = vtn_ssa_value(b, w[3 + i])->def;
- val->ssa->def =
- vtn_vector_construct(b, glsl_get_vector_elements(type),
+ ssa->def =
+ vtn_vector_construct(b, glsl_get_vector_elements(type->type),
elems, srcs);
} else {
- val->ssa->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+ ssa->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
for (unsigned i = 0; i < elems; i++)
- val->ssa->elems[i] = vtn_ssa_value(b, w[3 + i]);
+ ssa->elems[i] = vtn_ssa_value(b, w[3 + i]);
}
break;
}
case SpvOpCompositeExtract:
- val->ssa = vtn_composite_extract(b, vtn_ssa_value(b, w[3]),
- w + 4, count - 4);
+ ssa = vtn_composite_extract(b, vtn_ssa_value(b, w[3]),
+ w + 4, count - 4);
break;
case SpvOpCompositeInsert:
- val->ssa = vtn_composite_insert(b, vtn_ssa_value(b, w[4]),
- vtn_ssa_value(b, w[3]),
- w + 5, count - 5);
+ ssa = vtn_composite_insert(b, vtn_ssa_value(b, w[4]),
+ vtn_ssa_value(b, w[3]),
+ w + 5, count - 5);
break;
+ case SpvOpCopyLogical:
case SpvOpCopyObject:
- val->ssa = vtn_composite_copy(b, vtn_ssa_value(b, w[3]));
+ ssa = vtn_composite_copy(b, vtn_ssa_value(b, w[3]));
break;
default:
vtn_fail_with_opcode("unknown composite operation", opcode);
}
+
+ vtn_push_ssa(b, w[2], type, ssa);
}
static void
}
case SpvOpControlBarrier: {
- SpvScope execution_scope = vtn_constant_uint(b, w[1]);
- if (execution_scope == SpvScopeWorkgroup)
- vtn_emit_barrier(b, nir_intrinsic_barrier);
-
SpvScope memory_scope = vtn_constant_uint(b, w[2]);
SpvMemorySemanticsMask memory_semantics = vtn_constant_uint(b, w[3]);
vtn_emit_memory_barrier(b, memory_scope, memory_semantics);
+
+ SpvScope execution_scope = vtn_constant_uint(b, w[1]);
+ if (execution_scope == SpvScopeWorkgroup)
+ vtn_emit_barrier(b, nir_intrinsic_barrier);
break;
}
case SpvCapabilityImageReadWrite:
case SpvCapabilityImageMipmap:
case SpvCapabilityPipes:
- case SpvCapabilityGroups:
case SpvCapabilityDeviceEnqueue:
case SpvCapabilityLiteralSampler:
case SpvCapabilityGenericPointer:
spv_check_supported(subgroup_basic, cap);
break;
+ case SpvCapabilitySubgroupVoteKHR:
case SpvCapabilityGroupNonUniformVote:
spv_check_supported(subgroup_vote, cap);
break;
spv_check_supported(subgroup_arithmetic, cap);
break;
+ case SpvCapabilityGroups:
+ spv_check_supported(amd_shader_ballot, cap);
+ break;
+
case SpvCapabilityVariablePointersStorageBuffer:
case SpvCapabilityVariablePointers:
spv_check_supported(variable_pointers, cap);
spv_check_supported(storage_16bit, cap);
break;
+ case SpvCapabilityShaderLayer:
+ case SpvCapabilityShaderViewportIndex:
case SpvCapabilityShaderViewportIndexLayerEXT:
spv_check_supported(shader_viewport_index_layer, cap);
break;
case SpvCapabilitySampleMaskPostDepthCoverage:
spv_check_supported(post_depth_coverage, cap);
+
+ case SpvCapabilityDenormFlushToZero:
+ case SpvCapabilityDenormPreserve:
+ case SpvCapabilitySignedZeroInfNanPreserve:
+ case SpvCapabilityRoundingModeRTE:
+ case SpvCapabilityRoundingModeRTZ:
+ spv_check_supported(float_controls, cap);
break;
case SpvCapabilityPhysicalStorageBufferAddressesEXT:
spv_check_supported(float16, cap);
break;
+ case SpvCapabilityFragmentShaderSampleInterlockEXT:
+ spv_check_supported(fragment_shader_sample_interlock, cap);
+ break;
+
+ case SpvCapabilityFragmentShaderPixelInterlockEXT:
+ spv_check_supported(fragment_shader_pixel_interlock, cap);
+ break;
+
+ case SpvCapabilityDemoteToHelperInvocationEXT:
+ spv_check_supported(demote_to_helper_invocation, cap);
+ break;
+
default:
vtn_fail("Unhandled capability: %s (%u)",
spirv_capability_to_string(cap), cap);
case SpvOpMemberDecorate:
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
- case SpvOpDecorateStringGOOGLE:
- case SpvOpMemberDecorateStringGOOGLE:
+ case SpvOpDecorateString:
+ case SpvOpMemberDecorateString:
vtn_handle_decoration(b, opcode, w, count);
break;
b->shader->info.cs.derivative_group = DERIVATIVE_GROUP_LINEAR;
break;
+ case SpvExecutionModePixelInterlockOrderedEXT:
+ vtn_assert(b->shader->info.stage == MESA_SHADER_FRAGMENT);
+ b->shader->info.fs.pixel_interlock_ordered = true;
+ break;
+
+ case SpvExecutionModePixelInterlockUnorderedEXT:
+ vtn_assert(b->shader->info.stage == MESA_SHADER_FRAGMENT);
+ b->shader->info.fs.pixel_interlock_unordered = true;
+ break;
+
+ case SpvExecutionModeSampleInterlockOrderedEXT:
+ vtn_assert(b->shader->info.stage == MESA_SHADER_FRAGMENT);
+ b->shader->info.fs.sample_interlock_ordered = true;
+ break;
+
+ case SpvExecutionModeSampleInterlockUnorderedEXT:
+ vtn_assert(b->shader->info.stage == MESA_SHADER_FRAGMENT);
+ b->shader->info.fs.sample_interlock_unordered = true;
+ break;
+
+ case SpvExecutionModeDenormPreserve:
+ case SpvExecutionModeDenormFlushToZero:
+ case SpvExecutionModeSignedZeroInfNanPreserve:
+ case SpvExecutionModeRoundingModeRTE:
+ case SpvExecutionModeRoundingModeRTZ:
+ /* Already handled in vtn_handle_rounding_mode_in_execution_mode() */
+ break;
+
default:
vtn_fail("Unhandled execution mode: %s (%u)",
spirv_executionmode_to_string(mode->exec_mode),
}
}
+static void
+vtn_handle_rounding_mode_in_execution_mode(struct vtn_builder *b, struct vtn_value *entry_point,
+ const struct vtn_decoration *mode, void *data)
+{
+ vtn_assert(b->entry_point == entry_point);
+
+ unsigned execution_mode = 0;
+
+ switch(mode->exec_mode) {
+ case SpvExecutionModeDenormPreserve:
+ switch (mode->operands[0]) {
+ case 16: execution_mode = FLOAT_CONTROLS_DENORM_PRESERVE_FP16; break;
+ case 32: execution_mode = FLOAT_CONTROLS_DENORM_PRESERVE_FP32; break;
+ case 64: execution_mode = FLOAT_CONTROLS_DENORM_PRESERVE_FP64; break;
+ default: vtn_fail("Floating point type not supported");
+ }
+ break;
+ case SpvExecutionModeDenormFlushToZero:
+ switch (mode->operands[0]) {
+ case 16: execution_mode = FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP16; break;
+ case 32: execution_mode = FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP32; break;
+ case 64: execution_mode = FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP64; break;
+ default: vtn_fail("Floating point type not supported");
+ }
+ break;
+ case SpvExecutionModeSignedZeroInfNanPreserve:
+ switch (mode->operands[0]) {
+ case 16: execution_mode = FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP16; break;
+ case 32: execution_mode = FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP32; break;
+ case 64: execution_mode = FLOAT_CONTROLS_SIGNED_ZERO_INF_NAN_PRESERVE_FP64; break;
+ default: vtn_fail("Floating point type not supported");
+ }
+ break;
+ case SpvExecutionModeRoundingModeRTE:
+ switch (mode->operands[0]) {
+ case 16: execution_mode = FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP16; break;
+ case 32: execution_mode = FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP32; break;
+ case 64: execution_mode = FLOAT_CONTROLS_ROUNDING_MODE_RTE_FP64; break;
+ default: vtn_fail("Floating point type not supported");
+ }
+ break;
+ case SpvExecutionModeRoundingModeRTZ:
+ switch (mode->operands[0]) {
+ case 16: execution_mode = FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP16; break;
+ case 32: execution_mode = FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP32; break;
+ case 64: execution_mode = FLOAT_CONTROLS_ROUNDING_MODE_RTZ_FP64; break;
+ default: vtn_fail("Floating point type not supported");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ b->shader->info.float_controls_execution_mode |= execution_mode;
+}
+
static bool
vtn_handle_variable_or_type_instruction(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
case SpvOpMemberDecorate:
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
- case SpvOpDecorateStringGOOGLE:
- case SpvOpMemberDecorateStringGOOGLE:
+ case SpvOpDecorateString:
+ case SpvOpMemberDecorateString:
vtn_fail("Invalid opcode types and variables section");
break;
return true;
}
+static struct vtn_ssa_value *
+vtn_nir_select(struct vtn_builder *b, struct vtn_ssa_value *src0,
+ struct vtn_ssa_value *src1, struct vtn_ssa_value *src2)
+{
+ struct vtn_ssa_value *dest = rzalloc(b, struct vtn_ssa_value);
+ dest->type = src1->type;
+
+ if (glsl_type_is_vector_or_scalar(src1->type)) {
+ dest->def = nir_bcsel(&b->nb, src0->def, src1->def, src2->def);
+ } else {
+ unsigned elems = glsl_get_length(src1->type);
+
+ dest->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+ for (unsigned i = 0; i < elems; i++) {
+ dest->elems[i] = vtn_nir_select(b, src0,
+ src1->elems[i], src2->elems[i]);
+ }
+ }
+
+ return dest;
+}
+
+static void
+vtn_handle_select(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count)
+{
+ /* Handle OpSelect up-front here because it needs to be able to handle
+ * pointers and not just regular vectors and scalars.
+ */
+ struct vtn_value *res_val = vtn_untyped_value(b, w[2]);
+ struct vtn_value *cond_val = vtn_untyped_value(b, w[3]);
+ struct vtn_value *obj1_val = vtn_untyped_value(b, w[4]);
+ struct vtn_value *obj2_val = vtn_untyped_value(b, w[5]);
+
+ vtn_fail_if(obj1_val->type != res_val->type ||
+ obj2_val->type != res_val->type,
+ "Object types must match the result type in OpSelect");
+
+ vtn_fail_if((cond_val->type->base_type != vtn_base_type_scalar &&
+ cond_val->type->base_type != vtn_base_type_vector) ||
+ !glsl_type_is_boolean(cond_val->type->type),
+ "OpSelect must have either a vector of booleans or "
+ "a boolean as Condition type");
+
+ vtn_fail_if(cond_val->type->base_type == vtn_base_type_vector &&
+ (res_val->type->base_type != vtn_base_type_vector ||
+ res_val->type->length != cond_val->type->length),
+ "When Condition type in OpSelect is a vector, the Result "
+ "type must be a vector of the same length");
+
+ switch (res_val->type->base_type) {
+ case vtn_base_type_scalar:
+ case vtn_base_type_vector:
+ case vtn_base_type_matrix:
+ case vtn_base_type_array:
+ case vtn_base_type_struct:
+ /* OK. */
+ break;
+ case vtn_base_type_pointer:
+ /* We need to have actual storage for pointer types. */
+ vtn_fail_if(res_val->type->type == NULL,
+ "Invalid pointer result type for OpSelect");
+ break;
+ default:
+ vtn_fail("Result type of OpSelect must be a scalar, composite, or pointer");
+ }
+
+ struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
+ struct vtn_ssa_value *ssa = vtn_nir_select(b,
+ vtn_ssa_value(b, w[3]), vtn_ssa_value(b, w[4]), vtn_ssa_value(b, w[5]));
+
+ vtn_push_ssa(b, w[2], res_type, ssa);
+}
+
+static void
+vtn_handle_ptr(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count)
+{
+ struct vtn_type *type1 = vtn_untyped_value(b, w[3])->type;
+ struct vtn_type *type2 = vtn_untyped_value(b, w[4])->type;
+ vtn_fail_if(type1->base_type != vtn_base_type_pointer ||
+ type2->base_type != vtn_base_type_pointer,
+ "%s operands must have pointer types",
+ spirv_op_to_string(opcode));
+ vtn_fail_if(type1->storage_class != type2->storage_class,
+ "%s operands must have the same storage class",
+ spirv_op_to_string(opcode));
+
+ struct vtn_type *vtn_type =
+ vtn_value(b, w[1], vtn_value_type_type)->type;
+ const struct glsl_type *type = vtn_type->type;
+
+ nir_address_format addr_format = vtn_mode_to_address_format(
+ b, vtn_storage_class_to_mode(b, type1->storage_class, NULL, NULL));
+
+ nir_ssa_def *def;
+
+ switch (opcode) {
+ case SpvOpPtrDiff: {
+ /* OpPtrDiff returns the difference in number of elements (not byte offset). */
+ unsigned elem_size, elem_align;
+ glsl_get_natural_size_align_bytes(type1->deref->type,
+ &elem_size, &elem_align);
+
+ def = nir_build_addr_isub(&b->nb,
+ vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def,
+ addr_format);
+ def = nir_idiv(&b->nb, def, nir_imm_intN_t(&b->nb, elem_size, def->bit_size));
+ def = nir_i2i(&b->nb, def, glsl_get_bit_size(type));
+ break;
+ }
+
+ case SpvOpPtrEqual:
+ case SpvOpPtrNotEqual: {
+ def = nir_build_addr_ieq(&b->nb,
+ vtn_ssa_value(b, w[3])->def,
+ vtn_ssa_value(b, w[4])->def,
+ addr_format);
+ if (opcode == SpvOpPtrNotEqual)
+ def = nir_inot(&b->nb, def);
+ break;
+ }
+
+ default:
+ unreachable("Invalid ptr operation");
+ }
+
+ struct vtn_ssa_value *ssa_value = vtn_create_ssa_value(b, type);
+ ssa_value->def = def;
+ vtn_push_ssa(b, w[2], vtn_type, ssa_value);
+}
+
static bool
vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned 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_value *res_val = vtn_untyped_value(b, w[2]);
- struct vtn_value *sel_val = vtn_untyped_value(b, w[3]);
- struct vtn_value *obj1_val = vtn_untyped_value(b, w[4]);
- struct vtn_value *obj2_val = vtn_untyped_value(b, w[5]);
-
- const struct glsl_type *sel_type;
- switch (res_val->type->base_type) {
- case vtn_base_type_scalar:
- sel_type = glsl_bool_type();
- break;
- case vtn_base_type_vector:
- sel_type = glsl_vector_type(GLSL_TYPE_BOOL, res_val->type->length);
- break;
- case vtn_base_type_pointer:
- /* We need to have actual storage for pointer types */
- vtn_fail_if(res_val->type->type == NULL,
- "Invalid pointer result type for OpSelect");
- sel_type = glsl_bool_type();
- break;
- default:
- vtn_fail("Result type of OpSelect must be a scalar, vector, or pointer");
- }
-
- if (unlikely(sel_val->type->type != sel_type)) {
- if (sel_val->type->type == glsl_bool_type()) {
- /* This case is illegal but some older versions of GLSLang produce
- * it. The GLSLang issue was fixed on March 30, 2017:
- *
- * https://github.com/KhronosGroup/glslang/issues/809
- *
- * Unfortunately, there are applications in the wild which are
- * shipping with this bug so it isn't nice to fail on them so we
- * throw a warning instead. It's not actually a problem for us as
- * nir_builder will just splat the condition out which is most
- * likely what the client wanted anyway.
- */
- vtn_warn("Condition type of OpSelect must have the same number "
- "of components as Result Type");
- } else {
- vtn_fail("Condition type of OpSelect must be a scalar or vector "
- "of Boolean type. It must have the same number of "
- "components as Result Type");
- }
- }
-
- vtn_fail_if(obj1_val->type != res_val->type ||
- obj2_val->type != res_val->type,
- "Object types must match the result type in OpSelect");
-
- 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);
+ case SpvOpSelect:
+ vtn_handle_select(b, opcode, w, count);
break;
- }
case SpvOpSNegate:
case SpvOpFNegate:
case SpvOpCompositeConstruct:
case SpvOpCompositeExtract:
case SpvOpCompositeInsert:
+ case SpvOpCopyLogical:
case SpvOpCopyObject:
vtn_handle_composite(b, opcode, w, count);
break;
case SpvOpGroupNonUniformLogicalXor:
case SpvOpGroupNonUniformQuadBroadcast:
case SpvOpGroupNonUniformQuadSwap:
+ case SpvOpGroupAll:
+ case SpvOpGroupAny:
+ case SpvOpGroupBroadcast:
+ case SpvOpGroupIAdd:
+ case SpvOpGroupFAdd:
+ case SpvOpGroupFMin:
+ case SpvOpGroupUMin:
+ case SpvOpGroupSMin:
+ case SpvOpGroupFMax:
+ case SpvOpGroupUMax:
+ case SpvOpGroupSMax:
+ case SpvOpSubgroupBallotKHR:
+ case SpvOpSubgroupFirstInvocationKHR:
+ case SpvOpSubgroupReadInvocationKHR:
+ case SpvOpSubgroupAllKHR:
+ case SpvOpSubgroupAnyKHR:
+ case SpvOpSubgroupAllEqualKHR:
+ case SpvOpGroupIAddNonUniformAMD:
+ case SpvOpGroupFAddNonUniformAMD:
+ case SpvOpGroupFMinNonUniformAMD:
+ case SpvOpGroupUMinNonUniformAMD:
+ case SpvOpGroupSMinNonUniformAMD:
+ case SpvOpGroupFMaxNonUniformAMD:
+ case SpvOpGroupUMaxNonUniformAMD:
+ case SpvOpGroupSMaxNonUniformAMD:
vtn_handle_subgroup(b, opcode, w, count);
break;
+ case SpvOpPtrDiff:
+ case SpvOpPtrEqual:
+ case SpvOpPtrNotEqual:
+ vtn_handle_ptr(b, opcode, w, count);
+ break;
+
+ case SpvOpBeginInvocationInterlockEXT:
+ vtn_emit_barrier(b, nir_intrinsic_begin_invocation_interlock);
+ break;
+
+ case SpvOpEndInvocationInterlockEXT:
+ vtn_emit_barrier(b, nir_intrinsic_end_invocation_interlock);
+ break;
+
+ case SpvOpDemoteToHelperInvocationEXT: {
+ nir_intrinsic_instr *intrin =
+ nir_intrinsic_instr_create(b->shader, nir_intrinsic_demote);
+ nir_builder_instr_insert(&b->nb, &intrin->instr);
+ break;
+ }
+
+ case SpvOpIsHelperInvocationEXT: {
+ nir_intrinsic_instr *intrin =
+ nir_intrinsic_instr_create(b->shader, nir_intrinsic_is_helper_invocation);
+ nir_ssa_dest_init(&intrin->instr, &intrin->dest, 1, 1, NULL);
+ nir_builder_instr_insert(&b->nb, &intrin->instr);
+
+ struct vtn_type *res_type =
+ vtn_value(b, w[1], vtn_value_type_type)->type;
+ struct vtn_ssa_value *val = vtn_create_ssa_value(b, res_type->type);
+ val->def = &intrin->dest.ssa;
+
+ vtn_push_ssa(b, w[2], res_type, val);
+ break;
+ }
+
default:
vtn_fail_with_opcode("Unhandled opcode", opcode);
}
return main_entry_point;
}
-nir_function *
+nir_shader *
spirv_to_nir(const uint32_t *words, size_t word_count,
struct nir_spirv_specialization *spec, unsigned num_spec,
gl_shader_stage stage, const char *entry_point_name,
/* Set shader info defaults */
b->shader->info.gs.invocations = 1;
+ /* Parse rounding mode execution modes. This has to happen earlier than
+ * other changes in the execution modes since they can affect, for example,
+ * the result of the floating point constants.
+ */
+ vtn_foreach_execution_mode(b, b->entry_point,
+ vtn_handle_rounding_mode_in_execution_mode, NULL);
+
b->specializations = spec;
b->num_specializations = num_spec;
glsl_vector_type(GLSL_TYPE_UINT, 3));
nir_const_value *const_size =
- b->workgroup_size_builtin->constant->values[0];
+ b->workgroup_size_builtin->constant->values;
b->shader->info.cs.local_size[0] = const_size[0].u32;
b->shader->info.cs.local_size[1] = const_size[1].u32;
/* Unparent the shader from the vtn_builder before we delete the builder */
ralloc_steal(NULL, b->shader);
+ nir_shader *shader = b->shader;
ralloc_free(b);
- return entry_point;
+ return shader;
}