From 0e6ea2d9d66bc7bd4019ab10324e75e73e96f517 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 3 Nov 2025 20:20:19 +0100 Subject: [PATCH] [shader_recompiler] Add IAbs64 to prevent errors when using I2F with a 64-bit packed CBUF variant (#2918) - Using I2F cbuf variant (packed 32x2 aka. U64) - Code will call IAbs() if some conditions are met (signed + abs bit) - Uh oh we don't have a variant for 64 bits! - Fuck now we just made BAD ir code :( Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2918 Reviewed-by: MaranBr Reviewed-by: Caio Oliveira Co-authored-by: lizzie Co-committed-by: lizzie --- .../backend/glasm/emit_glasm_instructions.h | 4 +++ .../backend/glasm/emit_glasm_integer.cpp | 7 +++++ .../backend/glsl/emit_glsl_instructions.h | 4 +++ .../backend/glsl/emit_glsl_integer.cpp | 5 ++++ .../backend/spirv/emit_spirv_instructions.h | 4 +++ .../backend/spirv/emit_spirv_integer.cpp | 4 +++ .../frontend/ir/ir_emitter.cpp | 11 +++++-- .../frontend/ir/ir_emitter.h | 5 +++- src/shader_recompiler/frontend/ir/opcodes.inc | 1 + .../integer_floating_point_conversion.cpp | 30 +++++++------------ 10 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h index e4cc5e694b..6572db86dc 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h +++ b/src/shader_recompiler/backend/glasm/emit_glasm_instructions.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -313,6 +316,7 @@ void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, ScalarU32 a, ScalarU32 b); void EmitINeg32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value); void EmitINeg64(EmitContext& ctx, IR::Inst& inst, Register value); void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value); +void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, ScalarS32 value); void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, ScalarU32 base, ScalarU32 shift); void EmitShiftLeftLogical64(EmitContext& ctx, IR::Inst& inst, ScalarRegister base, ScalarU32 shift); void EmitShiftRightLogical32(EmitContext& ctx, IR::Inst& inst, ScalarU32 base, ScalarU32 shift); diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp index 528240f44a..a347a3f5ff 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_integer.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -113,6 +116,10 @@ void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) { ctx.Add("ABS.S {},{};", inst, value); } +void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) { + ctx.Add("ABS.S64 {},{};", inst, value); +} + void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, ScalarU32 base, ScalarU32 shift) { ctx.Add("SHL.U {}.x,{},{};", inst, base, shift); } diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h index fb669d399e..d508b84cec 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h +++ b/src/shader_recompiler/backend/glsl/emit_glsl_instructions.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -373,6 +376,7 @@ void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::strin void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value); void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value); void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value); +void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, std::string_view value); void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base, std::string_view shift); void EmitShiftLeftLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base, diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp index 77e644440b..c3f0e504f6 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp @@ -98,6 +98,11 @@ void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) { ctx.AddU32("{}=abs(int({}));", inst, value); } +void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, std::string_view value) { + // TODO: Uhm, are you sure? This may crash on some drivers! + ctx.AddU32("{}=abs(int64_t({}));", inst, value); +} + void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base, std::string_view shift) { ctx.AddU32("{}={}<<{};", inst, base, shift); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 52be1369c2..171977c85c 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -293,6 +296,7 @@ Id EmitUDiv32(EmitContext& ctx, Id a, Id b); Id EmitINeg32(EmitContext& ctx, Id value); Id EmitINeg64(EmitContext& ctx, Id value); Id EmitIAbs32(EmitContext& ctx, Id value); +Id EmitIAbs64(EmitContext& ctx, Id value); Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift); Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift); Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp index 000d193689..7c9a233fb8 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_integer.cpp @@ -94,6 +94,10 @@ Id EmitIAbs32(EmitContext& ctx, Id value) { return ctx.OpSAbs(ctx.U32[1], value); } +Id EmitIAbs64(EmitContext& ctx, Id value) { + return ctx.OpSAbs(ctx.U64, value); +} + Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) { return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift); } diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp index 0d9d05ddb5..171161ffd1 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp +++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp @@ -1190,8 +1190,15 @@ U32U64 IREmitter::INeg(const U32U64& value) { } } -U32 IREmitter::IAbs(const U32& value) { - return Inst(Opcode::IAbs32, value); +U32U64 IREmitter::IAbs(const U32U64& value) { + switch (value.Type()) { + case Type::U32: + return Inst(Opcode::IAbs32, value); + case Type::U64: + return Inst(Opcode::IAbs64, value); + default: + ThrowInvalidType(value.Type()); + } } U32U64 IREmitter::ShiftLeftLogical(const U32U64& base, const U32& shift) { diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h index 48828f3ecc..725eac3951 100644 --- a/src/shader_recompiler/frontend/ir/ir_emitter.h +++ b/src/shader_recompiler/frontend/ir/ir_emitter.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -218,7 +221,7 @@ public: [[nodiscard]] U32 IMul(const U32& a, const U32& b); [[nodiscard]] U32 IDiv(const U32& a, const U32& b, bool is_signed = false); [[nodiscard]] U32U64 INeg(const U32U64& value); - [[nodiscard]] U32 IAbs(const U32& value); + [[nodiscard]] U32U64 IAbs(const U32U64& value); [[nodiscard]] U32U64 ShiftLeftLogical(const U32U64& base, const U32& shift); [[nodiscard]] U32U64 ShiftRightLogical(const U32U64& base, const U32& shift); [[nodiscard]] U32U64 ShiftRightArithmetic(const U32U64& base, const U32& shift); diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc index 4a6da06f66..960009d89e 100644 --- a/src/shader_recompiler/frontend/ir/opcodes.inc +++ b/src/shader_recompiler/frontend/ir/opcodes.inc @@ -296,6 +296,7 @@ OPCODE(UDiv32, U32, U32, OPCODE(INeg32, U32, U32, ) OPCODE(INeg64, U64, U64, ) OPCODE(IAbs32, U32, U32, ) +OPCODE(IAbs64, U64, U64, ) OPCODE(ShiftLeftLogical32, U32, U32, U32, ) OPCODE(ShiftLeftLogical64, U64, U64, U32, ) OPCODE(ShiftRightLogical32, U32, U32, U32, ) diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp index 1f98b073be..9685b7e43e 100644 --- a/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate/impl/integer_floating_point_conversion.cpp @@ -70,32 +70,25 @@ void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) { int src_bitsize{}; switch (i2f.int_format) { case IntFormat::U8: - src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast(i2f.selector) * 8), - v.ir.Imm32(8), is_signed); - if (i2f.abs != 0) { + src = v.ir.BitFieldExtract(src, v.ir.Imm32(u32(i2f.selector) * 8), v.ir.Imm32(8), is_signed); + if (i2f.abs != 0) src = SmallAbs(v, src, 8); - } src_bitsize = 8; break; case IntFormat::U16: - if (i2f.selector == 1 || i2f.selector == 3) { + if (i2f.selector == 1 || i2f.selector == 3) throw NotImplementedException("Invalid U16 selector {}", i2f.selector.Value()); - } - src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast(i2f.selector) * 8), - v.ir.Imm32(16), is_signed); - if (i2f.abs != 0) { + src = v.ir.BitFieldExtract(src, v.ir.Imm32(u32(i2f.selector) * 8), v.ir.Imm32(16), is_signed); + if (i2f.abs != 0) src = SmallAbs(v, src, 16); - } src_bitsize = 16; break; case IntFormat::U32: case IntFormat::U64: - if (i2f.selector != 0) { + if (i2f.selector != 0) throw NotImplementedException("Unexpected selector {}", i2f.selector.Value()); - } - if (i2f.abs != 0 && is_signed) { + if (i2f.abs != 0 && is_signed) src = v.ir.IAbs(src); - } src_bitsize = i2f.int_format == IntFormat::U64 ? 64 : 32; break; } @@ -106,9 +99,7 @@ void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) { .rounding = CastFpRounding(i2f.fp_rounding), .fmz_mode = IR::FmzMode::DontCare, }; - auto value{v.ir.ConvertIToF(static_cast(dst_bitsize), - static_cast(conversion_src_bitsize), is_signed, src, - fp_control)}; + auto value{v.ir.ConvertIToF(size_t(dst_bitsize), size_t(conversion_src_bitsize), is_signed, src, fp_control)}; if (i2f.neg != 0) { if (i2f.abs != 0 || !is_signed) { // We know the value is positive @@ -141,9 +132,8 @@ void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) { throw NotImplementedException("Unaligned destination {}", i2f.dest_reg.Value()); } const IR::Value vector{v.ir.UnpackDouble2x32(value)}; - for (int i = 0; i < 2; ++i) { - v.X(i2f.dest_reg + i, IR::U32{v.ir.CompositeExtract(vector, static_cast(i))}); - } + for (int i = 0; i < 2; ++i) + v.X(i2f.dest_reg + i, IR::U32{v.ir.CompositeExtract(vector, size_t(i))}); break; } default: