mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-11-21 16:46:41 -08:00
vkd3d-shader/dxil: Implement the DXIL GEP instruction.
This commit is contained in:
parent
a0f5d70792
commit
59730ecfd8
Notes:
Alexandre Julliard
2023-11-22 22:48:50 +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/471
@ -2195,6 +2195,18 @@ static bool sm6_value_validate_is_handle(const struct sm6_value *value, struct s
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sm6_value_validate_is_pointer(const struct sm6_value *value, struct sm6_parser *sm6)
|
||||
{
|
||||
if (!sm6_type_is_pointer(value->type))
|
||||
{
|
||||
WARN("Operand result type class %u is not a pointer.\n", value->type->class);
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
|
||||
"A pointer operand passed to a DXIL instruction is not a pointer.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sm6_value_validate_is_bool(const struct sm6_value *value, struct sm6_parser *sm6)
|
||||
{
|
||||
const struct sm6_type *type = value->type;
|
||||
@ -3877,6 +3889,106 @@ static void sm6_parser_emit_extractval(struct sm6_parser *sm6, const struct dxil
|
||||
instruction_dst_param_init_ssa_scalar(ins, sm6);
|
||||
}
|
||||
|
||||
static void sm6_parser_emit_gep(struct sm6_parser *sm6, const struct dxil_record *record,
|
||||
struct vkd3d_shader_instruction *ins, struct sm6_value *dst)
|
||||
{
|
||||
const struct sm6_type *type, *pointee_type;
|
||||
unsigned int elem_idx, operand_idx = 2;
|
||||
enum bitcode_address_space addr_space;
|
||||
const struct sm6_value *elem_value;
|
||||
struct vkd3d_shader_register *reg;
|
||||
const struct sm6_value *src;
|
||||
bool is_in_bounds;
|
||||
|
||||
if (!dxil_record_validate_operand_min_count(record, 5, sm6)
|
||||
|| !(type = sm6_parser_get_type(sm6, record->operands[1]))
|
||||
|| !(src = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx))
|
||||
|| !sm6_value_validate_is_register(src, sm6)
|
||||
|| !sm6_value_validate_is_pointer(src, sm6)
|
||||
|| !dxil_record_validate_operand_min_count(record, operand_idx + 2, sm6))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (src->u.reg.idx_count > 1)
|
||||
{
|
||||
WARN("Unsupported stacked GEP.\n");
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
|
||||
"A GEP instruction on the result of a previous GEP is unsupported.");
|
||||
return;
|
||||
}
|
||||
|
||||
is_in_bounds = record->operands[0];
|
||||
|
||||
if ((pointee_type = src->type->u.pointer.type) != type)
|
||||
{
|
||||
WARN("Type mismatch, type %u width %u vs type %u width %u.\n", type->class,
|
||||
type->u.width, pointee_type->class, pointee_type->u.width);
|
||||
vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH,
|
||||
"Type mismatch in GEP operation arguments.");
|
||||
}
|
||||
addr_space = src->type->u.pointer.addr_space;
|
||||
|
||||
if (!(elem_value = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx)))
|
||||
return;
|
||||
|
||||
/* The first index is always zero, to form a simple pointer dereference. */
|
||||
if (sm6_value_get_constant_uint(elem_value))
|
||||
{
|
||||
WARN("Expected constant zero.\n");
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
|
||||
"The pointer dereference index for a GEP instruction is not constant zero.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sm6_type_is_array(pointee_type))
|
||||
{
|
||||
WARN("Invalid GEP on type class %u.\n", pointee_type->class);
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
|
||||
"Source type for index 1 of a GEP instruction is not an array.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(elem_value = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx)))
|
||||
return;
|
||||
|
||||
/* If indexing is dynamic, just get the type at offset zero. */
|
||||
elem_idx = sm6_value_is_constant(elem_value) ? sm6_value_get_constant_uint(elem_value) : 0;
|
||||
type = sm6_type_get_element_type_at_index(pointee_type, elem_idx);
|
||||
if (!type)
|
||||
{
|
||||
WARN("Invalid element index %u.\n", elem_idx);
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
|
||||
"Element index %u for a GEP instruction is out of bounds.", elem_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (operand_idx < record->operand_count)
|
||||
{
|
||||
FIXME("Multiple element indices are not implemented.\n");
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
|
||||
"Multi-dimensional addressing in GEP instructions is not supported.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(dst->type = sm6_type_get_pointer_to_type(type, addr_space, sm6)))
|
||||
{
|
||||
WARN("Failed to get pointer type for type %u.\n", type->class);
|
||||
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
|
||||
"Module does not define a pointer type for a GEP instruction.");
|
||||
return;
|
||||
}
|
||||
|
||||
reg = &dst->u.reg;
|
||||
*reg = src->u.reg;
|
||||
reg->idx[1].offset = 0;
|
||||
register_index_address_init(®->idx[1], elem_value, sm6);
|
||||
reg->idx[1].is_in_bounds = is_in_bounds;
|
||||
reg->idx_count = 2;
|
||||
|
||||
ins->handler_idx = VKD3DSIH_NOP;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -4079,6 +4191,9 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const
|
||||
case FUNC_CODE_INST_EXTRACTVAL:
|
||||
sm6_parser_emit_extractval(sm6, record, ins, dst);
|
||||
break;
|
||||
case FUNC_CODE_INST_GEP:
|
||||
sm6_parser_emit_gep(sm6, record, ins, dst);
|
||||
break;
|
||||
case FUNC_CODE_INST_RET:
|
||||
sm6_parser_emit_ret(sm6, record, code_block, ins);
|
||||
is_terminator = true;
|
||||
|
@ -300,10 +300,13 @@ void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_reg
|
||||
reg->data_type = data_type;
|
||||
reg->idx[0].offset = ~0u;
|
||||
reg->idx[0].rel_addr = NULL;
|
||||
reg->idx[0].is_in_bounds = false;
|
||||
reg->idx[1].offset = ~0u;
|
||||
reg->idx[1].rel_addr = NULL;
|
||||
reg->idx[1].is_in_bounds = false;
|
||||
reg->idx[2].offset = ~0u;
|
||||
reg->idx[2].rel_addr = NULL;
|
||||
reg->idx[2].is_in_bounds = false;
|
||||
reg->idx_count = idx_count;
|
||||
reg->dimension = VSIR_DIMENSION_SCALAR;
|
||||
}
|
||||
|
@ -814,6 +814,8 @@ struct vkd3d_shader_register_index
|
||||
{
|
||||
const struct vkd3d_shader_src_param *rel_addr;
|
||||
unsigned int offset;
|
||||
/* address is known to fall within the object (for optimisation) */
|
||||
bool is_in_bounds;
|
||||
};
|
||||
|
||||
struct vkd3d_shader_register
|
||||
|
Loading…
Reference in New Issue
Block a user