From dbc2b39e89483d17a08439c8eb2b7d415ece362b Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Sat, 22 Jul 2023 09:56:45 +1000 Subject: [PATCH] Updated vkd3d to 3bafd036bb53bf211cb8b05651835aba6fb47ebc. --- libs/vkd3d/include/private/vkd3d_common.h | 5 + libs/vkd3d/libs/vkd3d-shader/dxil.c | 1640 +++++++++++++++-- libs/vkd3d/libs/vkd3d-shader/hlsl.c | 102 +- libs/vkd3d/libs/vkd3d-shader/hlsl.h | 13 +- libs/vkd3d/libs/vkd3d-shader/hlsl.y | 241 ++- libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c | 195 +- libs/vkd3d/libs/vkd3d-shader/tpf.c | 335 ++-- .../libs/vkd3d-shader/vkd3d_shader_private.h | 9 + 8 files changed, 2120 insertions(+), 420 deletions(-) diff --git a/libs/vkd3d/include/private/vkd3d_common.h b/libs/vkd3d/include/private/vkd3d_common.h index da15ee23fd3..0263fc47297 100644 --- a/libs/vkd3d/include/private/vkd3d_common.h +++ b/libs/vkd3d/include/private/vkd3d_common.h @@ -173,6 +173,11 @@ static inline bool vkd3d_bound_range(size_t start, size_t count, size_t limit) #endif } +static inline bool vkd3d_object_range_overflow(size_t start, size_t count, size_t size) +{ + return (~(size_t)0 - start) / size < count; +} + static inline uint16_t vkd3d_make_u16(uint8_t low, uint8_t high) { return low | ((uint16_t)high << 8); diff --git a/libs/vkd3d/libs/vkd3d-shader/dxil.c b/libs/vkd3d/libs/vkd3d-shader/dxil.c index 67dcd26a0e0..53a4c2da4ba 100644 --- a/libs/vkd3d/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d/libs/vkd3d-shader/dxil.c @@ -62,6 +62,159 @@ enum bitcode_abbrev_type ABBREV_BLOB = 5, }; +enum bitcode_address_space +{ + ADDRESS_SPACE_DEFAULT, + ADDRESS_SPACE_DEVICEMEM, + ADDRESS_SPACE_CBUFFER, + ADDRESS_SPACE_GROUPSHARED, +}; + +enum bitcode_module_code +{ + MODULE_CODE_VERSION = 1, + MODULE_CODE_GLOBALVAR = 7, + MODULE_CODE_FUNCTION = 8, +}; + +enum bitcode_constant_code +{ + CST_CODE_SETTYPE = 1, + CST_CODE_NULL = 2, + CST_CODE_UNDEF = 3, + CST_CODE_INTEGER = 4, + CST_CODE_FLOAT = 6, + CST_CODE_STRING = 8, + CST_CODE_CE_GEP = 12, + CST_CODE_CE_INBOUNDS_GEP = 20, + CST_CODE_DATA = 22, +}; + +enum bitcode_function_code +{ + FUNC_CODE_DECLAREBLOCKS = 1, + FUNC_CODE_INST_BINOP = 2, + FUNC_CODE_INST_CAST = 3, + FUNC_CODE_INST_RET = 10, + FUNC_CODE_INST_BR = 11, + FUNC_CODE_INST_SWITCH = 12, + FUNC_CODE_INST_PHI = 16, + FUNC_CODE_INST_ALLOCA = 19, + FUNC_CODE_INST_LOAD = 20, + FUNC_CODE_INST_EXTRACTVAL = 26, + FUNC_CODE_INST_CMP2 = 28, + FUNC_CODE_INST_VSELECT = 29, + FUNC_CODE_INST_CALL = 34, + FUNC_CODE_INST_ATOMICRMW = 38, + FUNC_CODE_INST_LOADATOMIC = 41, + FUNC_CODE_INST_GEP = 43, + FUNC_CODE_INST_STORE = 44, + FUNC_CODE_INST_STOREATOMIC = 45, + FUNC_CODE_INST_CMPXCHG = 46, +}; + +enum bitcode_type_code +{ + TYPE_CODE_NUMENTRY = 1, + TYPE_CODE_VOID = 2, + TYPE_CODE_FLOAT = 3, + TYPE_CODE_DOUBLE = 4, + TYPE_CODE_LABEL = 5, + TYPE_CODE_INTEGER = 7, + TYPE_CODE_POINTER = 8, + TYPE_CODE_HALF = 10, + TYPE_CODE_ARRAY = 11, + TYPE_CODE_VECTOR = 12, + TYPE_CODE_METADATA = 16, + TYPE_CODE_STRUCT_ANON = 18, + TYPE_CODE_STRUCT_NAME = 19, + TYPE_CODE_STRUCT_NAMED = 20, + TYPE_CODE_FUNCTION = 21, +}; + +enum bitcode_value_symtab_code +{ + VST_CODE_ENTRY = 1, + VST_CODE_BBENTRY = 2, +}; + +struct sm6_pointer_info +{ + const struct sm6_type *type; + enum bitcode_address_space addr_space; +}; + +struct sm6_struct_info +{ + const char *name; + unsigned int elem_count; + const struct sm6_type *elem_types[]; +}; + +struct sm6_function_info +{ + const struct sm6_type *ret_type; + unsigned int param_count; + const struct sm6_type *param_types[]; +}; + +struct sm6_array_info +{ + unsigned int count; + const struct sm6_type *elem_type; +}; + +enum sm6_type_class +{ + TYPE_CLASS_VOID, + TYPE_CLASS_INTEGER, + TYPE_CLASS_FLOAT, + TYPE_CLASS_POINTER, + TYPE_CLASS_STRUCT, + TYPE_CLASS_FUNCTION, + TYPE_CLASS_VECTOR, + TYPE_CLASS_ARRAY, + TYPE_CLASS_LABEL, + TYPE_CLASS_METADATA, +}; + +struct sm6_type +{ + enum sm6_type_class class; + union + { + unsigned int width; + struct sm6_pointer_info pointer; + struct sm6_struct_info *struc; + struct sm6_function_info *function; + struct sm6_array_info array; + } u; +}; + +enum sm6_value_type +{ + VALUE_TYPE_FUNCTION, + VALUE_TYPE_REG, +}; + +struct sm6_function_data +{ + const char *name; + bool is_prototype; + unsigned int attribs_id; +}; + +struct sm6_value +{ + const struct sm6_type *type; + enum sm6_value_type value_type; + union + { + struct sm6_function_data function; + struct vkd3d_shader_register reg; + } u; +}; + struct dxil_record { unsigned int code; @@ -69,6 +222,27 @@ struct dxil_record uint64_t operands[]; }; +struct sm6_symbol +{ + unsigned int id; + const char *name; +}; + +struct sm6_block +{ + struct vkd3d_shader_instruction *instructions; + size_t instruction_capacity; + size_t instruction_count; +}; + +struct sm6_function +{ + const struct sm6_value *declaration; + + struct sm6_block *blocks[1]; + size_t block_count; +}; + struct dxil_block { const struct dxil_block *parent; @@ -106,6 +280,19 @@ struct sm6_parser size_t abbrev_capacity; size_t abbrev_count; + struct sm6_type *types; + size_t type_count; + + struct sm6_symbol *global_symbols; + size_t global_symbol_count; + + struct sm6_function *functions; + size_t function_count; + + struct sm6_value *values; + size_t value_count; + size_t value_capacity; + struct vkd3d_shader_parser p; }; @@ -128,6 +315,12 @@ struct dxil_global_abbrev struct dxil_abbrev abbrev; }; +static size_t size_add_with_overflow_check(size_t a, size_t b) +{ + size_t i = a + b; + return (i < a) ? SIZE_MAX : i; +} + static struct sm6_parser *sm6_parser(struct vkd3d_shader_parser *parser) { return CONTAINING_RECORD(parser, struct sm6_parser, p); @@ -628,10 +821,10 @@ static enum vkd3d_result dxil_block_read(struct dxil_block *parent, struct sm6_p return VKD3D_ERROR_INVALID_SHADER; } -static unsigned int sm6_parser_compute_global_abbrev_count_for_block_id(struct sm6_parser *sm6, +static size_t sm6_parser_compute_global_abbrev_count_for_block_id(struct sm6_parser *sm6, unsigned int block_id) { - unsigned int i, count; + size_t i, count; for (i = 0, count = 0; i < sm6->abbrev_count; ++i) count += sm6->abbrevs[i]->block_id == block_id; @@ -641,7 +834,7 @@ static unsigned int sm6_parser_compute_global_abbrev_count_for_block_id(struct s static void dxil_block_destroy(struct dxil_block *block) { - unsigned int i; + size_t i; for (i = 0; i < block->record_count; ++i) vkd3d_free(block->records[i]); @@ -663,7 +856,7 @@ static void dxil_block_destroy(struct dxil_block *block) static enum vkd3d_result dxil_block_init(struct dxil_block *block, const struct dxil_block *parent, struct sm6_parser *sm6) { - unsigned int i, abbrev_count = 0; + size_t i, abbrev_count = 0; enum vkd3d_result ret; block->parent = parent; @@ -705,159 +898,1360 @@ static enum vkd3d_result dxil_block_init(struct dxil_block *block, const struct return ret; } -static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, unsigned int count) +static size_t dxil_block_compute_function_count(const struct dxil_block *root) { - unsigned int i; + size_t i, count; + + for (i = 0, count = 0; i < root->child_block_count; ++i) + count += root->child_blocks[i]->id == FUNCTION_BLOCK; + + return count; +} + +static size_t dxil_block_compute_module_decl_count(const struct dxil_block *block) +{ + size_t i, count; + + for (i = 0, count = 0; i < block->record_count; ++i) + count += block->records[i]->code == MODULE_CODE_FUNCTION; + return count; +} + +static size_t dxil_block_compute_constants_count(const struct dxil_block *block) +{ + size_t i, count; + + for (i = 0, count = 0; i < block->record_count; ++i) + count += block->records[i]->code != CST_CODE_SETTYPE; + return count; +} + +static void dxil_global_abbrevs_cleanup(struct dxil_global_abbrev **abbrevs, size_t count) +{ + size_t i; for (i = 0; i < count; ++i) vkd3d_free(abbrevs[i]); vkd3d_free(abbrevs); } -static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) +static const struct dxil_block *sm6_parser_get_level_one_block(const struct sm6_parser *sm6, + enum bitcode_block_id id, bool *is_unique) { - struct sm6_parser *sm6 = sm6_parser(parser); + const struct dxil_block *block, *found = NULL; + size_t i; - dxil_block_destroy(&sm6->root_block); - dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); - shader_instruction_array_destroy(&parser->instructions); - free_shader_desc(&parser->shader_desc); - vkd3d_free(sm6); + for (i = 0, *is_unique = true; i < sm6->root_block.child_block_count; ++i) + { + block = sm6->root_block.child_blocks[i]; + if (block->id != id) + continue; + + if (!found) + found = block; + else + *is_unique = false; + } + + return found; } -static const struct vkd3d_shader_parser_ops sm6_parser_ops = +static char *dxil_record_to_string(const struct dxil_record *record, unsigned int offset) { - .parser_destroy = sm6_parser_destroy, -}; + unsigned int i; + char *str; -static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t *byte_code, size_t byte_code_size, - const char *source_name, struct vkd3d_shader_message_context *message_context) + assert(offset <= record->operand_count); + if (!(str = vkd3d_calloc(record->operand_count - offset + 1, 1))) + return NULL; + + for (i = offset; i < record->operand_count; ++i) + str[i - offset] = record->operands[i]; + + return str; +} + +static bool dxil_record_validate_operand_min_count(const struct dxil_record *record, unsigned int min_count, + struct sm6_parser *sm6) { - const struct vkd3d_shader_location location = {.source_name = source_name}; - uint32_t version_token, dxil_version, token_count, magic; - unsigned int count, length, chunk_offset, chunk_size; - enum bitcode_block_abbreviation abbr; - struct vkd3d_shader_version version; - struct dxil_block *block; - enum vkd3d_result ret; + if (record->operand_count >= min_count) + return true; - count = byte_code_size / sizeof(*byte_code); - if (count < 6) - { - WARN("Invalid data size %zu.\n", byte_code_size); - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_SIZE, - "DXIL chunk size %zu is smaller than the DXIL header size.", byte_code_size); - return VKD3D_ERROR_INVALID_SHADER; - } + WARN("Invalid operand count %u for code %u.\n", record->operand_count, record->code); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT, + "Invalid operand count %u for record code %u.", record->operand_count, record->code); + return false; +} - version_token = byte_code[0]; - TRACE("Compiler version: 0x%08x.\n", version_token); - token_count = byte_code[1]; - TRACE("Token count: %u.\n", token_count); +static void dxil_record_validate_operand_max_count(const struct dxil_record *record, unsigned int max_count, + struct sm6_parser *sm6) +{ + if (record->operand_count <= max_count) + return; - if (token_count < 6 || count < token_count) + WARN("Ignoring %u extra operands for code %u.\n", record->operand_count - max_count, record->code); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS, + "Ignoring %u extra operands for record code %u.", record->operand_count - max_count, record->code); +} + +static bool dxil_record_validate_operand_count(const struct dxil_record *record, unsigned int min_count, + unsigned int max_count, struct sm6_parser *sm6) +{ + dxil_record_validate_operand_max_count(record, max_count, sm6); + return dxil_record_validate_operand_min_count(record, min_count, sm6); +} + +static enum vkd3d_result sm6_parser_type_table_init(struct sm6_parser *sm6) +{ + const struct dxil_record *record; + size_t i, type_count, type_index; + const struct dxil_block *block; + char *struct_name = NULL; + unsigned int j, count; + struct sm6_type *type; + uint64_t type_id; + bool is_unique; + + sm6->p.location.line = 0; + sm6->p.location.column = 0; + + if (!(block = sm6_parser_get_level_one_block(sm6, TYPE_BLOCK, &is_unique))) { - WARN("Invalid token count %u (word count %u).\n", token_count, count); - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, - "DXIL chunk token count %#x is invalid (word count %u).", token_count, count); - return VKD3D_ERROR_INVALID_SHADER; + WARN("No type definitions found.\n"); + return VKD3D_OK; } + if (!is_unique) + WARN("Ignoring invalid extra type table(s).\n"); - if (byte_code[2] != TAG_DXIL) - WARN("Unknown magic number 0x%08x.\n", byte_code[2]); + sm6->p.location.line = block->id; - dxil_version = byte_code[3]; - if (dxil_version > 0x102) - WARN("Unknown DXIL version: 0x%08x.\n", dxil_version); - else - TRACE("DXIL version: 0x%08x.\n", dxil_version); + type_count = 0; + for (i = 0; i < block->record_count; ++i) + type_count += block->records[i]->code != TYPE_CODE_NUMENTRY && block->records[i]->code != TYPE_CODE_STRUCT_NAME; - chunk_offset = byte_code[4]; - if (chunk_offset < 16 || chunk_offset >= byte_code_size) - { - WARN("Invalid bitcode chunk offset %#x (data size %zu).\n", chunk_offset, byte_code_size); - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_OFFSET, - "DXIL bitcode chunk has invalid offset %#x (data size %#zx).", chunk_offset, byte_code_size); - return VKD3D_ERROR_INVALID_SHADER; - } - chunk_size = byte_code[5]; - if (chunk_size > byte_code_size - chunk_offset) + /* The type array must not be relocated. */ + if (!(sm6->types = vkd3d_calloc(type_count, sizeof(*sm6->types)))) { - WARN("Invalid bitcode chunk size %#x (data size %zu, chunk offset %#x).\n", - chunk_size, byte_code_size, chunk_offset); - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, - "DXIL bitcode chunk has invalid size %#x (data size %#zx, chunk offset %#x).", - chunk_size, byte_code_size, chunk_offset); - return VKD3D_ERROR_INVALID_SHADER; + ERR("Failed to allocate type array.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; } - sm6->start = (const uint32_t *)((const char*)&byte_code[2] + chunk_offset); - if ((magic = sm6->start[0]) != BITCODE_MAGIC) + for (i = 0; i < block->record_count; ++i) { - WARN("Unknown magic number 0x%08x.\n", magic); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER, - "DXIL bitcode chunk magic number 0x%08x is not the expected 0x%08x.", magic, BITCODE_MAGIC); - } + sm6->p.location.column = i; + record = block->records[i]; - sm6->end = &sm6->start[(chunk_size + sizeof(*sm6->start) - 1) / sizeof(*sm6->start)]; + type = &sm6->types[sm6->type_count]; + type_index = sm6->type_count; - if ((version.type = version_token >> 16) >= VKD3D_SHADER_TYPE_COUNT) - { - FIXME("Unknown shader type %#x.\n", version.type); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE, - "Unknown shader type %#x.", version.type); - } + switch (record->code) + { + case TYPE_CODE_ARRAY: + case TYPE_CODE_VECTOR: + if (!dxil_record_validate_operand_count(record, 2, 2, sm6)) + return VKD3D_ERROR_INVALID_SHADER; - version.major = VKD3D_SM6_VERSION_MAJOR(version_token); - version.minor = VKD3D_SM6_VERSION_MINOR(version_token); + type->class = record->code == TYPE_CODE_ARRAY ? TYPE_CLASS_ARRAY : TYPE_CLASS_VECTOR; - if ((abbr = sm6->start[1] & 3) != ENTER_SUBBLOCK) - { - WARN("Initial block abbreviation %u is not ENTER_SUBBLOCK.\n", abbr); - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, - "DXIL bitcode chunk has invalid initial block abbreviation %u.", abbr); - return VKD3D_ERROR_INVALID_SHADER; - } + if (!(type->u.array.count = record->operands[0])) + { + TRACE("Setting unbounded for type %zu.\n", type_index); + type->u.array.count = UINT_MAX; + } - /* Estimate instruction count to avoid reallocation in most shaders. */ - count = max(token_count, 400) - 400; - vkd3d_shader_parser_init(&sm6->p, message_context, source_name, &version, &sm6_parser_ops, - (count + (count >> 2)) / 2u + 10); - sm6->ptr = &sm6->start[1]; - sm6->bitpos = 2; + if ((type_id = record->operands[1]) >= type_count) + { + WARN("Invalid contained type id %"PRIu64" for type %zu.\n", type_id, type_index); + return VKD3D_ERROR_INVALID_SHADER; + } + type->u.array.elem_type = &sm6->types[type_id]; + break; - block = &sm6->root_block; - if ((ret = dxil_block_init(block, NULL, sm6)) < 0) - { - if (ret == VKD3D_ERROR_OUT_OF_MEMORY) - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, - "Out of memory parsing DXIL bitcode chunk."); - else if (ret == VKD3D_ERROR_INVALID_SHADER) - vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, - "DXIL bitcode chunk has invalid bitcode."); - else - vkd3d_unreachable(); - return ret; - } + case TYPE_CODE_DOUBLE: + dxil_record_validate_operand_max_count(record, 0, sm6); + type->class = TYPE_CLASS_FLOAT; + type->u.width = 64; + break; - dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); - sm6->abbrevs = NULL; - sm6->abbrev_count = 0; + case TYPE_CODE_FLOAT: + dxil_record_validate_operand_max_count(record, 0, sm6); + type->class = TYPE_CLASS_FLOAT; + type->u.width = 32; + break; - length = sm6->ptr - sm6->start - block->start; - if (length != block->length) - { - WARN("Invalid block length %u; expected %u.\n", length, block->length); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH, - "Root block ends with length %u but indicated length is %u.", length, block->length); - } - if (sm6->ptr != sm6->end) - { - unsigned int expected_length = sm6->end - sm6->start; - length = sm6->ptr - sm6->start; - WARN("Invalid module length %u; expected %u.\n", length, expected_length); - vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH, - "Module ends with length %u but indicated length is %u.", length, expected_length); + case TYPE_CODE_FUNCTION: + if (!dxil_record_validate_operand_min_count(record, 2, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + if (record->operands[0]) + FIXME("Unhandled vararg function type %zu.\n", type_index); + + type->class = TYPE_CLASS_FUNCTION; + + if ((type_id = record->operands[1]) >= type_count) + { + WARN("Invalid return type id %"PRIu64" for type %zu.\n", type_id, type_index); + return VKD3D_ERROR_INVALID_SHADER; + } + + count = record->operand_count - 2; + if (vkd3d_object_range_overflow(sizeof(type->u.function), count, sizeof(type->u.function->param_types[0])) + || !(type->u.function = vkd3d_malloc(offsetof(struct sm6_function_info, param_types[count])))) + { + ERR("Failed to allocate function parameter types.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + type->u.function->ret_type = &sm6->types[type_id]; + type->u.function->param_count = count; + for (j = 0; j < count; ++j) + { + if ((type_id = record->operands[j + 2]) >= type_count) + { + WARN("Invalid parameter type id %"PRIu64" for type %zu.\n", type_id, type_index); + vkd3d_free(type->u.function); + return VKD3D_ERROR_INVALID_SHADER; + } + type->u.function->param_types[j] = &sm6->types[type_id]; + } + break; + + case TYPE_CODE_HALF: + dxil_record_validate_operand_max_count(record, 0, sm6); + type->class = TYPE_CLASS_FLOAT; + type->u.width = 16; + break; + + case TYPE_CODE_INTEGER: + { + uint64_t width; + + if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + type->class = TYPE_CLASS_INTEGER; + + switch ((width = record->operands[0])) + { + case 1: + case 8: + case 16: + case 32: + case 64: + break; + default: + WARN("Invalid integer width %"PRIu64" for type %zu.\n", width, type_index); + return VKD3D_ERROR_INVALID_SHADER; + } + type->u.width = width; + break; + } + + case TYPE_CODE_LABEL: + type->class = TYPE_CLASS_LABEL; + break; + + case TYPE_CODE_METADATA: + type->class = TYPE_CLASS_METADATA; + break; + + case TYPE_CODE_NUMENTRY: + continue; + + case TYPE_CODE_POINTER: + if (!dxil_record_validate_operand_count(record, 1, 2, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + type->class = TYPE_CLASS_POINTER; + + if ((type_id = record->operands[0]) >= type_count) + { + WARN("Invalid pointee type id %"PRIu64" for type %zu.\n", type_id, type_index); + return VKD3D_ERROR_INVALID_SHADER; + } + type->u.pointer.type = &sm6->types[type_id]; + type->u.pointer.addr_space = (record->operand_count > 1) ? record->operands[1] : ADDRESS_SPACE_DEFAULT; + break; + + case TYPE_CODE_STRUCT_ANON: + case TYPE_CODE_STRUCT_NAMED: + if (!dxil_record_validate_operand_min_count(record, 2, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + if (record->code == TYPE_CODE_STRUCT_NAMED && !struct_name) + { + WARN("Missing struct name before struct type %zu.\n", type_index); + return VKD3D_ERROR_INVALID_SHADER; + } + + type->class = TYPE_CLASS_STRUCT; + + count = record->operand_count - 1; + if (vkd3d_object_range_overflow(sizeof(type->u.struc), count, sizeof(type->u.struc->elem_types[0])) + || !(type->u.struc = vkd3d_malloc(offsetof(struct sm6_struct_info, elem_types[count])))) + { + ERR("Failed to allocate struct element types.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + if (record->operands[0]) + FIXME("Ignoring struct packed attribute.\n"); + + type->u.struc->elem_count = count; + for (j = 0; j < count; ++j) + { + if ((type_id = record->operands[j + 1]) >= type_count) + { + WARN("Invalid contained type id %"PRIu64" for type %zu.\n", type_id, type_index); + vkd3d_free(type->u.struc); + return VKD3D_ERROR_INVALID_SHADER; + } + type->u.struc->elem_types[j] = &sm6->types[type_id]; + } + + if (record->code == TYPE_CODE_STRUCT_ANON) + { + type->u.struc->name = NULL; + break; + } + + type->u.struc->name = struct_name; + struct_name = NULL; + break; + + case TYPE_CODE_STRUCT_NAME: + if (!(struct_name = dxil_record_to_string(record, 0))) + { + ERR("Failed to allocate struct name.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + if (!struct_name[0]) + WARN("Struct name is empty for type %zu.\n", type_index); + continue; + + case TYPE_CODE_VOID: + dxil_record_validate_operand_max_count(record, 0, sm6); + type->class = TYPE_CLASS_VOID; + break; + + default: + FIXME("Unhandled type %u at index %zu.\n", record->code, type_index); + return VKD3D_ERROR_INVALID_SHADER; + } + ++sm6->type_count; + } + + assert(sm6->type_count == type_count); + + if (struct_name) + { + WARN("Unused struct name %s.\n", struct_name); + vkd3d_free(struct_name); + } + + return VKD3D_OK; +} + +static inline bool sm6_type_is_void(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_VOID; +} + +static inline bool sm6_type_is_integer(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_INTEGER; +} + +static inline bool sm6_type_is_floating_point(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_FLOAT; +} + +static inline bool sm6_type_is_numeric(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_INTEGER || type->class == TYPE_CLASS_FLOAT; +} + +static inline bool sm6_type_is_pointer(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_POINTER; +} + +static bool sm6_type_is_numeric_aggregate(const struct sm6_type *type) +{ + unsigned int i; + + switch (type->class) + { + case TYPE_CLASS_ARRAY: + case TYPE_CLASS_VECTOR: + return sm6_type_is_numeric(type->u.array.elem_type); + + case TYPE_CLASS_STRUCT: + /* Do not handle nested structs. Support can be added if they show up. */ + for (i = 0; i < type->u.struc->elem_count; ++i) + if (!sm6_type_is_numeric(type->u.struc->elem_types[i])) + return false; + return true; + + default: + return false; + } +} + +static inline bool sm6_type_is_struct(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_STRUCT; +} + +static inline bool sm6_type_is_function(const struct sm6_type *type) +{ + return type->class == TYPE_CLASS_FUNCTION; +} + +static inline bool sm6_type_is_function_pointer(const struct sm6_type *type) +{ + return sm6_type_is_pointer(type) && sm6_type_is_function(type->u.pointer.type); +} + +static inline bool sm6_type_is_handle(const struct sm6_type *type) +{ + return sm6_type_is_struct(type) && !strcmp(type->u.struc->name, "dx.types.Handle"); +} + +static inline const struct sm6_type *sm6_type_get_element_type(const struct sm6_type *type) +{ + return (type->class == TYPE_CLASS_ARRAY || type->class == TYPE_CLASS_VECTOR) ? type->u.array.elem_type : type; +} + +static const struct sm6_type *sm6_type_get_pointer_to_type(const struct sm6_type *type, + enum bitcode_address_space addr_space, struct sm6_parser *sm6) +{ + size_t i, start = type - sm6->types; + const struct sm6_type *pointer_type; + + /* DXC seems usually to place the pointer type immediately after its pointee. */ + for (i = (start + 1) % sm6->type_count; i != start; i = (i + 1) % sm6->type_count) + { + pointer_type = &sm6->types[i]; + if (sm6_type_is_pointer(pointer_type) && pointer_type->u.pointer.type == type + && pointer_type->u.pointer.addr_space == addr_space) + return pointer_type; + } + + return NULL; +} + +static const struct sm6_type *sm6_parser_get_type(struct sm6_parser *sm6, uint64_t type_id) +{ + if (type_id >= sm6->type_count) + { + WARN("Invalid type index %"PRIu64" at %zu.\n", type_id, sm6->value_count); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID, + "DXIL type id %"PRIu64" is invalid.", type_id); + return NULL; + } + return &sm6->types[type_id]; +} + +static int global_symbol_compare(const void *a, const void *b) +{ + return vkd3d_u32_compare(((const struct sm6_symbol *)a)->id, ((const struct sm6_symbol *)b)->id); +} + +static enum vkd3d_result sm6_parser_symtab_init(struct sm6_parser *sm6) +{ + const struct dxil_record *record; + const struct dxil_block *block; + struct sm6_symbol *symbol; + size_t i, count; + bool is_unique; + + sm6->p.location.line = 0; + sm6->p.location.column = 0; + + if (!(block = sm6_parser_get_level_one_block(sm6, VALUE_SYMTAB_BLOCK, &is_unique))) + { + /* There should always be at least one symbol: the name of the entry point function. */ + WARN("No value symtab block found.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + if (!is_unique) + FIXME("Ignoring extra value symtab block(s).\n"); + + sm6->p.location.line = block->id; + + for (i = 0, count = 0; i < block->record_count; ++i) + count += block->records[i]->code == VST_CODE_ENTRY; + + if (!(sm6->global_symbols = vkd3d_calloc(count, sizeof(*sm6->global_symbols)))) + { + ERR("Failed to allocate global symbols.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < block->record_count; ++i) + { + sm6->p.location.column = i; + record = block->records[i]; + + if (record->code != VST_CODE_ENTRY) + { + FIXME("Unhandled symtab code %u.\n", record->code); + continue; + } + if (!dxil_record_validate_operand_min_count(record, 1, sm6)) + continue; + + symbol = &sm6->global_symbols[sm6->global_symbol_count]; + symbol->id = record->operands[0]; + if (!(symbol->name = dxil_record_to_string(record, 1))) + { + ERR("Failed to allocate symbol name.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + ++sm6->global_symbol_count; + } + + sm6->p.location.column = block->record_count; + + qsort(sm6->global_symbols, sm6->global_symbol_count, sizeof(*sm6->global_symbols), global_symbol_compare); + for (i = 1; i < sm6->global_symbol_count; ++i) + { + if (sm6->global_symbols[i].id == sm6->global_symbols[i - 1].id) + { + WARN("Invalid duplicate symbol id %u.\n", sm6->global_symbols[i].id); + return VKD3D_ERROR_INVALID_SHADER; + } + } + + return VKD3D_OK; +} + +static const char *sm6_parser_get_global_symbol_name(const struct sm6_parser *sm6, size_t id) +{ + size_t i, start; + + /* id == array index is normally true */ + i = start = id % sm6->global_symbol_count; + do + { + if (sm6->global_symbols[i].id == id) + return sm6->global_symbols[i].name; + i = (i + 1) % sm6->global_symbol_count; + } while (i != start); + + return NULL; +} + +static inline bool sm6_value_is_dx_intrinsic_dcl(const struct sm6_value *fn) +{ + assert(fn->value_type == VALUE_TYPE_FUNCTION); + return fn->u.function.is_prototype && !strncmp(fn->u.function.name, "dx.op.", 6); +} + +static inline struct sm6_value *sm6_parser_get_current_value(const struct sm6_parser *sm6) +{ + assert(sm6->value_count < sm6->value_capacity); + return &sm6->values[sm6->value_count]; +} + +static enum vkd3d_data_type vkd3d_data_type_from_sm6_type(const struct sm6_type *type) +{ + if (type->class == TYPE_CLASS_INTEGER) + { + switch (type->u.width) + { + case 8: + return VKD3D_DATA_UINT8; + case 32: + return VKD3D_DATA_UINT; + default: + FIXME("Unhandled width %u.\n", type->u.width); + return VKD3D_DATA_UINT; + } + } + else if (type->class == TYPE_CLASS_FLOAT) + { + switch (type->u.width) + { + case 32: + return VKD3D_DATA_FLOAT; + case 64: + return VKD3D_DATA_DOUBLE; + default: + FIXME("Unhandled width %u.\n", type->u.width); + return VKD3D_DATA_FLOAT; + } + } + + FIXME("Unhandled type %u.\n", type->class); + return VKD3D_DATA_UINT; +} + +/* Recurse through the block tree while maintaining a current value count. The current + * count is the sum of the global count plus all declarations within the current function. + * Store into value_capacity the highest count seen. */ +static size_t sm6_parser_compute_max_value_count(struct sm6_parser *sm6, + const struct dxil_block *block, size_t value_count) +{ + size_t i, old_value_count = value_count; + + if (block->id == MODULE_BLOCK) + value_count = size_add_with_overflow_check(value_count, dxil_block_compute_module_decl_count(block)); + + for (i = 0; i < block->child_block_count; ++i) + value_count = sm6_parser_compute_max_value_count(sm6, block->child_blocks[i], value_count); + + switch (block->id) + { + case CONSTANTS_BLOCK: + /* Function local constants are contained in a child block of the function block. */ + value_count = size_add_with_overflow_check(value_count, dxil_block_compute_constants_count(block)); + break; + case FUNCTION_BLOCK: + /* A function must start with a block count, which emits no value. This formula is likely to + * overestimate the value count somewhat, but this should be no problem. */ + value_count = size_add_with_overflow_check(value_count, max(block->record_count, 1u) - 1); + sm6->value_capacity = max(sm6->value_capacity, value_count); + /* The value count returns to its previous value after handling a function. */ + if (value_count < SIZE_MAX) + value_count = old_value_count; + break; + default: + break; + } + + return value_count; +} + +static bool sm6_parser_declare_function(struct sm6_parser *sm6, const struct dxil_record *record) +{ + const unsigned int max_count = 15; + const struct sm6_type *ret_type; + struct sm6_value *fn; + unsigned int i, j; + + if (!dxil_record_validate_operand_count(record, 8, max_count, sm6)) + return false; + + fn = sm6_parser_get_current_value(sm6); + fn->value_type = VALUE_TYPE_FUNCTION; + if (!(fn->u.function.name = sm6_parser_get_global_symbol_name(sm6, sm6->value_count))) + { + WARN("Missing symbol name for function %zu.\n", sm6->value_count); + fn->u.function.name = ""; + } + + if (!(fn->type = sm6_parser_get_type(sm6, record->operands[0]))) + return false; + if (!sm6_type_is_function(fn->type)) + { + WARN("Type is not a function.\n"); + return false; + } + ret_type = fn->type->u.function->ret_type; + + if (!(fn->type = sm6_type_get_pointer_to_type(fn->type, ADDRESS_SPACE_DEFAULT, sm6))) + { + WARN("Failed to get pointer type for type %u.\n", fn->type->class); + return false; + } + + if (record->operands[1]) + WARN("Ignoring calling convention %#"PRIx64".\n", record->operands[1]); + + fn->u.function.is_prototype = !!record->operands[2]; + + if (record->operands[3]) + WARN("Ignoring linkage %#"PRIx64".\n", record->operands[3]); + + if (record->operands[4] > UINT_MAX) + WARN("Invalid attributes id %#"PRIx64".\n", record->operands[4]); + /* 1-based index. */ + if ((fn->u.function.attribs_id = record->operands[4])) + TRACE("Ignoring function attributes.\n"); + + /* These always seem to be zero. */ + for (i = 5, j = 0; i < min(record->operand_count, max_count); ++i) + j += !!record->operands[i]; + if (j) + WARN("Ignoring %u operands.\n", j); + + if (sm6_value_is_dx_intrinsic_dcl(fn) && !sm6_type_is_void(ret_type) && !sm6_type_is_numeric(ret_type) + && !sm6_type_is_numeric_aggregate(ret_type) && !sm6_type_is_handle(ret_type)) + { + WARN("Unexpected return type for dx intrinsic function '%s'.\n", fn->u.function.name); + } + + ++sm6->value_count; + + return true; +} + +static inline uint64_t decode_rotated_signed_value(uint64_t value) +{ + if (value != 1) + { + bool neg = value & 1; + value >>= 1; + return neg ? -value : value; + } + return value << 63; +} + +static inline float bitcast_uint64_to_float(uint64_t value) +{ + union + { + uint32_t uint32_value; + float float_value; + } u; + + u.uint32_value = value; + return u.float_value; +} + +static inline double bitcast_uint64_to_double(uint64_t value) +{ + union + { + uint64_t uint64_value; + double double_value; + } u; + + u.uint64_value = value; + return u.double_value; +} + +static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) +{ + enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; + const struct sm6_type *type, *elem_type; + enum vkd3d_data_type reg_data_type; + const struct dxil_record *record; + struct sm6_value *dst; + size_t i, value_idx; + uint64_t value; + + for (i = 0, type = NULL; i < block->record_count; ++i) + { + sm6->p.location.column = i; + record = block->records[i]; + value_idx = sm6->value_count; + + if (record->code == CST_CODE_SETTYPE) + { + if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + if (!(type = sm6_parser_get_type(sm6, record->operands[0]))) + return VKD3D_ERROR_INVALID_SHADER; + + elem_type = sm6_type_get_element_type(type); + if (sm6_type_is_numeric(elem_type)) + { + reg_data_type = vkd3d_data_type_from_sm6_type(elem_type); + reg_type = elem_type->u.width > 32 ? VKD3DSPR_IMMCONST64 : VKD3DSPR_IMMCONST; + } + else + { + reg_data_type = VKD3D_DATA_UNUSED; + reg_type = VKD3DSPR_INVALID; + } + + if (i == block->record_count - 1) + WARN("Unused SETTYPE record.\n"); + + continue; + } + + if (!type) + { + WARN("Constant record %zu has no type.\n", value_idx); + return VKD3D_ERROR_INVALID_SHADER; + } + + dst = sm6_parser_get_current_value(sm6); + dst->type = type; + dst->value_type = VALUE_TYPE_REG; + dst->u.reg.type = reg_type; + dst->u.reg.immconst_type = VKD3D_IMMCONST_SCALAR; + dst->u.reg.data_type = reg_data_type; + + switch (record->code) + { + case CST_CODE_NULL: + /* Register constant data is already zero-filled. */ + break; + + case CST_CODE_INTEGER: + if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + if (!sm6_type_is_integer(type)) + { + WARN("Invalid integer of non-integer type %u at constant idx %zu.\n", type->class, value_idx); + return VKD3D_ERROR_INVALID_SHADER; + } + + value = decode_rotated_signed_value(record->operands[0]); + if (type->u.width <= 32) + dst->u.reg.u.immconst_uint[0] = value & ((1ull << type->u.width) - 1); + else + dst->u.reg.u.immconst_uint64[0] = value; + + break; + + case CST_CODE_FLOAT: + if (!dxil_record_validate_operand_count(record, 1, 1, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + + if (!sm6_type_is_floating_point(type)) + { + WARN("Invalid float of non-fp type %u at constant idx %zu.\n", type->class, value_idx); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (type->u.width == 16) + FIXME("Half float type is not supported yet.\n"); + else if (type->u.width == 32) + dst->u.reg.u.immconst_float[0] = bitcast_uint64_to_float(record->operands[0]); + else if (type->u.width == 64) + dst->u.reg.u.immconst_double[0] = bitcast_uint64_to_double(record->operands[0]); + else + vkd3d_unreachable(); + + break; + + case CST_CODE_DATA: + WARN("Unhandled constant array.\n"); + break; + + default: + FIXME("Unhandled constant code %u.\n", record->code); + break; + } + + ++sm6->value_count; + } + + return VKD3D_OK; +} + +static enum vkd3d_result sm6_parser_globals_init(struct sm6_parser *sm6) +{ + const struct dxil_block *block = &sm6->root_block; + const struct dxil_record *record; + uint64_t version; + size_t i; + + sm6->p.location.line = block->id; + sm6->p.location.column = 0; + + for (i = 0; i < block->record_count; ++i) + { + sm6->p.location.column = i; + record = block->records[i]; + switch (record->code) + { + case MODULE_CODE_FUNCTION: + if (!sm6_parser_declare_function(sm6, record)) + { + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL, + "A DXIL function declaration is invalid."); + return VKD3D_ERROR_INVALID_SHADER; + } + break; + + case MODULE_CODE_GLOBALVAR: + FIXME("Global variables are not implemented yet.\n"); + break; + + case MODULE_CODE_VERSION: + dxil_record_validate_operand_count(record, 1, 1, sm6); + if ((version = record->operands[0]) != 1) + { + FIXME("Unsupported format version %#"PRIx64".\n", version); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED_BITCODE_FORMAT, + "Bitcode format version %#"PRIx64" is unsupported.", version); + return VKD3D_ERROR_INVALID_SHADER; + } + break; + + default: + break; + } + } + + return VKD3D_OK; +} + +static const struct sm6_value *sm6_parser_next_function_definition(struct sm6_parser *sm6) +{ + size_t i, count = sm6->function_count; + + for (i = 0; i < sm6->value_count; ++i) + { + if (sm6_type_is_function_pointer(sm6->values[i].type) && !sm6->values[i].u.function.is_prototype && !count--) + break; + } + if (i == sm6->value_count) + return NULL; + + ++sm6->function_count; + return &sm6->values[i]; +} + +static struct sm6_block *sm6_block_create() +{ + struct sm6_block *block = vkd3d_calloc(1, sizeof(*block)); + return block; +} + +static void sm6_parser_emit_ret(struct sm6_parser *sm6, const struct dxil_record *record, + struct sm6_block *code_block, struct vkd3d_shader_instruction *ins) +{ + if (!dxil_record_validate_operand_count(record, 0, 1, sm6)) + return; + + if (record->operand_count) + FIXME("Non-void return is not implemented.\n"); + + ins->handler_idx = VKD3DSIH_NOP; +} + +static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const struct dxil_block *block, + struct sm6_function *function) +{ + struct vkd3d_shader_instruction *ins; + const struct dxil_record *record; + struct sm6_block *code_block; + struct sm6_value *dst; + size_t i, block_idx; + bool ret_found; + enum + { + RESULT_VALUE, + RESULT_TERMINATE, + } result_type; + + if (sm6->function_count) + { + FIXME("Multiple functions are not supported yet.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + if (!(function->declaration = sm6_parser_next_function_definition(sm6))) + { + WARN("Failed to find definition to match function body.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (block->record_count < 2) + { + /* It should contain at least a block count and a RET instruction. */ + WARN("Invalid function block record count %zu.\n", block->record_count); + return VKD3D_ERROR_INVALID_SHADER; + } + if (block->records[0]->code != FUNC_CODE_DECLAREBLOCKS || !block->records[0]->operand_count + || block->records[0]->operands[0] > UINT_MAX) + { + WARN("Block count declaration not found or invalid.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!(function->block_count = block->records[0]->operands[0])) + { + WARN("Function contains no blocks.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + if (function->block_count > 1) + { + FIXME("Branched shaders are not supported yet.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!(function->blocks[0] = sm6_block_create())) + { + ERR("Failed to allocate code block.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + code_block = function->blocks[0]; + + for (i = 1, block_idx = 0, ret_found = false; i < block->record_count; ++i) + { + sm6->p.location.column = i; + + /* block->record_count - 1 is the instruction count, but some instructions + * can emit >1 IR instruction, so extra may be used. */ + if (!vkd3d_array_reserve((void **)&code_block->instructions, &code_block->instruction_capacity, + max(code_block->instruction_count + 1, block->record_count), sizeof(*code_block->instructions))) + { + ERR("Failed to allocate instructions.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + ins = &code_block->instructions[code_block->instruction_count]; + ins->handler_idx = VKD3DSIH_INVALID; + + dst = sm6_parser_get_current_value(sm6); + dst->type = NULL; + dst->value_type = VALUE_TYPE_REG; + result_type = RESULT_VALUE; + + record = block->records[i]; + switch (record->code) + { + case FUNC_CODE_INST_RET: + sm6_parser_emit_ret(sm6, record, code_block, ins); + result_type = RESULT_TERMINATE; + ret_found = true; + break; + default: + FIXME("Unhandled dxil instruction %u.\n", record->code); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (result_type == RESULT_TERMINATE) + { + ++block_idx; + code_block = (block_idx < function->block_count) ? function->blocks[block_idx] : NULL; + } + if (code_block) + code_block->instruction_count += ins->handler_idx != VKD3DSIH_NOP; + else + assert(ins->handler_idx == VKD3DSIH_NOP); + sm6->value_count += !!dst->type; + } + + if (!ret_found) + { + WARN("Function contains no RET instruction.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + return VKD3D_OK; +} + +static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const struct dxil_block *block, + unsigned int level) +{ + size_t i, old_value_count = sm6->value_count; + struct sm6_function *function; + enum vkd3d_result ret; + + for (i = 0; i < block->child_block_count; ++i) + { + if ((ret = sm6_parser_module_init(sm6, block->child_blocks[i], level + 1)) < 0) + return ret; + } + + sm6->p.location.line = block->id; + sm6->p.location.column = 0; + + switch (block->id) + { + case CONSTANTS_BLOCK: + return sm6_parser_constants_init(sm6, block); + + case FUNCTION_BLOCK: + function = &sm6->functions[sm6->function_count]; + if ((ret = sm6_parser_function_init(sm6, block, function)) < 0) + return ret; + /* The value index returns to its previous value after handling a function. It's usually nonzero + * at the start because of global constants/variables/function declarations. Function constants + * occur in a child block, so value_count is already saved before they are emitted. */ + memset(&sm6->values[old_value_count], 0, (sm6->value_count - old_value_count) * sizeof(*sm6->values)); + sm6->value_count = old_value_count; + break; + + case BLOCKINFO_BLOCK: + case MODULE_BLOCK: + case PARAMATTR_BLOCK: + case PARAMATTR_GROUP_BLOCK: + case VALUE_SYMTAB_BLOCK: + case METADATA_BLOCK: + case METADATA_ATTACHMENT_BLOCK: + case TYPE_BLOCK: + break; + + default: + FIXME("Unhandled block id %u.\n", block->id); + break; + } + + return VKD3D_OK; +} + +static void sm6_type_table_cleanup(struct sm6_type *types, size_t count) +{ + size_t i; + + if (!types) + return; + + for (i = 0; i < count; ++i) + { + switch (types[i].class) + { + case TYPE_CLASS_STRUCT: + vkd3d_free((void *)types[i].u.struc->name); + vkd3d_free(types[i].u.struc); + break; + case TYPE_CLASS_FUNCTION: + vkd3d_free(types[i].u.function); + break; + default: + break; + } + } + + vkd3d_free(types); +} + +static void sm6_symtab_cleanup(struct sm6_symbol *symbols, size_t count) +{ + size_t i; + + for (i = 0; i < count; ++i) + vkd3d_free((void *)symbols[i].name); + vkd3d_free(symbols); +} + +static void sm6_block_destroy(struct sm6_block *block) +{ + vkd3d_free(block->instructions); + vkd3d_free(block); +} + +static void sm6_functions_cleanup(struct sm6_function *functions, size_t count) +{ + size_t i, j; + + for (i = 0; i < count; ++i) + { + for (j = 0; j < functions[i].block_count; ++j) + sm6_block_destroy(functions[i].blocks[j]); + } + vkd3d_free(functions); +} + +static void sm6_parser_destroy(struct vkd3d_shader_parser *parser) +{ + struct sm6_parser *sm6 = sm6_parser(parser); + + dxil_block_destroy(&sm6->root_block); + dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); + shader_instruction_array_destroy(&parser->instructions); + sm6_type_table_cleanup(sm6->types, sm6->type_count); + sm6_symtab_cleanup(sm6->global_symbols, sm6->global_symbol_count); + sm6_functions_cleanup(sm6->functions, sm6->function_count); + vkd3d_free(sm6->values); + free_shader_desc(&parser->shader_desc); + vkd3d_free(sm6); +} + +static const struct vkd3d_shader_parser_ops sm6_parser_ops = +{ + .parser_destroy = sm6_parser_destroy, +}; + +static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t *byte_code, size_t byte_code_size, + const char *source_name, struct vkd3d_shader_message_context *message_context) +{ + const struct vkd3d_shader_location location = {.source_name = source_name}; + uint32_t version_token, dxil_version, token_count, magic; + unsigned int chunk_offset, chunk_size; + size_t count, length, function_count; + enum bitcode_block_abbreviation abbr; + struct vkd3d_shader_version version; + struct dxil_block *block; + enum vkd3d_result ret; + + count = byte_code_size / sizeof(*byte_code); + if (count < 6) + { + WARN("Invalid data size %zu.\n", byte_code_size); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_SIZE, + "DXIL chunk size %zu is smaller than the DXIL header size.", byte_code_size); + return VKD3D_ERROR_INVALID_SHADER; + } + + version_token = byte_code[0]; + TRACE("Compiler version: 0x%08x.\n", version_token); + token_count = byte_code[1]; + TRACE("Token count: %u.\n", token_count); + + if (token_count < 6 || count < token_count) + { + WARN("Invalid token count %u (word count %zu).\n", token_count, count); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, + "DXIL chunk token count %#x is invalid (word count %zu).", token_count, count); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (byte_code[2] != TAG_DXIL) + WARN("Unknown magic number 0x%08x.\n", byte_code[2]); + + dxil_version = byte_code[3]; + if (dxil_version > 0x102) + WARN("Unknown DXIL version: 0x%08x.\n", dxil_version); + else + TRACE("DXIL version: 0x%08x.\n", dxil_version); + + chunk_offset = byte_code[4]; + if (chunk_offset < 16 || chunk_offset >= byte_code_size) + { + WARN("Invalid bitcode chunk offset %#x (data size %zu).\n", chunk_offset, byte_code_size); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_OFFSET, + "DXIL bitcode chunk has invalid offset %#x (data size %#zx).", chunk_offset, byte_code_size); + return VKD3D_ERROR_INVALID_SHADER; + } + chunk_size = byte_code[5]; + if (chunk_size > byte_code_size - chunk_offset) + { + WARN("Invalid bitcode chunk size %#x (data size %zu, chunk offset %#x).\n", + chunk_size, byte_code_size, chunk_offset); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE, + "DXIL bitcode chunk has invalid size %#x (data size %#zx, chunk offset %#x).", + chunk_size, byte_code_size, chunk_offset); + return VKD3D_ERROR_INVALID_SHADER; + } + + sm6->start = (const uint32_t *)((const char*)&byte_code[2] + chunk_offset); + if ((magic = sm6->start[0]) != BITCODE_MAGIC) + { + WARN("Unknown magic number 0x%08x.\n", magic); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER, + "DXIL bitcode chunk magic number 0x%08x is not the expected 0x%08x.", magic, BITCODE_MAGIC); + } + + sm6->end = &sm6->start[(chunk_size + sizeof(*sm6->start) - 1) / sizeof(*sm6->start)]; + + if ((version.type = version_token >> 16) >= VKD3D_SHADER_TYPE_COUNT) + { + FIXME("Unknown shader type %#x.\n", version.type); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE, + "Unknown shader type %#x.", version.type); + } + + version.major = VKD3D_SM6_VERSION_MAJOR(version_token); + version.minor = VKD3D_SM6_VERSION_MINOR(version_token); + + if ((abbr = sm6->start[1] & 3) != ENTER_SUBBLOCK) + { + WARN("Initial block abbreviation %u is not ENTER_SUBBLOCK.\n", abbr); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, + "DXIL bitcode chunk has invalid initial block abbreviation %u.", abbr); + return VKD3D_ERROR_INVALID_SHADER; + } + + /* Estimate instruction count to avoid reallocation in most shaders. */ + count = max(token_count, 400) - 400; + vkd3d_shader_parser_init(&sm6->p, message_context, source_name, &version, &sm6_parser_ops, + (count + (count >> 2)) / 2u + 10); + sm6->ptr = &sm6->start[1]; + sm6->bitpos = 2; + + block = &sm6->root_block; + if ((ret = dxil_block_init(block, NULL, sm6)) < 0) + { + if (ret == VKD3D_ERROR_OUT_OF_MEMORY) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory parsing DXIL bitcode chunk."); + else if (ret == VKD3D_ERROR_INVALID_SHADER) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE, + "DXIL bitcode chunk has invalid bitcode."); + else + vkd3d_unreachable(); + return ret; + } + + dxil_global_abbrevs_cleanup(sm6->abbrevs, sm6->abbrev_count); + sm6->abbrevs = NULL; + sm6->abbrev_count = 0; + + length = sm6->ptr - sm6->start - block->start; + if (length != block->length) + { + WARN("Invalid block length %zu; expected %u.\n", length, block->length); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH, + "Root block ends with length %zu but indicated length is %u.", length, block->length); + } + if (sm6->ptr != sm6->end) + { + size_t expected_length = sm6->end - sm6->start; + length = sm6->ptr - sm6->start; + WARN("Invalid module length %zu; expected %zu.\n", length, expected_length); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH, + "Module ends with length %zu but indicated length is %zu.", length, expected_length); + } + + if ((ret = sm6_parser_type_table_init(sm6)) < 0) + { + if (ret == VKD3D_ERROR_OUT_OF_MEMORY) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory parsing DXIL type table."); + else if (ret == VKD3D_ERROR_INVALID_SHADER) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE, + "DXIL type table is invalid."); + else + vkd3d_unreachable(); + return ret; + } + + if ((ret = sm6_parser_symtab_init(sm6)) < 0) + { + if (ret == VKD3D_ERROR_OUT_OF_MEMORY) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory parsing DXIL value symbol table."); + else if (ret == VKD3D_ERROR_INVALID_SHADER) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB, + "DXIL value symbol table is invalid."); + else + vkd3d_unreachable(); + return ret; + } + + function_count = dxil_block_compute_function_count(&sm6->root_block); + if (!(sm6->functions = vkd3d_calloc(function_count, sizeof(*sm6->functions)))) + { + ERR("Failed to allocate function array.\n"); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating DXIL function array."); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + if (sm6_parser_compute_max_value_count(sm6, &sm6->root_block, 0) == SIZE_MAX) + { + WARN("Value array count overflowed.\n"); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "Overflow occurred in the DXIL module value count."); + return VKD3D_ERROR_INVALID_SHADER; + } + if (!(sm6->values = vkd3d_calloc(sm6->value_capacity, sizeof(*sm6->values)))) + { + ERR("Failed to allocate value array.\n"); + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory allocating DXIL value array."); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + if ((ret = sm6_parser_globals_init(sm6)) < 0) + { + WARN("Failed to load global declarations.\n"); + return ret; + } + + if ((ret = sm6_parser_module_init(sm6, &sm6->root_block, 0)) < 0) + { + if (ret == VKD3D_ERROR_OUT_OF_MEMORY) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, + "Out of memory parsing DXIL module."); + else if (ret == VKD3D_ERROR_INVALID_SHADER) + vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "DXIL module is invalid."); + else + vkd3d_unreachable(); + return ret; } dxil_block_destroy(&sm6->root_block); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.c b/libs/vkd3d/libs/vkd3d-shader/hlsl.c index 4e9af15c1be..ab508502623 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.c @@ -430,6 +430,51 @@ struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl return type; } +unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, + enum hlsl_regset regset, unsigned int index) +{ + struct hlsl_type *next_type; + unsigned int offset = 0; + unsigned int idx; + + while (!type_is_single_component(type)) + { + next_type = type; + idx = traverse_path_from_component_index(ctx, &next_type, &index); + + switch (type->class) + { + case HLSL_CLASS_SCALAR: + case HLSL_CLASS_VECTOR: + case HLSL_CLASS_MATRIX: + if (regset == HLSL_REGSET_NUMERIC) + offset += idx; + break; + + case HLSL_CLASS_STRUCT: + offset += type->e.record.fields[idx].reg_offset[regset]; + break; + + case HLSL_CLASS_ARRAY: + if (regset == HLSL_REGSET_NUMERIC) + offset += idx * align(type->e.array.type->reg_size[regset], 4); + else + offset += idx * type->e.array.type->reg_size[regset]; + break; + + case HLSL_CLASS_OBJECT: + assert(idx == 0); + break; + + default: + vkd3d_unreachable(); + } + type = next_type; + } + + return offset; +} + static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_var *var, unsigned int path_len) { @@ -524,7 +569,9 @@ struct hlsl_type *hlsl_deref_get_type(struct hlsl_ctx *ctx, const struct hlsl_de unsigned int i; assert(deref); - assert(!deref->offset.node); + + if (deref->offset.node) + return deref->data_type; type = deref->var->data_type; for (i = 0; i < deref->path_len; ++i) @@ -626,6 +673,7 @@ struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *ba type->e.array.type = basic_type; type->dimx = basic_type->dimx; type->dimy = basic_type->dimy; + type->sampler_dim = basic_type->sampler_dim; hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); @@ -992,20 +1040,31 @@ struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *tem struct vkd3d_string_buffer *string; struct hlsl_ir_var *var; static LONG counter; - const char *name; if (!(string = hlsl_get_string_buffer(ctx))) return NULL; vkd3d_string_buffer_printf(string, "<%s-%u>", template, InterlockedIncrement(&counter)); - if (!(name = hlsl_strdup(ctx, string->buffer))) - { - hlsl_release_string_buffer(ctx, string); - return NULL; - } - var = hlsl_new_var(ctx, name, type, loc, NULL, 0, NULL); + var = hlsl_new_synthetic_var_named(ctx, string->buffer, type, loc, true); hlsl_release_string_buffer(ctx, string); + return var; +} + +struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const char *name, + struct hlsl_type *type, const struct vkd3d_shader_location *loc, bool dummy_scope) +{ + struct hlsl_ir_var *var; + const char *name_copy; + + if (!(name_copy = hlsl_strdup(ctx, name))) + return NULL; + var = hlsl_new_var(ctx, name_copy, type, loc, NULL, 0, NULL); if (var) - list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); + { + if (dummy_scope) + list_add_tail(&ctx->dummy_scope->vars, &var->scope_entry); + else + list_add_tail(&ctx->globals->vars, &var->scope_entry); + } return var; } @@ -2066,6 +2125,31 @@ struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const stru } } +struct vkd3d_string_buffer *hlsl_component_to_string(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var, + unsigned int index) +{ + struct hlsl_type *type = var->data_type, *current_type; + struct vkd3d_string_buffer *buffer; + unsigned int element_index; + + if (!(buffer = hlsl_get_string_buffer(ctx))) + return NULL; + + vkd3d_string_buffer_printf(buffer, "%s", var->name); + + while (!type_is_single_component(type)) + { + current_type = type; + element_index = traverse_path_from_component_index(ctx, &type, &index); + if (current_type->class == HLSL_CLASS_STRUCT) + vkd3d_string_buffer_printf(buffer, ".%s", current_type->e.record.fields[element_index].name); + else + vkd3d_string_buffer_printf(buffer, "[%u]", element_index); + } + + return buffer; +} + const char *debug_hlsl_type(struct hlsl_ctx *ctx, const struct hlsl_type *type) { struct vkd3d_string_buffer *string; diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.h b/libs/vkd3d/libs/vkd3d-shader/hlsl.h index 17ac36a57c6..1a4b995abbf 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.h @@ -422,6 +422,7 @@ struct hlsl_ir_var uint32_t is_output_semantic : 1; uint32_t is_uniform : 1; uint32_t is_param : 1; + uint32_t is_separated_resource : 1; }; /* Sized array of variables representing a function's parameters. */ @@ -607,9 +608,11 @@ struct hlsl_deref * components, within the pertaining regset), from the start of the variable, of the part * referenced. * The path is lowered to this single offset -- whose value may vary between SM1 and SM4 -- - * before writing the bytecode. */ + * before writing the bytecode. + * Since the type information cannot longer be retrieved from the offset alone, the type is + * stored in the data_type field. */ struct hlsl_src offset; - enum hlsl_regset offset_regset; + struct hlsl_type *data_type; }; struct hlsl_ir_load @@ -1066,6 +1069,8 @@ const char *debug_hlsl_writemask(unsigned int writemask); const char *debug_hlsl_swizzle(unsigned int swizzle, unsigned int count); struct vkd3d_string_buffer *hlsl_type_to_string(struct hlsl_ctx *ctx, const struct hlsl_type *type); +struct vkd3d_string_buffer *hlsl_component_to_string(struct hlsl_ctx *ctx, const struct hlsl_ir_var *var, + unsigned int index); struct vkd3d_string_buffer *hlsl_modifiers_to_string(struct hlsl_ctx *ctx, unsigned int modifiers); const char *hlsl_node_type_to_string(enum hlsl_ir_node_type type); @@ -1169,6 +1174,8 @@ struct hlsl_ir_node *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned in struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc); struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *template, struct hlsl_type *type, const struct vkd3d_shader_location *loc); +struct hlsl_ir_var *hlsl_new_synthetic_var_named(struct hlsl_ctx *ctx, const char *name, + struct hlsl_type *type, const struct vkd3d_shader_location *loc, bool dummy_scope); struct hlsl_type *hlsl_new_texture_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format, unsigned int sample_count); struct hlsl_type *hlsl_new_uav_type(struct hlsl_ctx *ctx, enum hlsl_sampler_dim dim, struct hlsl_type *format); @@ -1200,6 +1207,8 @@ unsigned int hlsl_type_component_count(const struct hlsl_type *type); unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type, enum hlsl_regset regset); struct hlsl_type *hlsl_type_get_component_type(struct hlsl_ctx *ctx, struct hlsl_type *type, unsigned int index); +unsigned int hlsl_type_get_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, + enum hlsl_regset regset, unsigned int index); bool hlsl_type_is_row_major(const struct hlsl_type *type); unsigned int hlsl_type_minor_size(const struct hlsl_type *type); unsigned int hlsl_type_major_size(const struct hlsl_type *type); diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl.y b/libs/vkd3d/libs/vkd3d-shader/hlsl.y index 42fa2129e40..6bf87f8f916 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl.y @@ -133,11 +133,6 @@ static void yyerror(YYLTYPE *loc, void *scanner, struct hlsl_ctx *ctx, const cha hlsl_error(ctx, loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "%s", s); } -static struct hlsl_ir_node *node_from_list(struct list *list) -{ - return LIST_ENTRY(list_tail(list), struct hlsl_ir_node, entry); -} - static struct hlsl_ir_node *node_from_block(struct hlsl_block *block) { return LIST_ENTRY(list_tail(&block->instrs), struct hlsl_ir_node, entry); @@ -719,7 +714,7 @@ struct hlsl_ir_node *hlsl_add_load_component(struct hlsl_ctx *ctx, struct list * return load; } -static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *record, +static bool add_record_access(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_node *record, unsigned int idx, const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *index, *c; @@ -728,11 +723,11 @@ static bool add_record_access(struct hlsl_ctx *ctx, struct list *instrs, struct if (!(c = hlsl_new_uint_constant(ctx, idx, loc))) return false; - list_add_tail(instrs, &c->entry); + hlsl_block_add_instr(block, c); if (!(index = hlsl_new_index(ctx, record, c, loc))) return false; - list_add_tail(instrs, &index->entry); + hlsl_block_add_instr(block, index); return true; } @@ -1170,7 +1165,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str return 0; hlsl_block_add_block(&expr, block); - if (!add_implicit_conversion(ctx, &expr.instrs, node_from_list(&expr.instrs), + if (!add_implicit_conversion(ctx, &expr.instrs, node_from_block(&expr), hlsl_get_scalar_type(ctx, HLSL_TYPE_UINT), loc)) { hlsl_block_cleanup(&expr); @@ -1183,7 +1178,7 @@ static unsigned int evaluate_static_expression_as_uint(struct hlsl_ctx *ctx, str progress |= hlsl_copy_propagation_execute(ctx, &expr); } while (progress); - node = node_from_list(&expr.instrs); + node = node_from_block(&expr); if (node->type == HLSL_IR_CONSTANT) { constant = hlsl_ir_constant(node); @@ -1417,15 +1412,15 @@ static struct hlsl_ir_node *add_unary_arithmetic_expr(struct hlsl_ctx *ctx, stru return add_expr(ctx, block_to_list(block), op, args, arg->data_type, loc); } -static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, +static struct hlsl_ir_node *add_unary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) { check_integer_type(ctx, arg); - return add_unary_arithmetic_expr(ctx, list_to_block(instrs), op, arg, loc); + return add_unary_arithmetic_expr(ctx, block, op, arg, loc); } -static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, +static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg, const struct vkd3d_shader_location *loc) { struct hlsl_ir_node *args[HLSL_MAX_OPERANDS] = {0}; @@ -1434,10 +1429,10 @@ static struct hlsl_ir_node *add_unary_logical_expr(struct hlsl_ctx *ctx, struct bool_type = hlsl_get_numeric_type(ctx, arg->data_type->class, HLSL_TYPE_BOOL, arg->data_type->dimx, arg->data_type->dimy); - if (!(args[0] = add_implicit_conversion(ctx, instrs, arg, bool_type, loc))) + if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg, bool_type, loc))) return NULL; - return add_expr(ctx, instrs, op, args, bool_type, loc); + return add_expr(ctx, block_to_list(block), op, args, bool_type, loc); } static struct hlsl_type *get_common_numeric_type(struct hlsl_ctx *ctx, const struct hlsl_ir_node *arg1, @@ -1471,17 +1466,17 @@ static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, str return add_expr(ctx, block_to_list(block), op, args, common_type, loc); } -static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct list *instrs, +static struct hlsl_ir_node *add_binary_bitwise_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { check_integer_type(ctx, arg1); check_integer_type(ctx, arg2); - return add_binary_arithmetic_expr(ctx, list_to_block(instrs), op, arg1, arg2, loc); + return add_binary_arithmetic_expr(ctx, block, op, arg1, arg2, loc); } -static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct list *instrs, +static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { @@ -1497,16 +1492,16 @@ static struct hlsl_ir_node *add_binary_comparison_expr(struct hlsl_ctx *ctx, str common_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); return_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); - if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) + if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) return NULL; - if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) + if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) return NULL; - return add_expr(ctx, instrs, op, args, return_type, loc); + return add_expr(ctx, block_to_list(block), op, args, return_type, loc); } -static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct list *instrs, +static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { @@ -1520,16 +1515,16 @@ static struct hlsl_ir_node *add_binary_logical_expr(struct hlsl_ctx *ctx, struct common_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_BOOL, dimx, dimy); - if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, common_type, loc))) + if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, common_type, loc))) return NULL; - if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, common_type, loc))) + if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, common_type, loc))) return NULL; - return add_expr(ctx, instrs, op, args, common_type, loc); + return add_expr(ctx, block_to_list(block), op, args, common_type, loc); } -static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct list *instrs, +static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct hlsl_block *block, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2, const struct vkd3d_shader_location *loc) { @@ -1551,13 +1546,13 @@ static struct hlsl_ir_node *add_binary_shift_expr(struct hlsl_ctx *ctx, struct l return_type = hlsl_get_numeric_type(ctx, type, base, dimx, dimy); integer_type = hlsl_get_numeric_type(ctx, type, HLSL_TYPE_INT, dimx, dimy); - if (!(args[0] = add_implicit_conversion(ctx, instrs, arg1, return_type, loc))) + if (!(args[0] = add_implicit_conversion(ctx, block_to_list(block), arg1, return_type, loc))) return NULL; - if (!(args[1] = add_implicit_conversion(ctx, instrs, arg2, integer_type, loc))) + if (!(args[1] = add_implicit_conversion(ctx, block_to_list(block), arg2, integer_type, loc))) return NULL; - return add_expr(ctx, instrs, op, args, return_type, loc); + return add_expr(ctx, block_to_list(block), op, args, return_type, loc); } static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct hlsl_block *instrs, @@ -1613,13 +1608,13 @@ static struct hlsl_ir_node *add_binary_dot_expr(struct hlsl_ctx *ctx, struct hls return add_expr(ctx, block_to_list(instrs), op, args, ret_type, loc); } -static struct list *add_binary_expr_merge(struct hlsl_ctx *ctx, struct list *list1, struct list *list2, - enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) +static struct hlsl_block *add_binary_expr_merge(struct hlsl_ctx *ctx, struct hlsl_block *block1, + struct hlsl_block *block2, enum hlsl_ir_expr_op op, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *arg1 = node_from_list(list1), *arg2 = node_from_list(list2); + struct hlsl_ir_node *arg1 = node_from_block(block1), *arg2 = node_from_block(block2); - list_move_tail(list1, list2); - vkd3d_free(list2); + hlsl_block_add_block(block1, block2); + destroy_block(block2); switch (op) { @@ -1627,37 +1622,37 @@ static struct list *add_binary_expr_merge(struct hlsl_ctx *ctx, struct list *lis case HLSL_OP2_DIV: case HLSL_OP2_MOD: case HLSL_OP2_MUL: - add_binary_arithmetic_expr(ctx, list_to_block(list1), op, arg1, arg2, loc); + add_binary_arithmetic_expr(ctx, block1, op, arg1, arg2, loc); break; case HLSL_OP2_BIT_AND: case HLSL_OP2_BIT_OR: case HLSL_OP2_BIT_XOR: - add_binary_bitwise_expr(ctx, list1, op, arg1, arg2, loc); + add_binary_bitwise_expr(ctx, block1, op, arg1, arg2, loc); break; case HLSL_OP2_LESS: case HLSL_OP2_GEQUAL: case HLSL_OP2_EQUAL: case HLSL_OP2_NEQUAL: - add_binary_comparison_expr(ctx, list1, op, arg1, arg2, loc); + add_binary_comparison_expr(ctx, block1, op, arg1, arg2, loc); break; case HLSL_OP2_LOGIC_AND: case HLSL_OP2_LOGIC_OR: - add_binary_logical_expr(ctx, list1, op, arg1, arg2, loc); + add_binary_logical_expr(ctx, block1, op, arg1, arg2, loc); break; case HLSL_OP2_LSHIFT: case HLSL_OP2_RSHIFT: - add_binary_shift_expr(ctx, list1, op, arg1, arg2, loc); + add_binary_shift_expr(ctx, block1, op, arg1, arg2, loc); break; default: vkd3d_unreachable(); } - return list1; + return block1; } static enum hlsl_ir_expr_op op_from_assignment(enum parse_assign_op op) @@ -1882,10 +1877,10 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in return copy; } -static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrement, bool post, +static bool add_increment(struct hlsl_ctx *ctx, struct hlsl_block *block, bool decrement, bool post, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *lhs = node_from_list(instrs); + struct hlsl_ir_node *lhs = node_from_block(block); struct hlsl_ir_node *one; if (lhs->data_type->modifiers & HLSL_MODIFIER_CONST) @@ -1894,9 +1889,9 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem if (!(one = hlsl_new_int_constant(ctx, 1, loc))) return false; - list_add_tail(instrs, &one->entry); + hlsl_block_add_instr(block, one); - if (!add_assignment(ctx, instrs, lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) + if (!add_assignment(ctx, block_to_list(block), lhs, decrement ? ASSIGN_OP_SUB : ASSIGN_OP_ADD, one)) return false; if (post) @@ -1905,7 +1900,7 @@ static bool add_increment(struct hlsl_ctx *ctx, struct list *instrs, bool decrem if (!(copy = hlsl_new_copy(ctx, lhs))) return false; - list_add_tail(instrs, ©->entry); + hlsl_block_add_instr(block, copy); /* Post increment/decrement expressions are considered const. */ if (!(copy->data_type = hlsl_type_clone(ctx, copy->data_type, 0, HLSL_MODIFIER_CONST))) @@ -2495,7 +2490,7 @@ static bool intrinsic_all(struct hlsl_ctx *ctx, return false; } - return !!add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_NEQUAL, mul, zero, loc); + return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, mul, zero, loc); } static bool intrinsic_any(struct hlsl_ctx *ctx, @@ -2519,7 +2514,7 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, if (!(dot = add_binary_dot_expr(ctx, params->instrs, arg, arg, loc))) return false; - return !!add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_NEQUAL, dot, zero, loc); + return !!add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_NEQUAL, dot, zero, loc); } else if (arg->data_type->base_type == HLSL_TYPE_BOOL) { @@ -2535,7 +2530,7 @@ static bool intrinsic_any(struct hlsl_ctx *ctx, if (!(load = hlsl_add_load_component(ctx, block_to_list(params->instrs), arg, i, loc))) return false; - if (!(or = add_binary_bitwise_expr(ctx, block_to_list(params->instrs), HLSL_OP2_BIT_OR, or, load, loc))) + if (!(or = add_binary_bitwise_expr(ctx, params->instrs, HLSL_OP2_BIT_OR, or, load, loc))) return false; } @@ -2881,7 +2876,7 @@ static bool intrinsic_fmod(struct hlsl_ctx *ctx, const struct parse_initializer if (!(neg_frac = add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_NEG, frac, loc))) return false; - if (!(ge = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_GEQUAL, div, zero, loc))) + if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, div, zero, loc))) return false; if (!(select = hlsl_add_conditional(ctx, block_to_list(params->instrs), ge, frac, neg_frac))) @@ -3035,13 +3030,13 @@ static bool intrinsic_lit(struct hlsl_ctx *ctx, hlsl_block_add_block(params->instrs, &block); /* Specular component. */ - if (!(n_h_neg = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, n_h, zero, loc))) + if (!(n_h_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_h, zero, loc))) return false; - if (!(n_l_neg = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, n_l, zero, loc))) + if (!(n_l_neg = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, n_l, zero, loc))) return false; - if (!(specular_or = add_binary_logical_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) + if (!(specular_or = add_binary_logical_expr(ctx, params->instrs, HLSL_OP2_LOGIC_OR, n_l_neg, n_h_neg, loc))) return false; if (!(specular_pow = add_pow_expr(ctx, params->instrs, n_h, m, loc))) @@ -3330,7 +3325,7 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, /* Check if 0 < arg, cast bool to int */ - if (!(lt = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, zero, arg, loc))) + if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, zero, arg, loc))) return false; if (!(op1 = add_implicit_conversion(ctx, block_to_list(params->instrs), lt, int_type, loc))) @@ -3338,7 +3333,7 @@ static bool intrinsic_sign(struct hlsl_ctx *ctx, /* Check if arg < 0, cast bool to int and invert (meaning true is -1) */ - if (!(lt = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_LESS, arg, zero, loc))) + if (!(lt = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_LESS, arg, zero, loc))) return false; if (!(op2 = add_implicit_conversion(ctx, block_to_list(params->instrs), lt, int_type, loc))) @@ -3440,7 +3435,7 @@ static bool intrinsic_step(struct hlsl_ctx *ctx, if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) return false; - if (!(ge = add_binary_comparison_expr(ctx, block_to_list(params->instrs), HLSL_OP2_GEQUAL, + if (!(ge = add_binary_comparison_expr(ctx, params->instrs, HLSL_OP2_GEQUAL, params->args[1], params->args[0], loc))) return false; @@ -3824,7 +3819,7 @@ fail: return NULL; } -static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, +static struct hlsl_block *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type, struct parse_initializer *params, const struct vkd3d_shader_location *loc) { struct hlsl_ir_load *load; @@ -3857,7 +3852,7 @@ static struct list *add_constructor(struct hlsl_ctx *ctx, struct hlsl_type *type hlsl_block_add_instr(params->instrs, &load->node); vkd3d_free(params->args); - return block_to_list(params->instrs); + return params->instrs; } static unsigned int hlsl_offset_dim_count(enum hlsl_sampler_dim dim) @@ -4562,26 +4557,11 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %token C_INTEGER %token PRE_LINE -%type add_expr -%type assignment_expr -%type bitand_expr -%type bitor_expr -%type bitxor_expr -%type conditional_expr %type declaration %type declaration_statement -%type equality_expr -%type initializer_expr -%type logicand_expr -%type logicor_expr -%type mul_expr -%type postfix_expr %type primary_expr -%type relational_expr -%type shift_expr %type struct_declaration_without_vars %type type_specs -%type unary_expr %type variables_def %type variables_def_typed @@ -4599,15 +4579,30 @@ static void validate_texture_format_type(struct hlsl_ctx *ctx, struct hlsl_type %type attribute_list %type attribute_list_optional +%type add_expr +%type assignment_expr +%type bitand_expr +%type bitor_expr +%type bitxor_expr %type compound_statement +%type conditional_expr +%type equality_expr %type expr %type expr_optional %type expr_statement +%type initializer_expr %type jump_statement +%type logicand_expr +%type logicor_expr %type loop_statement +%type mul_expr +%type postfix_expr +%type relational_expr +%type shift_expr %type selection_statement %type statement %type statement_list +%type unary_expr %type boolean @@ -5433,7 +5428,7 @@ type_no_void: struct hlsl_block block; hlsl_block_init(&block); - list_move_tail(&block.instrs, $5); + hlsl_block_add_block(&block, $5); sample_count = evaluate_static_expression_as_uint(ctx, &block, &@5); @@ -5824,11 +5819,11 @@ complex_initializer: $$.args_count = 1; if (!($$.args = hlsl_alloc(ctx, sizeof(*$$.args)))) { - destroy_instr_list($1); + destroy_block($1); YYABORT; } - $$.args[0] = node_from_list($1); - $$.instrs = list_to_block($1); + $$.args[0] = node_from_block($1); + $$.instrs = $1; $$.braces = false; } | '{' complex_initializer_list '}' @@ -5872,11 +5867,11 @@ initializer_expr_list: $$.args_count = 1; if (!($$.args = hlsl_alloc(ctx, sizeof(*$$.args)))) { - destroy_instr_list($1); + destroy_block($1); YYABORT; } - $$.args[0] = node_from_list($1); - $$.instrs = list_to_block($1); + $$.args[0] = node_from_block($1); + $$.instrs = $1; $$.braces = false; } | initializer_expr_list ',' initializer_expr @@ -5887,13 +5882,13 @@ initializer_expr_list: if (!(new_args = hlsl_realloc(ctx, $$.args, ($$.args_count + 1) * sizeof(*$$.args)))) { free_parse_initializer(&$$); - destroy_instr_list($3); + destroy_block($3); YYABORT; } $$.args = new_args; - $$.args[$$.args_count++] = node_from_list($3); - list_move_tail(&$$.instrs->instrs, $3); - vkd3d_free($3); + $$.args[$$.args_count++] = node_from_block($3); + hlsl_block_add_block($$.instrs, $3); + destroy_block($3); } boolean: @@ -6123,11 +6118,14 @@ primary_expr: postfix_expr: primary_expr + { + $$ = list_to_block($1); + } | postfix_expr OP_INC { if (!add_increment(ctx, $1, false, true, &@2)) { - destroy_instr_list($1); + destroy_block($1); YYABORT; } $$ = $1; @@ -6136,14 +6134,14 @@ postfix_expr: { if (!add_increment(ctx, $1, true, true, &@2)) { - destroy_instr_list($1); + destroy_block($1); YYABORT; } $$ = $1; } | postfix_expr '.' any_identifier { - struct hlsl_ir_node *node = node_from_list($1); + struct hlsl_ir_node *node = node_from_block($1); if (node->data_type->class == HLSL_CLASS_STRUCT) { @@ -6171,7 +6169,7 @@ postfix_expr: hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Invalid swizzle \"%s\".", $3); YYABORT; } - list_add_tail($1, &swizzle->entry); + hlsl_block_add_instr($1, swizzle); $$ = $1; } else @@ -6182,17 +6180,17 @@ postfix_expr: } | postfix_expr '[' expr ']' { - struct hlsl_ir_node *array = node_from_list($1), *index = node_from_block($3); + struct hlsl_ir_node *array = node_from_block($1), *index = node_from_block($3); - list_move_head($1, &$3->instrs); - destroy_block($3); + hlsl_block_add_block($3, $1); + destroy_block($1); - if (!add_array_access(ctx, $1, array, index, &@2)) + if (!add_array_access(ctx, block_to_list($3), array, index, &@2)) { - destroy_instr_list($1); + destroy_block($3); YYABORT; } - $$ = $1; + $$ = $3; } /* var_modifiers is necessary to avoid shift/reduce conflicts. */ @@ -6233,14 +6231,14 @@ postfix_expr: } | postfix_expr '.' any_identifier '(' func_arguments ')' { - struct hlsl_ir_node *object = node_from_list($1); + struct hlsl_ir_node *object = node_from_block($1); - list_move_tail($1, &$5.instrs->instrs); + hlsl_block_add_block($1, $5.instrs); vkd3d_free($5.instrs); - if (!add_method_call(ctx, $1, object, $3, &$5, &@3)) + if (!add_method_call(ctx, block_to_list($1), object, $3, &$5, &@3)) { - hlsl_free_instr_list($1); + destroy_block($1); vkd3d_free($5.args); YYABORT; } @@ -6254,7 +6252,7 @@ unary_expr: { if (!add_increment(ctx, $2, false, false, &@1)) { - destroy_instr_list($2); + destroy_block($2); YYABORT; } $$ = $2; @@ -6263,7 +6261,7 @@ unary_expr: { if (!add_increment(ctx, $2, true, false, &@1)) { - destroy_instr_list($2); + destroy_block($2); YYABORT; } $$ = $2; @@ -6274,23 +6272,23 @@ unary_expr: } | '-' unary_expr { - add_unary_arithmetic_expr(ctx, list_to_block($2), HLSL_OP1_NEG, node_from_list($2), &@1); + add_unary_arithmetic_expr(ctx, $2, HLSL_OP1_NEG, node_from_block($2), &@1); $$ = $2; } | '~' unary_expr { - add_unary_bitwise_expr(ctx, $2, HLSL_OP1_BIT_NOT, node_from_list($2), &@1); + add_unary_bitwise_expr(ctx, $2, HLSL_OP1_BIT_NOT, node_from_block($2), &@1); $$ = $2; } | '!' unary_expr { - add_unary_logical_expr(ctx, $2, HLSL_OP1_LOGIC_NOT, node_from_list($2), &@1); + add_unary_logical_expr(ctx, $2, HLSL_OP1_LOGIC_NOT, node_from_block($2), &@1); $$ = $2; } /* var_modifiers is necessary to avoid shift/reduce conflicts. */ | '(' var_modifiers type arrays ')' unary_expr { - struct hlsl_type *src_type = node_from_list($6)->data_type; + struct hlsl_type *src_type = node_from_block($6)->data_type; struct hlsl_type *dst_type; unsigned int i; @@ -6326,9 +6324,9 @@ unary_expr: YYABORT; } - if (!add_cast(ctx, $6, node_from_list($6), dst_type, &@3)) + if (!add_cast(ctx, block_to_list($6), node_from_block($6), dst_type, &@3)) { - hlsl_free_instr_list($6); + destroy_block($6); YYABORT; } $$ = $6; @@ -6359,7 +6357,7 @@ add_expr: { struct hlsl_ir_node *neg; - if (!(neg = add_unary_arithmetic_expr(ctx, list_to_block($3), HLSL_OP1_NEG, node_from_list($3), &@2))) + if (!(neg = add_unary_arithmetic_expr(ctx, $3, HLSL_OP1_NEG, node_from_block($3), &@2))) YYABORT; $$ = add_binary_expr_merge(ctx, $1, $3, HLSL_OP2_ADD, &@2); } @@ -6444,24 +6442,26 @@ conditional_expr: logicor_expr | logicor_expr '?' expr ':' assignment_expr { - struct hlsl_ir_node *cond = node_from_list($1), *first = node_from_block($3), *second = node_from_list($5); + struct hlsl_ir_node *cond = node_from_block($1); + struct hlsl_ir_node *first = node_from_block($3); + struct hlsl_ir_node *second = node_from_block($5); struct hlsl_type *common_type; - list_move_tail($1, &$3->instrs); - list_move_tail($1, $5); + hlsl_block_add_block($1, $3); + hlsl_block_add_block($1, $5); destroy_block($3); - vkd3d_free($5); + destroy_block($5); if (!(common_type = get_common_numeric_type(ctx, first, second, &@3))) YYABORT; - if (!(first = add_implicit_conversion(ctx, $1, first, common_type, &@3))) + if (!(first = add_implicit_conversion(ctx, block_to_list($1), first, common_type, &@3))) YYABORT; - if (!(second = add_implicit_conversion(ctx, $1, second, common_type, &@5))) + if (!(second = add_implicit_conversion(ctx, block_to_list($1), second, common_type, &@5))) YYABORT; - if (!hlsl_add_conditional(ctx, $1, cond, first, second)) + if (!hlsl_add_conditional(ctx, block_to_list($1), cond, first, second)) YYABORT; $$ = $1; } @@ -6471,16 +6471,16 @@ assignment_expr: conditional_expr | unary_expr assign_op assignment_expr { - struct hlsl_ir_node *lhs = node_from_list($1), *rhs = node_from_list($3); + struct hlsl_ir_node *lhs = node_from_block($1), *rhs = node_from_block($3); if (lhs->data_type->modifiers & HLSL_MODIFIER_CONST) { hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_MODIFIES_CONST, "Statement modifies a const expression."); YYABORT; } - list_move_tail($3, $1); - vkd3d_free($1); - if (!add_assignment(ctx, $3, lhs, $2, rhs)) + hlsl_block_add_block($3, $1); + destroy_block($1); + if (!add_assignment(ctx, block_to_list($3), lhs, $2, rhs)) YYABORT; $$ = $3; } @@ -6533,12 +6533,9 @@ assign_op: expr: assignment_expr - { - $$ = list_to_block($1); - } | expr ',' assignment_expr { $$ = $1; - list_move_tail(&$$->instrs, $3); - vkd3d_free($3); + hlsl_block_add_block($$, $3); + destroy_block($3); } diff --git a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c index 8927e291183..09a3ea4ca08 100644 --- a/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d/libs/vkd3d-shader/hlsl_codegen.c @@ -97,6 +97,7 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, struct hlsl_block *block, const struct hlsl_deref *deref, const struct vkd3d_shader_location *loc) { + enum hlsl_regset regset = hlsl_type_get_regset(deref->data_type); struct hlsl_ir_node *offset = NULL; struct hlsl_type *type; unsigned int i; @@ -111,7 +112,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st struct hlsl_block idx_block; if (!(offset = new_offset_from_path_index(ctx, &idx_block, type, offset, deref->path[i].node, - deref->offset_regset, loc))) + regset, loc))) return NULL; hlsl_block_add_block(block, &idx_block); @@ -126,7 +127,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_node *instr) { - const struct hlsl_type *type; + struct hlsl_type *type; struct hlsl_ir_node *offset; struct hlsl_block block; @@ -145,7 +146,7 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der return true; } - deref->offset_regset = hlsl_type_get_regset(type); + deref->data_type = type; if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &instr->loc))) return false; @@ -1689,7 +1690,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ { struct hlsl_ir_resource_load *load = hlsl_ir_resource_load(instr); - if (!(load->resource.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) + if (!load->resource.var->is_uniform) { hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, "Loaded resource must have a single uniform source."); @@ -1704,7 +1705,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ if (load->sampler.var) { - if (!(load->sampler.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) + if (!load->sampler.var->is_uniform) { hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, "Resource load sampler must have a single uniform source."); @@ -1722,7 +1723,7 @@ static bool validate_static_object_references(struct hlsl_ctx *ctx, struct hlsl_ { struct hlsl_ir_resource_store *store = hlsl_ir_resource_store(instr); - if (!(store->resource.var->storage_modifiers & HLSL_STORAGE_UNIFORM)) + if (!store->resource.var->is_uniform) { hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_NON_STATIC_OBJECT_REF, "Accessed resource must have a single uniform source."); @@ -2066,6 +2067,97 @@ static bool lower_nonconstant_vector_derefs(struct hlsl_ctx *ctx, struct hlsl_ir return false; } +/* Lower combined samples and sampler variables to synthesized separated textures and samplers. + * That is, translate SM1-style samples in the source to SM4-style samples in the bytecode. */ +static bool lower_combined_samples(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_resource_load *load; + struct vkd3d_string_buffer *name; + struct hlsl_ir_var *var; + unsigned int i; + + if (instr->type != HLSL_IR_RESOURCE_LOAD) + return false; + load = hlsl_ir_resource_load(instr); + + switch (load->load_type) + { + case HLSL_RESOURCE_LOAD: + case HLSL_RESOURCE_GATHER_RED: + case HLSL_RESOURCE_GATHER_GREEN: + case HLSL_RESOURCE_GATHER_BLUE: + case HLSL_RESOURCE_GATHER_ALPHA: + case HLSL_RESOURCE_SAMPLE_CMP: + case HLSL_RESOURCE_SAMPLE_CMP_LZ: + case HLSL_RESOURCE_SAMPLE_GRAD: + return false; + + case HLSL_RESOURCE_SAMPLE: + case HLSL_RESOURCE_SAMPLE_LOD: + case HLSL_RESOURCE_SAMPLE_LOD_BIAS: + break; + } + if (load->sampler.var) + return false; + + if (!hlsl_type_is_resource(load->resource.var->data_type)) + { + hlsl_fixme(ctx, &instr->loc, "Lower combined samplers within structs."); + return false; + } + + assert(hlsl_type_get_regset(load->resource.var->data_type) == HLSL_REGSET_SAMPLERS); + + if (!(name = hlsl_get_string_buffer(ctx))) + return false; + vkd3d_string_buffer_printf(name, "%s", load->resource.var->name); + + TRACE("Lowering to separate resource %s.\n", debugstr_a(name->buffer)); + + if (!(var = hlsl_get_var(ctx->globals, name->buffer))) + { + struct hlsl_type *texture_array_type = hlsl_new_texture_type(ctx, load->sampling_dim, + hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, 4), 0); + + /* Create (possibly multi-dimensional) texture array type with the same dims as the sampler array. */ + struct hlsl_type *arr_type = load->resource.var->data_type; + for (i = 0; i < load->resource.path_len; ++i) + { + assert(arr_type->class == HLSL_CLASS_ARRAY); + texture_array_type = hlsl_new_array_type(ctx, texture_array_type, arr_type->e.array.elements_count); + arr_type = arr_type->e.array.type; + } + + if (!(var = hlsl_new_synthetic_var_named(ctx, name->buffer, texture_array_type, &instr->loc, false))) + { + hlsl_release_string_buffer(ctx, name); + return false; + } + var->is_uniform = 1; + var->is_separated_resource = true; + + list_add_tail(&ctx->extern_vars, &var->extern_entry); + } + hlsl_release_string_buffer(ctx, name); + + if (load->sampling_dim != var->data_type->sampler_dim) + { + hlsl_error(ctx, &load->node.loc, VKD3D_SHADER_ERROR_HLSL_INCONSISTENT_SAMPLER, + "Cannot split combined samplers from \"%s\" if they have different usage dimensions.", + load->resource.var->name); + hlsl_note(ctx, &var->loc, VKD3D_SHADER_LOG_ERROR, "First use as combined sampler is here."); + return false; + + } + + hlsl_copy_deref(ctx, &load->sampler, &load->resource); + load->resource.var = var; + assert(hlsl_deref_get_type(ctx, &load->resource)->base_type == HLSL_TYPE_TEXTURE); + assert(hlsl_deref_get_type(ctx, &load->sampler)->base_type == HLSL_TYPE_SAMPLER); + + return true; +} + /* Lower DIV to RCP + MUL. */ static bool lower_division(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { @@ -3096,7 +3188,7 @@ static const char *debug_register(char class, struct hlsl_reg reg, const struct return vkd3d_dbg_sprintf("%c%u%s", class, reg.id, debug_hlsl_writemask(reg.writemask)); } -static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +static bool track_object_components_sampler_dim(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { struct hlsl_ir_resource_load *load; struct hlsl_ir_var *var; @@ -3108,15 +3200,16 @@ static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_n load = hlsl_ir_resource_load(instr); var = load->resource.var; + regset = hlsl_type_get_regset(hlsl_deref_get_type(ctx, &load->resource)); + if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) + return false; if (regset == HLSL_REGSET_SAMPLERS) { enum hlsl_sampler_dim dim; assert(!load->sampler.var); - if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) - return false; dim = var->objects_usage[regset][index].sampler_dim; if (dim != load->sampling_dim) @@ -3134,25 +3227,37 @@ static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_n return false; } } - var->objects_usage[regset][index].used = true; - var->objects_usage[regset][index].sampler_dim = load->sampling_dim; } - else - { - if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) - return false; + var->objects_usage[regset][index].sampler_dim = load->sampling_dim; - var->objects_usage[regset][index].used = true; - var->objects_usage[regset][index].sampler_dim = load->sampling_dim; + return false; +} - if (load->sampler.var) - { - var = load->sampler.var; - if (!hlsl_regset_index_from_deref(ctx, &load->sampler, HLSL_REGSET_SAMPLERS, &index)) - return false; +static bool track_object_components_usage(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + struct hlsl_ir_resource_load *load; + struct hlsl_ir_var *var; + enum hlsl_regset regset; + unsigned int index; - var->objects_usage[HLSL_REGSET_SAMPLERS][index].used = true; - } + if (instr->type != HLSL_IR_RESOURCE_LOAD) + return false; + + load = hlsl_ir_resource_load(instr); + var = load->resource.var; + + regset = hlsl_type_get_regset(hlsl_deref_get_type(ctx, &load->resource)); + if (!hlsl_regset_index_from_deref(ctx, &load->resource, regset, &index)) + return false; + + var->objects_usage[regset][index].used = true; + if (load->sampler.var) + { + var = load->sampler.var; + if (!hlsl_regset_index_from_deref(ctx, &load->sampler, HLSL_REGSET_SAMPLERS, &index)) + return false; + + var->objects_usage[HLSL_REGSET_SAMPLERS][index].used = true; } return false; @@ -3172,9 +3277,12 @@ static void calculate_resource_register_counts(struct hlsl_ctx *ctx) { for (i = 0; i < type->reg_size[k]; ++i) { - /* Samplers are only allocated until the last used one. */ + bool is_separated = var->is_separated_resource; + + /* Samplers (and textures separated from them) are only allocated until the last + * used one. */ if (var->objects_usage[k][i].used) - var->regs[k].bind_count = (k == HLSL_REGSET_SAMPLERS) ? i + 1 : type->reg_size[k]; + var->regs[k].bind_count = (k == HLSL_REGSET_SAMPLERS || is_separated) ? i + 1 : type->reg_size[k]; } } } @@ -3568,7 +3676,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) LIST_FOR_EACH_ENTRY(var1, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (!var1->is_uniform || var1->data_type->class == HLSL_CLASS_OBJECT) + if (!var1->is_uniform || hlsl_type_is_resource(var1->data_type)) continue; buffer = var1->buffer; @@ -3579,7 +3687,7 @@ static void validate_buffer_offsets(struct hlsl_ctx *ctx) { unsigned int var1_reg_size, var2_reg_size; - if (!var2->is_uniform || var2->data_type->class == HLSL_CLASS_OBJECT) + if (!var2->is_uniform || hlsl_type_is_resource(var2->data_type)) continue; if (var1 == var2 || var1->buffer != var2->buffer) @@ -3629,7 +3737,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx) LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (var->is_uniform && var->data_type->class != HLSL_CLASS_OBJECT) + if (var->is_uniform && !hlsl_type_is_resource(var->data_type)) { if (var->is_param) var->buffer = ctx->params_buffer; @@ -3689,7 +3797,7 @@ static void allocate_buffers(struct hlsl_ctx *ctx) } static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum hlsl_regset regset, - uint32_t index) + uint32_t index, bool allocated_only) { const struct hlsl_ir_var *var; unsigned int start, count; @@ -3703,6 +3811,9 @@ static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum * bound there even if the reserved vars aren't used. */ start = var->reg_reservation.reg_index; count = var->data_type->reg_size[regset]; + + if (!var->regs[regset].allocated && allocated_only) + continue; } else if (var->regs[regset].allocated) { @@ -3743,6 +3854,7 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) if (count == 0) continue; + /* The variable was already allocated if it has a reservation. */ if (var->regs[regset].allocated) { const struct hlsl_ir_var *reserved_object, *last_reported = NULL; @@ -3761,7 +3873,10 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) { index = var->regs[regset].id + i; - reserved_object = get_allocated_object(ctx, regset, index); + /* get_allocated_object() may return "var" itself, but we + * actually want that, otherwise we'll end up reporting the + * same conflict between the same two variables twice. */ + reserved_object = get_allocated_object(ctx, regset, index, true); if (reserved_object && reserved_object != var && reserved_object != last_reported) { hlsl_error(ctx, &var->loc, VKD3D_SHADER_ERROR_HLSL_OVERLAPPING_RESERVATIONS, @@ -3780,7 +3895,7 @@ static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset) while (available < count) { - if (get_allocated_object(ctx, regset, index)) + if (get_allocated_object(ctx, regset, index, false)) available = 0; else ++available; @@ -3924,6 +4039,7 @@ bool hlsl_regset_index_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, unsigned int *offset) { struct hlsl_ir_node *offset_node = deref->offset.node; + enum hlsl_regset regset; unsigned int size; if (!offset_node) @@ -3940,8 +4056,9 @@ bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref return false; *offset = hlsl_ir_constant(offset_node)->value.u[0].u; + regset = hlsl_type_get_regset(deref->data_type); - size = deref->var->data_type->reg_size[deref->offset_regset]; + size = deref->var->data_type->reg_size[regset]; if (*offset >= size) { hlsl_error(ctx, &deref->offset.node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS, @@ -3971,7 +4088,8 @@ struct hlsl_reg hlsl_reg_from_deref(struct hlsl_ctx *ctx, const struct hlsl_dere struct hlsl_reg ret = var->regs[HLSL_REGSET_NUMERIC]; unsigned int offset = hlsl_offset_from_deref_safe(ctx, deref); - assert(deref->offset_regset == HLSL_REGSET_NUMERIC); + assert(deref->data_type); + assert(deref->data_type->class <= HLSL_CLASS_LAST_NUMERIC); ret.id += offset / 4; @@ -4169,6 +4287,12 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry hlsl_transform_ir(ctx, lower_casts_to_bool, body, NULL); hlsl_transform_ir(ctx, lower_int_dot, body, NULL); + hlsl_transform_ir(ctx, validate_static_object_references, body, NULL); + hlsl_transform_ir(ctx, track_object_components_sampler_dim, body, NULL); + if (profile->major_version >= 4) + hlsl_transform_ir(ctx, lower_combined_samples, body, NULL); + hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); + if (profile->major_version < 4) { hlsl_transform_ir(ctx, lower_division, body, NULL); @@ -4182,9 +4306,6 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry hlsl_transform_ir(ctx, lower_abs, body, NULL); } - hlsl_transform_ir(ctx, validate_static_object_references, body, NULL); - hlsl_transform_ir(ctx, track_object_components_usage, body, NULL); - /* TODO: move forward, remove when no longer needed */ transform_derefs(ctx, replace_deref_path_with_offset, body); while (hlsl_transform_ir(ctx, hlsl_fold_constant_exprs, body, NULL)); diff --git a/libs/vkd3d/libs/vkd3d-shader/tpf.c b/libs/vkd3d/libs/vkd3d-shader/tpf.c index 290fdcb3f62..801c688a297 100644 --- a/libs/vkd3d/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d/libs/vkd3d-shader/tpf.c @@ -2970,47 +2970,154 @@ static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *typ } } +struct extern_resource +{ + /* var is only not NULL if this resource is a whole variable, so it may be responsible for more + * than one component. */ + const struct hlsl_ir_var *var; + + char *name; + struct hlsl_type *data_type; + bool is_user_packed; + + enum hlsl_regset regset; + unsigned int id, bind_count; +}; + static int sm4_compare_extern_resources(const void *a, const void *b) { - const struct hlsl_ir_var *aa = *(const struct hlsl_ir_var **)a; - const struct hlsl_ir_var *bb = *(const struct hlsl_ir_var **)b; - enum hlsl_regset aa_regset, bb_regset; + const struct extern_resource *aa = (const struct extern_resource *)a; + const struct extern_resource *bb = (const struct extern_resource *)b; + int r; + + if ((r = vkd3d_u32_compare(aa->regset, bb->regset))) + return r; - aa_regset = hlsl_type_get_regset(aa->data_type); - bb_regset = hlsl_type_get_regset(bb->data_type); + return vkd3d_u32_compare(aa->id, bb->id); +} - if (aa_regset != bb_regset) - return aa_regset - bb_regset; +static void sm4_free_extern_resources(struct extern_resource *extern_resources, unsigned int count) +{ + unsigned int i; - return aa->regs[aa_regset].id - bb->regs[bb_regset].id; + for (i = 0; i < count; ++i) + vkd3d_free(extern_resources[i].name); + vkd3d_free(extern_resources); +} + +static const char *string_skip_tag(const char *string) +{ + if (!strncmp(string, "", strlen(""))) + return string + strlen(""); + return string; } -static const struct hlsl_ir_var **sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count) +static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, unsigned int *count) { - const struct hlsl_ir_var **extern_resources = NULL; + bool separate_components = ctx->profile->major_version == 5 && ctx->profile->minor_version == 0; + struct extern_resource *extern_resources = NULL; const struct hlsl_ir_var *var; enum hlsl_regset regset; size_t capacity = 0; + char *name; *count = 0; LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - if (!hlsl_type_is_resource(var->data_type)) - continue; - regset = hlsl_type_get_regset(var->data_type); - if (!var->regs[regset].allocated) - continue; - - if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, - sizeof(*extern_resources)))) + if (separate_components) { - *count = 0; - return NULL; + unsigned int component_count = hlsl_type_component_count(var->data_type); + unsigned int k, regset_offset; + + for (k = 0; k < component_count; ++k) + { + struct hlsl_type *component_type = hlsl_type_get_component_type(ctx, var->data_type, k); + struct vkd3d_string_buffer *name_buffer; + + if (!hlsl_type_is_resource(component_type)) + continue; + + regset = hlsl_type_get_regset(component_type); + regset_offset = hlsl_type_get_component_offset(ctx, var->data_type, regset, k); + + if (regset_offset > var->regs[regset].bind_count) + continue; + + if (var->objects_usage[regset][regset_offset].used) + { + if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, + sizeof(*extern_resources)))) + { + sm4_free_extern_resources(extern_resources, *count); + *count = 0; + return NULL; + } + + if (!(name_buffer = hlsl_component_to_string(ctx, var, k))) + { + sm4_free_extern_resources(extern_resources, *count); + *count = 0; + return NULL; + } + if (!(name = hlsl_strdup(ctx, string_skip_tag(name_buffer->buffer)))) + { + sm4_free_extern_resources(extern_resources, *count); + *count = 0; + hlsl_release_string_buffer(ctx, name_buffer); + return NULL; + } + hlsl_release_string_buffer(ctx, name_buffer); + + extern_resources[*count].var = NULL; + + extern_resources[*count].name = name; + extern_resources[*count].data_type = component_type; + extern_resources[*count].is_user_packed = false; + + extern_resources[*count].regset = regset; + extern_resources[*count].id = var->regs[regset].id + regset_offset; + extern_resources[*count].bind_count = 1; + + ++*count; + } + } } + else + { + if (!hlsl_type_is_resource(var->data_type)) + continue; + regset = hlsl_type_get_regset(var->data_type); + if (!var->regs[regset].allocated) + continue; + + if (!(hlsl_array_reserve(ctx, (void **)&extern_resources, &capacity, *count + 1, + sizeof(*extern_resources)))) + { + sm4_free_extern_resources(extern_resources, *count); + *count = 0; + return NULL; + } - extern_resources[*count] = var; - ++*count; + if (!(name = hlsl_strdup(ctx, string_skip_tag(var->name)))) + { + sm4_free_extern_resources(extern_resources, *count); + *count = 0; + return NULL; + } + + extern_resources[*count].var = var; + + extern_resources[*count].name = name; + extern_resources[*count].data_type = var->data_type; + extern_resources[*count].is_user_packed = !!var->reg_reservation.reg_type; + + extern_resources[*count].regset = regset; + extern_resources[*count].id = var->regs[regset].id; + extern_resources[*count].bind_count = var->regs[regset].bind_count; + + ++*count; + } } qsort(extern_resources, *count, sizeof(*extern_resources), sm4_compare_extern_resources); @@ -3023,8 +3130,8 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) size_t cbuffers_offset, resources_offset, creator_offset, string_offset; size_t cbuffer_position, resource_position, creator_position; const struct hlsl_profile_info *profile = ctx->profile; - const struct hlsl_ir_var **extern_resources; struct vkd3d_bytecode_buffer buffer = {0}; + struct extern_resource *extern_resources; const struct hlsl_buffer *cbuffer; const struct hlsl_ir_var *var; @@ -3078,18 +3185,15 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) for (i = 0; i < extern_resources_count; ++i) { - enum hlsl_regset regset; + const struct extern_resource *resource = &extern_resources[i]; uint32_t flags = 0; - var = extern_resources[i]; - regset = hlsl_type_get_regset(var->data_type); - - if (var->reg_reservation.reg_type) + if (resource->is_user_packed) flags |= D3D_SIF_USERPACKED; put_u32(&buffer, 0); /* name */ - put_u32(&buffer, sm4_resource_type(var->data_type)); - if (regset == HLSL_REGSET_SAMPLERS) + put_u32(&buffer, sm4_resource_type(resource->data_type)); + if (resource->regset == HLSL_REGSET_SAMPLERS) { put_u32(&buffer, 0); put_u32(&buffer, 0); @@ -3097,15 +3201,15 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) } else { - unsigned int dimx = hlsl_type_get_component_type(ctx, var->data_type, 0)->e.resource_format->dimx; + unsigned int dimx = hlsl_type_get_component_type(ctx, resource->data_type, 0)->e.resource_format->dimx; - put_u32(&buffer, sm4_resource_format(var->data_type)); - put_u32(&buffer, sm4_rdef_resource_dimension(var->data_type)); + put_u32(&buffer, sm4_resource_format(resource->data_type)); + put_u32(&buffer, sm4_rdef_resource_dimension(resource->data_type)); put_u32(&buffer, ~0u); /* FIXME: multisample count */ flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; } - put_u32(&buffer, var->regs[regset].id); - put_u32(&buffer, var->regs[regset].bind_count); + put_u32(&buffer, resource->id); + put_u32(&buffer, resource->bind_count); put_u32(&buffer, flags); } @@ -3131,9 +3235,9 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) for (i = 0; i < extern_resources_count; ++i) { - var = extern_resources[i]; + const struct extern_resource *resource = &extern_resources[i]; - string_offset = put_string(&buffer, var->name); + string_offset = put_string(&buffer, resource->name); set_u32(&buffer, resources_offset + i * 8 * sizeof(uint32_t), string_offset); } @@ -3239,7 +3343,7 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc) add_section(dxbc, TAG_RDEF, &buffer); - vkd3d_free(extern_resources); + sm4_free_extern_resources(extern_resources, extern_resources_count); } static enum vkd3d_sm4_resource_type sm4_resource_dimension(const struct hlsl_type *type) @@ -3349,8 +3453,9 @@ struct sm4_instruction static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *reg, unsigned int *writemask, enum vkd3d_sm4_swizzle_type *swizzle_type, - const struct hlsl_deref *deref, const struct hlsl_type *data_type) + const struct hlsl_deref *deref) { + const struct hlsl_type *data_type = hlsl_deref_get_type(ctx, deref); const struct hlsl_ir_var *var = deref->var; if (var->is_uniform) @@ -3365,7 +3470,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r *swizzle_type = VKD3D_SM4_SWIZZLE_VEC4; reg->idx[0] = var->regs[HLSL_REGSET_TEXTURES].id; reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); - assert(deref->offset_regset == HLSL_REGSET_TEXTURES); + assert(regset == HLSL_REGSET_TEXTURES); reg->idx_count = 1; *writemask = VKD3DSP_WRITEMASK_ALL; } @@ -3377,7 +3482,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r *swizzle_type = VKD3D_SM4_SWIZZLE_VEC4; reg->idx[0] = var->regs[HLSL_REGSET_UAVS].id; reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); - assert(deref->offset_regset == HLSL_REGSET_UAVS); + assert(regset == HLSL_REGSET_UAVS); reg->idx_count = 1; *writemask = VKD3DSP_WRITEMASK_ALL; } @@ -3389,7 +3494,7 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r *swizzle_type = VKD3D_SM4_SWIZZLE_NONE; reg->idx[0] = var->regs[HLSL_REGSET_SAMPLERS].id; reg->idx[0] += hlsl_offset_from_deref_safe(ctx, deref); - assert(deref->offset_regset == HLSL_REGSET_SAMPLERS); + assert(regset == HLSL_REGSET_SAMPLERS); reg->idx_count = 1; *writemask = VKD3DSP_WRITEMASK_ALL; } @@ -3487,11 +3592,11 @@ static void sm4_register_from_deref(struct hlsl_ctx *ctx, struct sm4_register *r } static void sm4_src_from_deref(struct hlsl_ctx *ctx, struct sm4_src_register *src, - const struct hlsl_deref *deref, const struct hlsl_type *data_type, unsigned int map_writemask) + const struct hlsl_deref *deref, unsigned int map_writemask) { unsigned int writemask; - sm4_register_from_deref(ctx, &src->reg, &writemask, &src->swizzle_type, deref, data_type); + sm4_register_from_deref(ctx, &src->reg, &writemask, &src->swizzle_type, deref); if (src->swizzle_type == VKD3D_SM4_SWIZZLE_VEC4) src->swizzle = hlsl_map_swizzle(hlsl_swizzle_from_writemask(writemask), map_writemask); } @@ -3692,9 +3797,11 @@ static void write_sm4_dcl_constant_buffer(struct vkd3d_bytecode_buffer *buffer, write_sm4_instruction(buffer, &instr); } -static void write_sm4_dcl_samplers(struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_var *var) +static void write_sm4_dcl_samplers(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, + const struct extern_resource *resource) { - unsigned int i, count = var->data_type->reg_size[HLSL_REGSET_SAMPLERS]; + struct hlsl_type *component_type; + unsigned int i; struct sm4_instruction instr = { .opcode = VKD3D_SM4_OP_DCL_SAMPLER, @@ -3704,38 +3811,44 @@ static void write_sm4_dcl_samplers(struct vkd3d_bytecode_buffer *buffer, const s .dst_count = 1, }; - if (var->data_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON) + component_type = hlsl_type_get_component_type(ctx, resource->data_type, 0); + + if (component_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON) instr.opcode |= VKD3D_SM4_SAMPLER_COMPARISON << VKD3D_SM4_SAMPLER_MODE_SHIFT; - for (i = 0; i < count; ++i) + assert(resource->regset == HLSL_REGSET_SAMPLERS); + + for (i = 0; i < resource->bind_count; ++i) { - if (!var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) + if (resource->var && !resource->var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) continue; - instr.dsts[0].reg.idx[0] = var->regs[HLSL_REGSET_SAMPLERS].id + i; + instr.dsts[0].reg.idx[0] = resource->id + i; write_sm4_instruction(buffer, &instr); } } static void write_sm4_dcl_textures(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, - const struct hlsl_ir_var *var, bool uav) + const struct extern_resource *resource, bool uav) { enum hlsl_regset regset = uav ? HLSL_REGSET_UAVS : HLSL_REGSET_TEXTURES; - unsigned int i, count = var->data_type->reg_size[regset]; struct hlsl_type *component_type; struct sm4_instruction instr; + unsigned int i; - component_type = hlsl_type_get_component_type(ctx, var->data_type, 0); + assert(resource->regset == regset); - for (i = 0; i < count; ++i) + component_type = hlsl_type_get_component_type(ctx, resource->data_type, 0); + + for (i = 0; i < resource->bind_count; ++i) { - if (!var->objects_usage[regset][i].used) + if (resource->var && !resource->var->objects_usage[regset][i].used) continue; instr = (struct sm4_instruction) { .dsts[0].reg.type = uav ? VKD3D_SM5_RT_UAV : VKD3D_SM4_RT_RESOURCE, - .dsts[0].reg.idx = {var->regs[regset].id + i}, + .dsts[0].reg.idx = {resource->id + i}, .dsts[0].reg.idx_count = 1, .dst_count = 1, @@ -3745,11 +3858,11 @@ static void write_sm4_dcl_textures(struct hlsl_ctx *ctx, struct vkd3d_bytecode_b if (uav) { - switch (var->data_type->sampler_dim) + switch (resource->data_type->sampler_dim) { case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER: instr.opcode = VKD3D_SM5_OP_DCL_UAV_STRUCTURED; - instr.byte_stride = var->data_type->e.resource_format->reg_size[HLSL_REGSET_NUMERIC] * 4; + instr.byte_stride = resource->data_type->e.resource_format->reg_size[HLSL_REGSET_NUMERIC] * 4; break; default: instr.opcode = VKD3D_SM5_OP_DCL_UAV_TYPED; @@ -4011,11 +4124,11 @@ static void write_sm4_binary_op_with_two_destinations(struct vkd3d_bytecode_buff } static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, - const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, - const struct hlsl_deref *resource, const struct hlsl_ir_node *coords, - const struct hlsl_ir_node *sample_index, const struct hlsl_ir_node *texel_offset, - enum hlsl_sampler_dim dim) + const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, + const struct hlsl_ir_node *coords, const struct hlsl_ir_node *sample_index, + const struct hlsl_ir_node *texel_offset, enum hlsl_sampler_dim dim) { + const struct hlsl_type *resource_type = hlsl_deref_get_type(ctx, resource); bool multisampled = resource_type->base_type == HLSL_TYPE_TEXTURE && (resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || resource_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY); bool uav = (hlsl_type_get_regset(resource_type) == HLSL_REGSET_UAVS); @@ -4055,7 +4168,7 @@ static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buf sm4_src_from_node(&instr.srcs[0], coords, coords_writemask); - sm4_src_from_deref(ctx, &instr.srcs[1], resource, resource_type, instr.dsts[0].writemask); + sm4_src_from_deref(ctx, &instr.srcs[1], resource, instr.dsts[0].writemask); instr.src_count = 2; @@ -4092,7 +4205,6 @@ static void write_sm4_ld(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buf static void write_sm4_sample(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_load *load) { - const struct hlsl_type *resource_type = load->resource.var->data_type; const struct hlsl_ir_node *texel_offset = load->texel_offset.node; const struct hlsl_ir_node *coords = load->coords.node; const struct hlsl_deref *resource = &load->resource; @@ -4145,8 +4257,8 @@ static void write_sm4_sample(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer instr.dst_count = 1; sm4_src_from_node(&instr.srcs[0], coords, VKD3DSP_WRITEMASK_ALL); - sm4_src_from_deref(ctx, &instr.srcs[1], resource, resource_type, instr.dsts[0].writemask); - sm4_src_from_deref(ctx, &instr.srcs[2], sampler, sampler->var->data_type, VKD3DSP_WRITEMASK_ALL); + sm4_src_from_deref(ctx, &instr.srcs[1], resource, instr.dsts[0].writemask); + sm4_src_from_deref(ctx, &instr.srcs[2], sampler, VKD3DSP_WRITEMASK_ALL); instr.src_count = 3; if (load->load_type == HLSL_RESOURCE_SAMPLE_LOD @@ -4316,7 +4428,7 @@ static void write_sm4_store_uav_typed(struct hlsl_ctx *ctx, struct vkd3d_bytecod memset(&instr, 0, sizeof(instr)); instr.opcode = VKD3D_SM5_OP_STORE_UAV_TYPED; - sm4_register_from_deref(ctx, &instr.dsts[0].reg, &instr.dsts[0].writemask, NULL, dst, dst->var->data_type); + sm4_register_from_deref(ctx, &instr.dsts[0].reg, &instr.dsts[0].writemask, NULL, dst); instr.dst_count = 1; sm4_src_from_node(&instr.srcs[0], coords, VKD3DSP_WRITEMASK_ALL); @@ -4856,7 +4968,7 @@ static void write_sm4_load(struct hlsl_ctx *ctx, instr.opcode = VKD3D_SM4_OP_MOVC; - sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, type, instr.dsts[0].writemask); + sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, instr.dsts[0].writemask); memset(&value, 0xff, sizeof(value)); sm4_src_from_constant_value(&instr.srcs[1], &value, type->dimx, instr.dsts[0].writemask); @@ -4868,7 +4980,7 @@ static void write_sm4_load(struct hlsl_ctx *ctx, { instr.opcode = VKD3D_SM4_OP_MOV; - sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, type, instr.dsts[0].writemask); + sm4_src_from_deref(ctx, &instr.srcs[0], &load->src, instr.dsts[0].writemask); instr.src_count = 1; } @@ -4892,8 +5004,7 @@ static void write_sm4_loop(struct hlsl_ctx *ctx, } static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, - const struct hlsl_type *resource_type, const struct hlsl_ir_node *dst, - const struct hlsl_deref *resource, const struct hlsl_deref *sampler, + const struct hlsl_ir_node *dst, const struct hlsl_deref *resource, const struct hlsl_deref *sampler, const struct hlsl_ir_node *coords, unsigned int swizzle, const struct hlsl_ir_node *texel_offset) { struct sm4_src_register *src; @@ -4923,10 +5034,10 @@ static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer } } - sm4_src_from_deref(ctx, &instr.srcs[instr.src_count++], resource, resource_type, instr.dsts[0].writemask); + sm4_src_from_deref(ctx, &instr.srcs[instr.src_count++], resource, instr.dsts[0].writemask); src = &instr.srcs[instr.src_count++]; - sm4_src_from_deref(ctx, src, sampler, sampler->var->data_type, VKD3DSP_WRITEMASK_ALL); + sm4_src_from_deref(ctx, src, sampler, VKD3DSP_WRITEMASK_ALL); src->reg.dim = VKD3D_SM4_DIMENSION_VEC4; src->swizzle_type = VKD3D_SM4_SWIZZLE_SCALAR; src->swizzle = swizzle; @@ -4937,34 +5048,16 @@ static void write_sm4_gather(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer static void write_sm4_resource_load(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_load *load) { - const struct hlsl_type *resource_type = load->resource.var->data_type; const struct hlsl_ir_node *texel_offset = load->texel_offset.node; const struct hlsl_ir_node *sample_index = load->sample_index.node; const struct hlsl_ir_node *coords = load->coords.node; - if (!hlsl_type_is_resource(resource_type)) + if (load->sampler.var && !load->sampler.var->is_uniform) { - hlsl_fixme(ctx, &load->node.loc, "Separate object fields as new variables."); + hlsl_fixme(ctx, &load->node.loc, "Sample using non-uniform sampler variable."); return; } - if (load->sampler.var) - { - const struct hlsl_type *sampler_type = load->sampler.var->data_type; - - if (!hlsl_type_is_resource(sampler_type)) - { - hlsl_fixme(ctx, &load->node.loc, "Separate object fields as new variables."); - return; - } - - if (!load->sampler.var->is_uniform) - { - hlsl_fixme(ctx, &load->node.loc, "Sample using non-uniform sampler variable."); - return; - } - } - if (!load->resource.var->is_uniform) { hlsl_fixme(ctx, &load->node.loc, "Load from non-uniform resource variable."); @@ -4974,7 +5067,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, switch (load->load_type) { case HLSL_RESOURCE_LOAD: - write_sm4_ld(ctx, buffer, resource_type, &load->node, &load->resource, + write_sm4_ld(ctx, buffer, &load->node, &load->resource, coords, sample_index, texel_offset, load->sampling_dim); break; @@ -4984,32 +5077,29 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, case HLSL_RESOURCE_SAMPLE_LOD: case HLSL_RESOURCE_SAMPLE_LOD_BIAS: case HLSL_RESOURCE_SAMPLE_GRAD: - if (!load->sampler.var) - { - hlsl_fixme(ctx, &load->node.loc, "SM4 combined sample expression."); - return; - } + /* Combined sample expressions were lowered. */ + assert(load->sampler.var); write_sm4_sample(ctx, buffer, load); break; case HLSL_RESOURCE_GATHER_RED: - write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, - &load->sampler, coords, HLSL_SWIZZLE(X, X, X, X), texel_offset); + write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, + HLSL_SWIZZLE(X, X, X, X), texel_offset); break; case HLSL_RESOURCE_GATHER_GREEN: - write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, - &load->sampler, coords, HLSL_SWIZZLE(Y, Y, Y, Y), texel_offset); + write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, + HLSL_SWIZZLE(Y, Y, Y, Y), texel_offset); break; case HLSL_RESOURCE_GATHER_BLUE: - write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, - &load->sampler, coords, HLSL_SWIZZLE(Z, Z, Z, Z), texel_offset); + write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, + HLSL_SWIZZLE(Z, Z, Z, Z), texel_offset); break; case HLSL_RESOURCE_GATHER_ALPHA: - write_sm4_gather(ctx, buffer, resource_type, &load->node, &load->resource, - &load->sampler, coords, HLSL_SWIZZLE(W, W, W, W), texel_offset); + write_sm4_gather(ctx, buffer, &load->node, &load->resource, &load->sampler, coords, + HLSL_SWIZZLE(W, W, W, W), texel_offset); break; } } @@ -5017,13 +5107,7 @@ static void write_sm4_resource_load(struct hlsl_ctx *ctx, static void write_sm4_resource_store(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *buffer, const struct hlsl_ir_resource_store *store) { - const struct hlsl_type *resource_type = store->resource.var->data_type; - - if (!hlsl_type_is_resource(resource_type)) - { - hlsl_fixme(ctx, &store->node.loc, "Separate object fields as new variables."); - return; - } + struct hlsl_type *resource_type = hlsl_deref_get_type(ctx, &store->resource); if (!store->resource.var->is_uniform) { @@ -5050,7 +5134,7 @@ static void write_sm4_store(struct hlsl_ctx *ctx, memset(&instr, 0, sizeof(instr)); instr.opcode = VKD3D_SM4_OP_MOV; - sm4_register_from_deref(ctx, &instr.dsts[0].reg, &writemask, NULL, &store->lhs, rhs->data_type); + sm4_register_from_deref(ctx, &instr.dsts[0].reg, &writemask, NULL, &store->lhs); instr.dsts[0].writemask = hlsl_combine_writemasks(writemask, store->writemask); instr.dst_count = 1; @@ -5161,8 +5245,8 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, const struct hlsl_ir_function_decl *entry_func, struct dxbc_writer *dxbc) { const struct hlsl_profile_info *profile = ctx->profile; - const struct hlsl_ir_var **extern_resources; struct vkd3d_bytecode_buffer buffer = {0}; + struct extern_resource *extern_resources; unsigned int extern_resources_count, i; const struct hlsl_buffer *cbuffer; const struct hlsl_ir_var *var; @@ -5194,17 +5278,14 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, for (i = 0; i < extern_resources_count; ++i) { - enum hlsl_regset regset; - - var = extern_resources[i]; - regset = hlsl_type_get_regset(var->data_type); + const struct extern_resource *resource = &extern_resources[i]; - if (regset == HLSL_REGSET_SAMPLERS) - write_sm4_dcl_samplers(&buffer, var); - else if (regset == HLSL_REGSET_TEXTURES) - write_sm4_dcl_textures(ctx, &buffer, var, false); - else if (regset == HLSL_REGSET_UAVS) - write_sm4_dcl_textures(ctx, &buffer, var, true); + if (resource->regset == HLSL_REGSET_SAMPLERS) + write_sm4_dcl_samplers(ctx, &buffer, resource); + else if (resource->regset == HLSL_REGSET_TEXTURES) + write_sm4_dcl_textures(ctx, &buffer, resource, false); + else if (resource->regset == HLSL_REGSET_UAVS) + write_sm4_dcl_textures(ctx, &buffer, resource, true); } LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) @@ -5227,7 +5308,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, add_section(dxbc, TAG_SHDR, &buffer); - vkd3d_free(extern_resources); + sm4_free_extern_resources(extern_resources, extern_resources_count); } int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func, struct vkd3d_shader_code *out) diff --git a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h index 85fca964227..0e93f3a556a 100644 --- a/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d/libs/vkd3d-shader/vkd3d_shader_private.h @@ -155,11 +155,19 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_OFFSET = 8002, VKD3D_SHADER_ERROR_DXIL_INVALID_CHUNK_SIZE = 8003, VKD3D_SHADER_ERROR_DXIL_INVALID_BITCODE = 8004, + VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND_COUNT = 8005, + VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_TABLE = 8006, + VKD3D_SHADER_ERROR_DXIL_INVALID_VALUE_SYMTAB = 8007, + VKD3D_SHADER_ERROR_DXIL_UNSUPPORTED_BITCODE_FORMAT = 8008, + VKD3D_SHADER_ERROR_DXIL_INVALID_FUNCTION_DCL = 8009, + VKD3D_SHADER_ERROR_DXIL_INVALID_TYPE_ID = 8010, + VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE = 8011, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_MAGIC_NUMBER = 8300, VKD3D_SHADER_WARNING_DXIL_UNKNOWN_SHADER_TYPE = 8301, VKD3D_SHADER_WARNING_DXIL_INVALID_BLOCK_LENGTH = 8302, VKD3D_SHADER_WARNING_DXIL_INVALID_MODULE_LENGTH = 8303, + VKD3D_SHADER_WARNING_DXIL_IGNORING_OPERANDS = 8304, }; enum vkd3d_shader_opcode @@ -529,6 +537,7 @@ enum vkd3d_data_type VKD3D_DATA_DOUBLE, VKD3D_DATA_CONTINUED, VKD3D_DATA_UNUSED, + VKD3D_DATA_UINT8, }; enum vkd3d_immconst_type -- 2.40.1