From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 117 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 0787ee139..5ea60929b 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2875,14 +2875,123 @@ static enum vkd3d_result value_allocate_constant_array(struct sm6_value *dst, co return VKD3D_OK; }
+static enum vkd3d_result sm6_parser_init_constexpr_gep(struct sm6_parser *sm6, const struct dxil_record *record, + struct sm6_value *dst) +{ + const struct sm6_type *elem_type, *pointee_type, *gep_type, *ptr_type; + unsigned int i, j, operand_count, offset; + struct sm6_value *operands[3]; + uint64_t value; + + i = 0; + pointee_type = (record->operand_count & 1) ? sm6_parser_get_type(sm6, record->operands[i++]) : NULL; + + if (!dxil_record_validate_operand_count(record, i + 6, i + 6, sm6)) + return VKD3D_ERROR_INVALID_SHADER; + operand_count = min(record->operand_count, i + 6); + + for (j = 0; i < operand_count; i += 2, ++j) + { + if (!(elem_type = sm6_parser_get_type(sm6, record->operands[i]))) + return VKD3D_ERROR_INVALID_SHADER; + + if ((value = record->operands[i + 1]) >= sm6->cur_max_value) + { + WARN("Invalid value index %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value index %"PRIu64".", value); + return VKD3D_ERROR_INVALID_SHADER; + } + else if (value == sm6->value_count) + { + WARN("Invalid value self-reference at %"PRIu64".\n", value); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Invalid value self-reference for a constexpr GEP."); + return VKD3D_ERROR_INVALID_SHADER; + } + + operands[j] = &sm6->values[value]; + if (value > sm6->value_count) + { + operands[j]->type = elem_type; + } + else if (operands[j]->type != elem_type) + { + WARN("Type mismatch.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Type mismatch in constexpr GEP elements."); + } + } + + if (!sm6_value_is_constant_zero(operands[1])) + { + WARN("Expected constant zero.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "The pointer dereference index for a constexpr GEP instruction is not constant zero."); + return VKD3D_ERROR_INVALID_SHADER; + } + if (!sm6_value_is_constant(operands[2]) || !sm6_type_is_integer(operands[2]->type)) + { + WARN("Element index is not constant int.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "A constexpr GEP element index is not a constant integer."); + return VKD3D_ERROR_INVALID_SHADER; + } + + dst->structure_stride = operands[0]->structure_stride; + + ptr_type = operands[0]->type; + if (!sm6_type_is_pointer(ptr_type)) + { + WARN("Constexpr GEP base value is not a pointer.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "A constexpr GEP base value is not a pointer."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!pointee_type) + { + pointee_type = ptr_type->u.pointer.type; + } + else if (pointee_type != ptr_type->u.pointer.type) + { + WARN("Explicit pointee type mismatch.\n"); + vkd3d_shader_parser_warning(&sm6->p, VKD3D_SHADER_WARNING_DXIL_TYPE_MISMATCH, + "Explicit pointee type for constexpr GEP does not match the element type."); + } + + offset = sm6_value_get_constant_uint(operands[2]); + if (!(gep_type = sm6_type_get_element_type_at_index(pointee_type, offset))) + { + WARN("Failed to get element type.\n"); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND, + "Failed to get the element type of a constexpr GEP."); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (!(dst->type = sm6_type_get_pointer_to_type(gep_type, ptr_type->u.pointer.addr_space, sm6))) + { + WARN("Failed to get pointer type for type %u.\n", gep_type->class); + vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE, + "Module does not define a pointer type for a constexpr GEP result."); + return VKD3D_ERROR_INVALID_SHADER; + } + dst->u.reg = operands[0]->u.reg; + dst->u.reg.idx[1].offset = offset; + dst->u.reg.idx[1].is_in_bounds = record->code == CST_CODE_CE_INBOUNDS_GEP; + dst->u.reg.idx_count = 2; + + return VKD3D_OK; +} + static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) { enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; const struct sm6_type *type, *elem_type; enum vkd3d_data_type reg_data_type; const struct dxil_record *record; - enum vkd3d_result ret; struct sm6_value *dst; + enum vkd3d_result ret; size_t i, value_idx; uint64_t value;
@@ -2995,6 +3104,12 @@ static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const
break;
+ case CST_CODE_CE_GEP: + case CST_CODE_CE_INBOUNDS_GEP: + if ((ret = sm6_parser_init_constexpr_gep(sm6, record, dst)) < 0) + return ret; + break; + case CST_CODE_UNDEF: dxil_record_validate_operand_max_count(record, 0, sm6); dst->u.reg.type = VKD3DSPR_UNDEF;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 46130244c..611d7695f 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -4419,11 +4419,11 @@ static void spirv_compiler_emit_store_dst_components(struct spirv_compiler *comp { unsigned int component_count = vsir_write_mask_component_count(dst->write_mask); struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t type_id, val_id; + uint32_t type_id, dst_type_id, val_id;
+ type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count); if (component_count > 1) { - type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count); val_id = vkd3d_spirv_build_op_composite_construct(builder, type_id, component_ids, component_count); } @@ -4431,6 +4431,11 @@ static void spirv_compiler_emit_store_dst_components(struct spirv_compiler *comp { val_id = *component_ids; } + + dst_type_id = vkd3d_spirv_get_type_id_for_data_type(builder, dst->reg.data_type, component_count); + if (dst_type_id != type_id) + val_id = vkd3d_spirv_build_op_bitcast(builder, dst_type_id, val_id); + spirv_compiler_emit_store_dst(compiler, dst, val_id); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 7 ++++--- tests/hlsl/tgsm.shader_test | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 611d7695f..5ab1fcfd2 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -8900,8 +8900,8 @@ static void spirv_compiler_emit_store_tgsm(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst = instruction->dst; const struct vkd3d_shader_src_param *src = instruction->src; uint32_t base_coordinate_id, component_idx; - const struct vkd3d_shader_src_param *data; struct vkd3d_shader_register_info reg_info; + struct vkd3d_shader_src_param data; unsigned int component_count;
if (!spirv_compiler_get_register_info(compiler, &dst->reg, ®_info)) @@ -8913,8 +8913,9 @@ static void spirv_compiler_emit_store_tgsm(struct spirv_compiler *compiler, base_coordinate_id = spirv_compiler_emit_raw_structured_addressing(compiler, type_id, reg_info.structure_stride, &src[0], VKD3DSP_WRITEMASK_0, &src[1], VKD3DSP_WRITEMASK_0);
- data = &src[instruction->src_count - 1]; - val_id = spirv_compiler_emit_load_src(compiler, data, dst->write_mask); + data = src[instruction->src_count - 1]; + data.reg.data_type = VKD3D_DATA_UINT; + val_id = spirv_compiler_emit_load_src(compiler, &data, dst->write_mask);
component_count = vsir_write_mask_component_count(dst->write_mask); for (component_idx = 0; component_idx < component_count; ++component_idx) diff --git a/tests/hlsl/tgsm.shader_test b/tests/hlsl/tgsm.shader_test index e6b1a6858..4e0c7a49e 100644 --- a/tests/hlsl/tgsm.shader_test +++ b/tests/hlsl/tgsm.shader_test @@ -116,7 +116,7 @@ void main(uint local_idx : SV_GroupIndex, uint group_id : SV_GroupID,
[test] uniform 0 uint 1 -todo dispatch 2 1 1 +todo(sm<6) dispatch 2 1 1 probe uav 1 (0) r (0.0) probe uav 1 (1) r (0.0) probe uav 1 (2) r (0.0)
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
- dst->u.reg.idx[1].offset = offset;
- dst->u.reg.idx[1].is_in_bounds = record->code == CST_CODE_CE_INBOUNDS_GEP;
- dst->u.reg.idx_count = 2;
- return VKD3D_OK;
+}
static enum vkd3d_result sm6_parser_constants_init(struct sm6_parser *sm6, const struct dxil_block *block) { enum vkd3d_shader_register_type reg_type = VKD3DSPR_INVALID; const struct sm6_type *type, *elem_type; enum vkd3d_data_type reg_data_type; const struct dxil_record *record;
- enum vkd3d_result ret; struct sm6_value *dst;
- enum vkd3d_result ret;
Minor, but is this useful?
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
}
+static enum vkd3d_result sm6_parser_init_constexpr_gep(struct sm6_parser *sm6, const struct dxil_record *record,
struct sm6_value *dst)
+{
- const struct sm6_type *elem_type, *pointee_type, *gep_type, *ptr_type;
- unsigned int i, j, operand_count, offset;
- struct sm6_value *operands[3];
- uint64_t value;
- i = 0;
- pointee_type = (record->operand_count & 1) ? sm6_parser_get_type(sm6, record->operands[i++]) : NULL;
- if (!dxil_record_validate_operand_count(record, i + 6, i + 6, sm6))
return VKD3D_ERROR_INVALID_SHADER;
- operand_count = min(record->operand_count, i + 6);
Haven't we just validated that `record->operand_count` is not smaller than `i + 6`? So this `min()` is always `i + 6`.
Giovanni Mascellani (@giomasce) commented about libs/vkd3d-shader/dxil.c:
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_OPERAND,
"Failed to get the element type of a constexpr GEP.");
return VKD3D_ERROR_INVALID_SHADER;
- }
- if (!(dst->type = sm6_type_get_pointer_to_type(gep_type, ptr_type->u.pointer.addr_space, sm6)))
- {
WARN("Failed to get pointer type for type %u.\n", gep_type->class);
vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_INVALID_MODULE,
"Module does not define a pointer type for a constexpr GEP result.");
return VKD3D_ERROR_INVALID_SHADER;
- }
- dst->u.reg = operands[0]->u.reg;
- dst->u.reg.idx[1].offset = offset;
- dst->u.reg.idx[1].is_in_bounds = record->code == CST_CODE_CE_INBOUNDS_GEP;
- dst->u.reg.idx_count = 2;
For the "regular" GEP you ensure that the base pointer doesn't already have two indices. Wouldn't the same check make sense here?