mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-31 06:59:45 +08:00
444af50f4b
* [shader] add scalar control flow graph Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [shader] add scalar control flow graph * [shader] add gen5 branch resolver Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [shader] add gen5 branch resolver * [shader] add scalar reaching definitions Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [shader] add scalar reaching definitions * [shader] add cfg and dataflow tests Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [shader] add cfg and dataflow tests * [shader] guard descriptors from unresolved registers Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * [shader] guard descriptors from unresolved registers --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
91 lines
3.0 KiB
C#
91 lines
3.0 KiB
C#
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
using System.Collections.Generic;
|
|
using SharpEmu.ShaderCompiler;
|
|
using SharpEmu.ShaderCompiler.Ir;
|
|
using Xunit;
|
|
|
|
namespace SharpEmu.ShaderCompiler.Tests;
|
|
|
|
public sealed class Gen5ImplicitVccTests
|
|
{
|
|
private static Gen5ShaderInstruction Vopc(uint pc, string opcode = "VCmpEqU32") =>
|
|
new(pc, Gen5ShaderEncoding.Vopc, opcode, [0u], [], [], null);
|
|
|
|
private static Gen5ShaderInstruction Vop2(uint pc, string opcode) =>
|
|
new(pc, Gen5ShaderEncoding.Vop2, opcode, [0u], [], [Gen5Operand.Vector(0)], null);
|
|
|
|
private static Gen5ShaderInstruction Nop(uint pc) =>
|
|
new(pc, Gen5ShaderEncoding.Sop1, "SNop", [0u], [], [], null);
|
|
|
|
[Fact]
|
|
public void VopcIsRecognisedAsAnImplicitVccWriter()
|
|
{
|
|
Assert.True(Gen5ScalarSsa.WritesVccImplicitly(Vopc(0)));
|
|
Assert.True(Gen5ScalarSsa.WritesVccImplicitly(Vopc(0, "VCmpLtF32")));
|
|
}
|
|
|
|
[Fact]
|
|
public void Vop2CarryFormsAreRecognised()
|
|
{
|
|
Assert.True(Gen5ScalarSsa.WritesVccImplicitly(Vop2(0, "VAddCoCiU32")));
|
|
Assert.True(Gen5ScalarSsa.WritesVccImplicitly(Vop2(0, "VSubCoCiU32")));
|
|
Assert.True(Gen5ScalarSsa.WritesVccImplicitly(Vop2(0, "VSubrevCoCiU32")));
|
|
}
|
|
|
|
[Fact]
|
|
public void PlainVop2DoesNotWriteVcc()
|
|
{
|
|
Assert.False(Gen5ScalarSsa.WritesVccImplicitly(Vop2(0, "VAddF32")));
|
|
Assert.False(Gen5ScalarSsa.WritesVccImplicitly(Nop(0)));
|
|
}
|
|
|
|
[Fact]
|
|
public void VopcDefinesBothVccHalves()
|
|
{
|
|
List<Gen5ShaderInstruction> program = [Vopc(0), Nop(4)];
|
|
|
|
var ssa = Gen5ScalarSsa.Build(program, userData: []);
|
|
|
|
var low = ssa.GetReachingDefinitionAt(4, Gen5ScalarSsa.VccLo);
|
|
var high = ssa.GetReachingDefinitionAt(4, Gen5ScalarSsa.VccHi);
|
|
|
|
Assert.Equal(IrReachingState.Single, low.State);
|
|
Assert.Equal(0u, low.DefinitionPc);
|
|
Assert.Equal(IrReachingState.Single, high.State);
|
|
Assert.Equal(0u, high.DefinitionPc);
|
|
}
|
|
|
|
[Fact]
|
|
public void WithoutTheImplicitWriteVccWouldLookUndefined()
|
|
{
|
|
// The regression this models: before implicit VCC was tracked the offset
|
|
// register reported "none" and its stale value was used as a byte offset.
|
|
List<Gen5ShaderInstruction> program = [Nop(0), Nop(4)];
|
|
|
|
var ssa = Gen5ScalarSsa.Build(program, userData: []);
|
|
|
|
Assert.Equal(IrReachingState.None, ssa.GetReachingDefinitionAt(4, Gen5ScalarSsa.VccLo).State);
|
|
}
|
|
|
|
[Fact]
|
|
public void VccWrittenOnBothBranchesBecomesMultiple()
|
|
{
|
|
List<Gen5ShaderInstruction> program =
|
|
[
|
|
new(0, Gen5ShaderEncoding.Sopp, "SCbranchScc0", [2u], [], [], null),
|
|
Vopc(4),
|
|
new(8, Gen5ShaderEncoding.Sopp, "SBranch", [1u], [], [], null),
|
|
Vopc(12),
|
|
Nop(16),
|
|
];
|
|
|
|
var ssa = Gen5ScalarSsa.Build(program, userData: []);
|
|
|
|
Assert.Equal(
|
|
IrReachingState.Multiple,
|
|
ssa.GetReachingDefinitionAt(16, Gen5ScalarSsa.VccLo).State);
|
|
}
|
|
}
|