From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 110 +++++++++++++++++++++++ libs/vkd3d-shader/ir.c | 3 + libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 3 files changed, 114 insertions(+)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 6692eae08..17b16bac8 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -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; @@ -3868,6 +3880,101 @@ 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; + struct vkd3d_shader_register *reg; + struct sm6_value *operands[2]; + struct sm6_value *elem_value; + const struct sm6_value *src; + bool is_in_bounds; + size_t operand; + + if (!(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; + + if (record->operand_count > operand_idx + 2) + { + 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; + } + + for (type = src->type, i = 0; operand_idx < record->operand_count; ++i) + { + bool is_constant; + + 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 ((operand = sm6_parser_get_value_idx_by_ref(sm6, record, NULL, &operand_idx)) == SIZE_MAX) + return; + + elem_value = &sm6->values[operand]; + is_constant = sm6_value_is_constant(elem_value); + elem_idx = is_constant ? sm6_value_get_constant_uint(elem_value) : 0; + + if (sm6_type_is_pointer(type)) + type = type->u.pointer.type; + else + type = sm6_type_get_element_type_at_index(type, elem_idx); + + /* The first index is always a simple pointer dereference, i.e. zero. */ + if (!type || (!i && (!is_constant || elem_idx))) + { + 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) { @@ -4070,6 +4177,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..bf4b3b46a 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -811,6 +811,7 @@ struct vkd3d_shader_register_index { const struct vkd3d_shader_src_param *rel_addr; unsigned int offset; + bool is_in_bounds; };
struct vkd3d_shader_register