diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 6752cd14..9d104561 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -29,6 +29,9 @@ static const uint64_t MAX_ALIGNMENT_EXPONENT = 29; static const uint64_t GLOBALVAR_FLAG_IS_CONSTANT = 1; static const uint64_t GLOBALVAR_FLAG_EXPLICIT_TYPE = 2; static const unsigned int GLOBALVAR_ADDRESS_SPACE_SHIFT = 2; +static const uint64_t ALLOCA_FLAG_IN_ALLOCA = 0x20; +static const uint64_t ALLOCA_FLAG_EXPLICIT_TYPE = 0x40; +static const uint64_t ALLOCA_ALIGNMENT_MASK = ALLOCA_FLAG_IN_ALLOCA - 1; static const unsigned int SHADER_DESCRIPTOR_TYPE_COUNT = 4; static const unsigned int dx_max_thread_group_size[3] = {1024, 1024, 64}; @@ -2688,12 +2691,15 @@ static void sm6_parser_declare_icb(struct sm6_parser *sm6, const struct sm6_type } static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const struct sm6_type *elem_type, - unsigned int count, unsigned int alignment, unsigned int init, struct sm6_value *dst) + unsigned int count, unsigned int alignment, unsigned int init, struct vkd3d_shader_instruction *ins, + struct sm6_value *dst) { enum vkd3d_data_type data_type = vkd3d_data_type_from_sm6_type(elem_type); - struct vkd3d_shader_instruction *ins; - ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_INDEXABLE_TEMP); + if (ins) + vsir_instruction_init(ins, &sm6->p.location, VKD3DSIH_DCL_INDEXABLE_TEMP); + else + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_DCL_INDEXABLE_TEMP); ins->declaration.indexable_temp.register_idx = sm6->indexable_temp_count++; ins->declaration.indexable_temp.register_size = count; ins->declaration.indexable_temp.alignment = alignment; @@ -2826,7 +2832,7 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_ if (is_constant) sm6_parser_declare_icb(sm6, scalar_type, count, alignment, init, dst); else - sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, dst); + sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, NULL, dst); } else if (address_space == ADDRESS_SPACE_GROUPSHARED) { @@ -3019,6 +3025,81 @@ static struct sm6_block *sm6_block_create() return block; } +static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_record *record, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) +{ + const struct sm6_type *type[2], *elem_type; + const struct sm6_value *size; + unsigned int i, alignment; + uint64_t packed_operands; + + if (!dxil_record_validate_operand_count(record, 4, 4, sm6)) + return; + + for (i = 0; i < 2; ++i) + { + if (!(type[i] = sm6_parser_get_type(sm6, record->operands[i]))) + return; + } + + packed_operands = record->operands[3]; + if (packed_operands & ALLOCA_FLAG_IN_ALLOCA) + WARN("Ignoring in_alloca flag.\n"); + if (!(packed_operands & ALLOCA_FLAG_EXPLICIT_TYPE)) + { + FIXME("Unhandled implicit type.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Implicit result type for ALLOCA instructions is not supported."); + return; + } + packed_operands &= ~(ALLOCA_FLAG_IN_ALLOCA | ALLOCA_FLAG_EXPLICIT_TYPE); + + if (!sm6_type_is_array(type[0]) || !sm6_type_is_numeric(elem_type = type[0]->u.array.elem_type)) + { + WARN("Type is not a numeric array.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Result type of an ALLOCA instruction is not a numeric array."); + return; + } + /* The second type operand is the type of the allocation size operand, in case it is a + * forward reference. We only support a constant size, so no forward ref support is needed. */ + if (!sm6_type_is_integer(type[1])) + { + WARN("Size operand type is not scalar integer.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The type of the allocation size operand of an ALLOCA instruction is not scalar integer."); + return; + } + + if (!(dst->type = sm6_type_get_pointer_to_type(type[0], ADDRESS_SPACE_DEFAULT, sm6))) + { + WARN("Failed to get pointer type for type class %u.\n", type[0]->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "Module does not define a pointer type for an ALLOCA instruction."); + return; + } + + if (!(size = sm6_parser_get_value_safe(sm6, record->operands[2]))) + return; + /* A size of 1 means one instance of type[0], i.e. one array. */ + if (sm6_value_get_constant_uint(size) != 1) + { + FIXME("Allocation size is not 1.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "ALLOCA instruction allocation sizes other than 1 are not supported."); + return; + } + + if (!bitcode_parse_alignment(packed_operands & ALLOCA_ALIGNMENT_MASK, &alignment)) + WARN("Invalid alignment %"PRIu64".\n", packed_operands); + packed_operands &= ~ALLOCA_ALIGNMENT_MASK; + + if (packed_operands) + WARN("Ignoring flags %#"PRIx64".\n", packed_operands); + + sm6_parser_declare_indexable_temp(sm6, elem_type, type[0]->u.array.count, alignment, 0, ins, dst); +} + static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_type *type_a, const struct sm6_type *type_b, struct sm6_parser *sm6) { @@ -4578,6 +4659,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const record = block->records[i]; switch (record->code) { + case FUNC_CODE_INST_ALLOCA: + sm6_parser_emit_alloca(sm6, record, ins, dst); + break; case FUNC_CODE_INST_BINOP: sm6_parser_emit_binop(sm6, record, ins, dst); break;