From 79736ae6ffa5095a9ed9b4b8ef95286bccf5e2d0 Mon Sep 17 00:00:00 2001 From: Giovanni Mascellani Date: Wed, 8 Oct 2025 22:26:59 +0200 Subject: [PATCH] vkd3d-shader/ir: Introduce VSIR_OP_NEG to represent floating-point negation. --- libs/vkd3d-shader/dxil.c | 55 +++++++++++++++++++----- libs/vkd3d-shader/ir.c | 4 ++ libs/vkd3d-shader/msl.c | 1 + libs/vkd3d-shader/spirv.c | 2 + libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 07cfd6a1f..c7af58118 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -4511,7 +4511,7 @@ static void sm6_parser_emit_atomicrmw(struct sm6_parser *sm6, const struct dxil_ } static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_type *type_a, - const struct sm6_type *type_b, struct sm6_parser *sm6) + const struct sm6_type *type_b, struct sm6_parser *sm6, enum vkd3d_shader_opcode *aux_opcode) { bool is_int = sm6_type_is_bool_i16_i32_i64(type_a); bool is_double = sm6_type_is_double(type_a); @@ -4534,14 +4534,19 @@ static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_ty "Type mismatch in binary operation arguments."); } + *aux_opcode = VSIR_OP_NOP; + switch (code) { case BINOP_ADD: - case BINOP_SUB: - /* NEG is applied later for subtraction. */ op = is_int ? VSIR_OP_IADD : (is_double ? VSIR_OP_DADD : VSIR_OP_ADD); is_valid = !is_bool; break; + case BINOP_SUB: + op = is_int ? VSIR_OP_IADD : (is_double ? VSIR_OP_DADD : VSIR_OP_ADD); + *aux_opcode = is_int ? VSIR_OP_INEG : VSIR_OP_NEG; + is_valid = !is_bool; + break; case BINOP_AND: op = VSIR_OP_AND; is_valid = is_int; @@ -4603,12 +4608,13 @@ static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_ty } static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_record *record, - struct vkd3d_shader_instruction *ins, struct sm6_value *dst) + struct sm6_block *code_block, struct vkd3d_shader_instruction *ins, struct sm6_value *dst) { + enum vkd3d_shader_opcode opcode, aux_opcode; struct vkd3d_shader_src_param *src_params; - enum vkd3d_shader_opcode opcode; + struct vkd3d_shader_dst_param *dst_params; + uint32_t type_flags = 0, aux_id = 0; const struct sm6_value *a, *b; - uint32_t type_flags = 0; uint64_t code, flags; bool silence_warning; unsigned int i = 0; @@ -4624,9 +4630,28 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco return; code = record->operands[i++]; - if ((opcode = map_binary_op(code, a->type, b->type, sm6)) == VSIR_OP_INVALID) + if ((opcode = map_binary_op(code, a->type, b->type, sm6, &aux_opcode)) == VSIR_OP_INVALID) return; + if (aux_opcode != VSIR_OP_NOP) + { + vsir_instruction_init(ins, &sm6->p.location, aux_opcode); + + if (!(dst_params = instruction_dst_params_alloc(ins, 1, sm6)) + || !(src_params = instruction_src_params_alloc(ins, 1, sm6))) + return; + + aux_id = sm6_parser_alloc_ssa_id(sm6); + + src_param_init_from_value(&src_params[0], b, DXIL_TYPE_SIGNED, sm6); + + dst_param_init(&dst_params[0]); + register_init_with_id(&dst_params[0].reg, VKD3DSPR_SSA, src_params[0].reg.data_type, aux_id); + + ++ins; + ++code_block->instruction_count; + } + vsir_instruction_init(ins, &sm6->p.location, opcode); flags = (record->operand_count > i) ? record->operands[i] : 0; @@ -4676,10 +4701,18 @@ static void sm6_parser_emit_binop(struct sm6_parser *sm6, const struct dxil_reco if (!(src_params = instruction_src_params_alloc(ins, 2, sm6))) return; + src_param_init_from_value(&src_params[0], a, type_flags, sm6); - src_param_init_from_value(&src_params[1], b, type_flags, sm6); - if (code == BINOP_SUB) - src_params[1].modifiers = VKD3DSPSM_NEG; + + if (aux_opcode == VSIR_OP_NOP) + { + src_param_init_from_value(&src_params[1], b, type_flags, sm6); + } + else + { + src_param_init(&src_params[1]); + register_init_with_id(&src_params[1].reg, VKD3DSPR_SSA, src_params[0].reg.data_type, aux_id); + } dst->type = a->type; @@ -8345,7 +8378,7 @@ static enum vkd3d_result sm6_parser_function_init(struct sm6_parser *sm6, const break; } case FUNC_CODE_INST_BINOP: - sm6_parser_emit_binop(sm6, record, ins, dst); + sm6_parser_emit_binop(sm6, record, code_block, ins, dst); break; case FUNC_CODE_INST_BR: sm6_parser_emit_br(sm6, record, function, code_block, ins); diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 1dc691152..fb0734e47 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -299,6 +299,7 @@ const char *vsir_opcode_get_name(enum vkd3d_shader_opcode op, const char *error) [VSIR_OP_MOVC ] = "movc", [VSIR_OP_MSAD ] = "msad", [VSIR_OP_MUL ] = "mul", + [VSIR_OP_NEG ] = "neg", [VSIR_OP_NEO ] = "ne_ord", [VSIR_OP_NEU ] = "ne", [VSIR_OP_NOP ] = "nop", @@ -8732,6 +8733,7 @@ static bool vsir_src_is_masked(enum vkd3d_shader_opcode opcode, unsigned int src case VSIR_OP_MOVC: case VSIR_OP_MSAD: /* FIXME: Is this correct? */ case VSIR_OP_MUL: + case VSIR_OP_NEG: case VSIR_OP_NEO: case VSIR_OP_NEU: case VSIR_OP_NOT: @@ -12813,6 +12815,7 @@ static const struct vsir_validator_instruction_desc vsir_validator_instructions[ [VSIR_OP_MAX] = {1, 2, vsir_validate_float_elementwise_operation}, [VSIR_OP_MIN] = {1, 2, vsir_validate_float_elementwise_operation}, [VSIR_OP_MUL] = {1, 2, vsir_validate_float_elementwise_operation}, + [VSIR_OP_NEG] = {1, 1, vsir_validate_float_or_double_elementwise_operation}, [VSIR_OP_NEO] = {1, 2, vsir_validate_float_comparison_operation}, [VSIR_OP_NEU] = {1, 2, vsir_validate_float_comparison_operation}, [VSIR_OP_NOP] = {0, 0, vsir_validate_nop}, @@ -13232,6 +13235,7 @@ static bool vsir_instruction_has_side_effects(const struct vkd3d_shader_instruct case VSIR_OP_MOVC: case VSIR_OP_MSAD: case VSIR_OP_MUL: + case VSIR_OP_NEG: case VSIR_OP_NEO: case VSIR_OP_NEU: case VSIR_OP_NOP: diff --git a/libs/vkd3d-shader/msl.c b/libs/vkd3d-shader/msl.c index 9b4969a9b..6d89cf43c 100644 --- a/libs/vkd3d-shader/msl.c +++ b/libs/vkd3d-shader/msl.c @@ -1624,6 +1624,7 @@ static void msl_handle_instruction(struct msl_generator *gen, const struct vkd3d msl_relop(gen, ins, "!="); break; case VSIR_OP_INEG: + case VSIR_OP_NEG: msl_unary_op(gen, ins, "-"); break; case VSIR_OP_ITOF: diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index a67299ecb..3bb2ba6bf 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -7548,6 +7548,7 @@ static SpvOp spirv_compiler_map_alu_instruction(const struct vkd3d_shader_instru {VSIR_OP_ITOF, SpvOpConvertSToF}, {VSIR_OP_ITOI, SpvOpSConvert}, {VSIR_OP_MUL, SpvOpFMul}, + {VSIR_OP_NEG, SpvOpFNegate}, {VSIR_OP_NOT, SpvOpNot}, {VSIR_OP_OR, SpvOpBitwiseOr}, {VSIR_OP_UDIV_SIMPLE, SpvOpUDiv}, @@ -10581,6 +10582,7 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VSIR_OP_ITOF: case VSIR_OP_ITOI: case VSIR_OP_MUL: + case VSIR_OP_NEG: case VSIR_OP_NOT: case VSIR_OP_OR: case VSIR_OP_UDIV_SIMPLE: diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 25865e319..8e9db2b09 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -503,6 +503,7 @@ enum vkd3d_shader_opcode VSIR_OP_MOVC, VSIR_OP_MSAD, VSIR_OP_MUL, + VSIR_OP_NEG, VSIR_OP_NEO, VSIR_OP_NEU, VSIR_OP_NOP,