vkd3d-shader/dxil: Implement the DXIL ALLOCA instruction.

This commit is contained in:
Conor McCarthy 2023-11-21 14:20:25 +10:00 committed by Alexandre Julliard
parent df82c61482
commit 2d5f2bf7a4
Notes: Alexandre Julliard 2023-12-11 23:20:30 +01:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Approved-by: Alexandre Julliard (@julliard)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/498

View File

@ -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;