From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 115 +++++++++++++++++++++++ libs/vkd3d-shader/ir.c | 3 + libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 3 files changed, 120 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 78a5cb534..3865cdb59 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -1703,6 +1703,15 @@ static const struct sm6_type *sm6_type_get_element_type_at_index(const struct sm } }
+/* Call for aggregate or pointer types only. */ +static const struct sm6_type *sm6_type_get_element_or_pointee_type_at_index(const struct sm6_type *type, + uint64_t elem_idx) +{ + if (sm6_type_is_pointer(type) && !elem_idx) + return type->u.pointer.type; + return sm6_type_get_element_type_at_index(type, elem_idx); +} + /* Never returns null for elem_idx 0. */ static const struct sm6_type *sm6_type_get_scalar_type(const struct sm6_type *type, unsigned int elem_idx) { @@ -2195,6 +2204,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; @@ -3876,6 +3897,97 @@ 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 i, elem_idx, operand_idx = 2; + enum bitcode_address_space addr_space; + const struct sm6_value *operands[2]; + 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; + } + + 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; + + for (type = src->type, i = 0; operand_idx < record->operand_count; ++i) + { + bool is_constant; + + if (i > 1) + { + 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 (!sm6_type_is_pointer(type) && !sm6_type_is_aggregate(type)) + { + WARN("Invalid GEP on type class %u.\n", type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Source type of a GEP instruction is not a pointer or aggregate."); + return; + } + + if (!(elem_value = sm6_parser_get_value_by_ref(sm6, record, NULL, &operand_idx))) + return; + + is_constant = sm6_value_is_constant(elem_value); + elem_idx = is_constant ? sm6_value_get_constant_uint(elem_value) : 0; + + type = sm6_type_get_element_or_pointee_type_at_index(type, elem_idx); + + /* The first index is always a simple pointer dereference, i.e. zero. */ + if (!type || (!i && !is_constant)) + { + 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; + } + + operands[i] = elem_value; + } + + if (!(dst->type = sm6_type_get_pointer_to_type(type, addr_space, sm6))) + { + FIXME("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], operands[1], 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) { @@ -4078,6 +4190,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; diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 2a3343994..ae1610483 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -295,10 +295,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; } diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 9980827f9..68eef0b8d 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -811,6 +811,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