mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-16 00:40:59 +00:00
[AGC] Fix v_fmac_f32 family decoding in Gen5 VOP2 table (#103)
VOP2 opcode 0x2B was mapped to v_ldexp_f32, which is its gfx6/gfx7 assignment. On gfx10-class hardware 0x2B is v_fmac_f32, so any shader using it silently computed ldexp(a, b) instead of dst += a * b. v_ldexp_f32 on gfx10 only exists as VOP3 0x362, which the VOP3 table already maps correctly. Also add the remaining members of the fmac family: - v_fmamk_f32 (0x2C) and v_fmaak_f32 (0x2D), including their mandatory literal dword in instruction sizing and operand construction, reusing the existing v_madmk/v_madak handling. - The VOP3-encoded form of v_fmac_f32 (0x12B), emitted when source modifiers are present. SPIR-V emission reuses the existing v_mac_f32 body (fma with the destination register as addend) and the v_mad/v_fma case group. Opcode assignments verified against LLVM's AMDGPU backend (VOP2Instructions.td): V_FMAC_F32 gfx10 = 0x02b, V_FMAMK_F32 = 0x02c, V_FMAAK_F32 = 0x02d; V_LDEXP_F32 is 0x02b only on gfx6/gfx7 and is VOP3-only 0x362 on gfx10. Decode verified by feeding hand-assembled gfx1013 words through Gen5ShaderTranslator: 0x560A0501 previously decoded as VLdexpF32 and a v_fmamk_f32 program failed with unknown-vop2 op=0x2C; both now decode correctly, and VOP3 0x362 still decodes as VLdexpF32. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -718,7 +718,7 @@ internal static class Gen5ShaderTranslator
|
||||
}
|
||||
|
||||
var src0 = word & 0x1FF;
|
||||
sizeDwords = opcode is 0x20 or 0x21 || src0 is 0xF9 or 0xFA or 0xFF ? 2u : 1u;
|
||||
sizeDwords = opcode is 0x20 or 0x21 or 0x2C or 0x2D || src0 is 0xF9 or 0xFA or 0xFF ? 2u : 1u;
|
||||
error = string.Empty;
|
||||
name = opcode switch
|
||||
{
|
||||
@@ -757,7 +757,9 @@ internal static class Gen5ShaderTranslator
|
||||
0x28 => "VAddcU32",
|
||||
0x29 => "VSubbU32",
|
||||
0x2A => "VSubbrevU32",
|
||||
0x2B => "VLdexpF32",
|
||||
0x2B => "VFmacF32",
|
||||
0x2C => "VFmamkF32",
|
||||
0x2D => "VFmaakF32",
|
||||
0x2F => "VCvtPkrtzF16F32",
|
||||
0x30 => "VCvtPkU16U32",
|
||||
0x31 => "VCvtPkI16I32",
|
||||
@@ -870,6 +872,7 @@ internal static class Gen5ShaderTranslator
|
||||
0x10F => "VMinF32",
|
||||
0x110 => "VMaxF32",
|
||||
0x11F => "VMacF32",
|
||||
0x12B => "VFmacF32",
|
||||
0x12F => "VCvtPkrtzF16F32",
|
||||
0x141 => "VMadF32",
|
||||
0x143 => "VMadU32U24",
|
||||
@@ -1379,7 +1382,7 @@ internal static class Gen5ShaderTranslator
|
||||
Gen5Operand.Source(word & 0x1FF, literal),
|
||||
Gen5Operand.Vector((word >> 9) & 0xFF),
|
||||
];
|
||||
if (opcode == "VMadMkF32" && literal.HasValue)
|
||||
if (opcode is "VMadMkF32" or "VFmamkF32" && literal.HasValue)
|
||||
{
|
||||
sources =
|
||||
[
|
||||
@@ -1388,7 +1391,7 @@ internal static class Gen5ShaderTranslator
|
||||
sources[1],
|
||||
];
|
||||
}
|
||||
else if (opcode == "VMadAkF32" && literal.HasValue)
|
||||
else if (opcode is "VMadAkF32" or "VFmaakF32" && literal.HasValue)
|
||||
{
|
||||
sources =
|
||||
[
|
||||
|
||||
@@ -255,6 +255,8 @@ internal static partial class Gen5SpirvTranslator
|
||||
case "VFmaF32":
|
||||
case "VMadMkF32":
|
||||
case "VMadAkF32":
|
||||
case "VFmamkF32":
|
||||
case "VFmaakF32":
|
||||
result = EmitFloatResult(
|
||||
instruction,
|
||||
Ext(
|
||||
@@ -265,6 +267,7 @@ internal static partial class Gen5SpirvTranslator
|
||||
GetFloatSource(instruction, 2)));
|
||||
break;
|
||||
case "VMacF32":
|
||||
case "VFmacF32":
|
||||
{
|
||||
var addend = Bitcast(_floatType, LoadV(destination));
|
||||
result = EmitFloatResult(
|
||||
|
||||
Reference in New Issue
Block a user