From 823a8724de368cff0b599258cfb77f17fd2d7ba5 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Tue, 10 Jun 2025 19:20:12 +0200 Subject: [PATCH] vkd3d-shader/ir: Introduce VSIR_OP_IREM. It is meant to compute the signed integer remainder. --- libs/vkd3d-shader/dxil.c | 3 +- libs/vkd3d-shader/ir.c | 2 ++ libs/vkd3d-shader/spirv.c | 37 ++++++++++++++++++++++-- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index e8fbb18d9..2b939ebc3 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -4528,7 +4528,7 @@ static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_ty is_valid = !is_bool; break; case BINOP_SREM: - op = is_int ? VSIR_OP_IDIV : VSIR_OP_FREM; + op = is_int ? VSIR_OP_IREM : VSIR_OP_FREM; is_valid = !is_bool; break; case BINOP_SHL: @@ -4611,6 +4611,7 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco case VSIR_OP_USHR: case VSIR_OP_IDIV: case VSIR_OP_UDIV: + case VSIR_OP_IREM: silence_warning = !(flags & ~PEB_EXACT); break; default: diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index f238531f3..23b3ac7dc 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -211,6 +211,7 @@ const char *vsir_opcode_get_name(enum vkd3d_shader_opcode op, const char *error) [VSIR_OP_IMUL_LOW ] = "imul_low", [VSIR_OP_INE ] = "ine", [VSIR_OP_INEG ] = "ineg", + [VSIR_OP_IREM ] = "irem", [VSIR_OP_ISFINITE ] = "isfinite", [VSIR_OP_ISHL ] = "ishl", [VSIR_OP_ISHR ] = "ishr", @@ -7876,6 +7877,7 @@ static bool vsir_src_is_masked(enum vkd3d_shader_opcode opcode, unsigned int src case VSIR_OP_IMUL_LOW: case VSIR_OP_INE: case VSIR_OP_INEG: + case VSIR_OP_IREM: case VSIR_OP_ISFINITE: case VSIR_OP_ISHL: case VSIR_OP_ISHR: diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 3f5ef27e5..09b13b090 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -7536,6 +7536,7 @@ static SpvOp spirv_compiler_map_alu_instruction(const struct vkd3d_shader_instru {VSIR_OP_IADD, SpvOpIAdd}, {VSIR_OP_IMUL_LOW, SpvOpIMul}, {VSIR_OP_INEG, SpvOpSNegate}, + {VSIR_OP_IREM, SpvOpSRem}, {VSIR_OP_ISHL, SpvOpShiftLeftLogical}, {VSIR_OP_ISHR, SpvOpShiftRightArithmetic}, {VSIR_OP_ISINF, SpvOpIsInf}, @@ -7618,13 +7619,14 @@ static void spirv_compiler_emit_bool_cast(struct spirv_compiler *compiler, static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { + uint32_t src_ids[SPIRV_MAX_SRC_COUNT], condition_id = 0, uint_max_id = 0; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_dst_param *dst = instruction->dst; const struct vkd3d_shader_src_param *src = instruction->src; - uint32_t src_ids[SPIRV_MAX_SRC_COUNT]; + unsigned int i, component_count; uint32_t type_id, val_id; SpvOp op = SpvOpMax; - unsigned int i; + bool check_zero; if (src->reg.data_type == VKD3D_DATA_UINT64 && instruction->opcode == VSIR_OP_COUNTBITS) { @@ -7664,14 +7666,41 @@ static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compil return VKD3D_ERROR_INVALID_SHADER; } + /* SPIR-V doesn't mandate a behaviour when a denominator is zero, + * so we have an explicit check. */ + switch (instruction->opcode) + { + case VSIR_OP_IREM: + check_zero = true; + break; + + default: + check_zero = false; + break; + } + VKD3D_ASSERT(instruction->dst_count == 1); VKD3D_ASSERT(instruction->src_count <= SPIRV_MAX_SRC_COUNT); + if (check_zero) + VKD3D_ASSERT(instruction->src_count == 2); + component_count = vsir_write_mask_component_count(dst[0].write_mask); type_id = spirv_compiler_get_type_id_for_dst(compiler, dst); for (i = 0; i < instruction->src_count; ++i) src_ids[i] = spirv_compiler_emit_load_src(compiler, &src[i], dst->write_mask); + if (check_zero) + { + condition_id = spirv_compiler_emit_int_to_bool(compiler, + VKD3D_SHADER_CONDITIONAL_OP_NZ, src[1].reg.data_type, component_count, src_ids[1]); + + if (dst[0].reg.data_type == VKD3D_DATA_UINT64) + uint_max_id = spirv_compiler_get_constant_uint64_vector(compiler, UINT64_MAX, component_count); + else + uint_max_id = spirv_compiler_get_constant_uint_vector(compiler, UINT_MAX, component_count); + } + /* The SPIR-V specification states, "The resulting value is undefined if * Shift is greater than or equal to the bit width of the components of * Base." Direct3D applies only the lowest 5 bits of the shift. @@ -7692,6 +7721,9 @@ static enum vkd3d_result spirv_compiler_emit_alu_instruction(struct spirv_compil if (instruction->flags & VKD3DSI_PRECISE_XYZW) vkd3d_spirv_build_op_decorate(builder, val_id, SpvDecorationNoContraction, NULL, 0); + if (check_zero) + val_id = vkd3d_spirv_build_op_select(builder, type_id, condition_id, val_id, uint_max_id); + spirv_compiler_emit_store_dst(compiler, dst, val_id); return VKD3D_OK; } @@ -10650,6 +10682,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VSIR_OP_IADD: case VSIR_OP_IMUL_LOW: case VSIR_OP_INEG: + case VSIR_OP_IREM: case VSIR_OP_ISHL: case VSIR_OP_ISHR: case VSIR_OP_ISINF: diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index b57032eab..ccad9d558 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -459,6 +459,7 @@ enum vkd3d_shader_opcode VSIR_OP_IMUL_LOW, VSIR_OP_INE, VSIR_OP_INEG, + VSIR_OP_IREM, VSIR_OP_ISFINITE, VSIR_OP_ISHL, VSIR_OP_ISHR,