From 4799a1f82fbfd12af1e6d7c16717b526ffbc5ba5 Mon Sep 17 00:00:00 2001 From: okidooh <108128670+okidooh@users.noreply.github.com> Date: Mon, 28 Sep 2026 01:59:51 +0200 Subject: [PATCH] test(shader): cover SAshrI64 translation (#914) --- .../Gen5ScalarArithmeticShift64Tests.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/SharpEmu.ShaderCompiler.Tests/Gen5ScalarArithmeticShift64Tests.cs diff --git a/tests/SharpEmu.ShaderCompiler.Tests/Gen5ScalarArithmeticShift64Tests.cs b/tests/SharpEmu.ShaderCompiler.Tests/Gen5ScalarArithmeticShift64Tests.cs new file mode 100644 index 0000000..6c78179 --- /dev/null +++ b/tests/SharpEmu.ShaderCompiler.Tests/Gen5ScalarArithmeticShift64Tests.cs @@ -0,0 +1,67 @@ +// Copyright (C) 2026 SharpEmu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +using System.Buffers.Binary; +using SharpEmu.HLE; +using SharpEmu.ShaderCompiler.Metal; +using SharpEmu.ShaderCompiler.Tests.Resources; +using SharpEmu.ShaderCompiler.Vulkan; +using Xunit; +using static SharpEmu.ShaderCompiler.Tests.Resources.ResourceTestProgram; + +namespace SharpEmu.ShaderCompiler.Tests; + +public sealed class Gen5ScalarArithmeticShift64Tests +{ + [Fact] + public void DecodeGfx10Encoding() + { + var instruction = Decode(0x91880604); + Assert.Equal("SAshrI64", instruction.Opcode); + Assert.Equal(Gen5ShaderEncoding.Sop2, instruction.Encoding); + Assert.Equal(Gen5Operand.Scalar(4), instruction.Sources[0]); + Assert.Equal(Gen5Operand.Scalar(6), instruction.Sources[1]); + Assert.Equal(Gen5Operand.Scalar(8), Assert.Single(instruction.Destinations)); + } + + [Fact] + public void CompilesOnBothBackends() + { + var program = Program( + Sop2(0, "SAshrI64", 8, Gen5Operand.Scalar(4), Gen5Operand.Scalar(6)), + EndProgram(4)); + var (plan, resources, layout) = Prepare(program); + var request = new ShaderCompileRequest(plan, resources, layout) { LocalSizeX = 1, ThreadCountX = 1 }; + + Assert.True(Gen5SpirvTranslator.TryCompileProgram(request, out var spirv, out var spirvError), spirvError); + var inspector = new SpirvModuleInspector(spirv.Spirv); + Assert.Contains((ushort)SpirvOp.ShiftRightArithmetic, inspector.Opcodes); + + Assert.True(Gen5MslTranslator.TryCompileProgram(request, out var metal, out var metalError), metalError); + Assert.Contains("as_type", metal.Source); + Assert.Contains("& 63u", metal.Source); + } + + private static Gen5ShaderInstruction Decode(uint word) + { + var bytes = new byte[8]; + BinaryPrimitives.WriteUInt32LittleEndian(bytes, word); + BinaryPrimitives.WriteUInt32LittleEndian(bytes.AsSpan(4), 0xBF810000); + var context = new CpuContext(new InstructionMemory(bytes), Generation.Gen5); + Assert.True(Gen5ShaderTranslator.TryDecodeProgram(context, 0x1000, out var program, out var error), error); + return program.Instructions[0]; + } + + private sealed class InstructionMemory(byte[] bytes) : ICpuMemory + { + public bool TryRead(ulong address, Span destination) + { + if (address < 0x1000 || destination.Length > bytes.Length || + address - 0x1000 > (ulong)(bytes.Length - destination.Length)) return false; + bytes.AsSpan((int)(address - 0x1000), destination.Length).CopyTo(destination); + return true; + } + + public bool TryWrite(ulong address, ReadOnlySpan source) => false; + } +}