Add 9+7 fast/slow FP inst. impls.; add 14 FP Tests. (#437)
* Update CpuTest.cs * Delete CpuTestSimdCmp.cs Obsolete. * Update CpuTestSimdArithmetic.cs Superseded. * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update AInstEmitSimdArithmetic.cs * Update AInstEmitSimdHelper.cs * Update ASoftFloat.cs * Nit. * Update AOpCodeTable.cs * Update AOptimizations.cs * Update AInstEmitSimdArithmetic.cs * Update ASoftFloat.cs * Update CpuTest.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update AOpCodeTable.cs * Update AInstEmitSimdArithmetic.cs * Update ASoftFloat.cs * Update CpuTestSimdReg.cs * Update AOpCodeTable.cs * Update AInstEmitSimdArithmetic.cs * Update ASoftFloat.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs
This commit is contained in:
parent
0254a84f90
commit
bba9bf97d0
10 changed files with 2471 additions and 1162 deletions
|
@ -178,8 +178,15 @@ namespace Ryujinx.Tests.Cpu
|
|||
return GetThreadState();
|
||||
}
|
||||
|
||||
[Flags]
|
||||
protected enum FPSR
|
||||
/// <summary>Floating-point Control Register.</summary>
|
||||
protected enum FPCR
|
||||
{
|
||||
/// <summary>Default NaN mode control bit.</summary>
|
||||
DN = 25
|
||||
}
|
||||
|
||||
/// <summary>Floating-point Status Register.</summary>
|
||||
[Flags] protected enum FPSR
|
||||
{
|
||||
None = 0,
|
||||
|
||||
|
@ -195,32 +202,43 @@ namespace Ryujinx.Tests.Cpu
|
|||
IXC = 1 << 4,
|
||||
/// <summary>Input Denormal cumulative floating-point exception bit.</summary>
|
||||
IDC = 1 << 7,
|
||||
|
||||
/// <summary>Cumulative saturation bit.</summary>
|
||||
QC = 1 << 27
|
||||
QC = 1 << 27
|
||||
}
|
||||
|
||||
protected enum FpSkips { None, IfNaN_S, IfNaN_D };
|
||||
[Flags] protected enum FpSkips
|
||||
{
|
||||
None = 0,
|
||||
|
||||
protected enum FpUseTolerance { None, OneUlps_S, OneUlps_D };
|
||||
IfNaN_S = 1,
|
||||
IfNaN_D = 2,
|
||||
|
||||
IfUnderflow = 4,
|
||||
IfOverflow = 8
|
||||
}
|
||||
|
||||
protected enum FpTolerances
|
||||
{
|
||||
None,
|
||||
|
||||
UpToOneUlps_S,
|
||||
UpToOneUlps_D
|
||||
}
|
||||
|
||||
protected void CompareAgainstUnicorn(
|
||||
FPSR FpsrMask = FPSR.None,
|
||||
FpSkips FpSkips = FpSkips.None,
|
||||
FpUseTolerance FpUseTolerance = FpUseTolerance.None)
|
||||
FPSR FpsrMask = FPSR.None,
|
||||
FpSkips FpSkips = FpSkips.None,
|
||||
FpTolerances FpTolerances = FpTolerances.None)
|
||||
{
|
||||
if (!UnicornAvailable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FpSkips == FpSkips.IfNaN_S && float.IsNaN(VectorExtractSingle(UnicornEmu.Q[0], (byte)0)))
|
||||
if (FpSkips != FpSkips.None)
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
}
|
||||
|
||||
if (FpSkips == FpSkips.IfNaN_D && double.IsNaN(VectorExtractDouble(UnicornEmu.Q[0], (byte)0)))
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
ManageFpSkips(FpSkips);
|
||||
}
|
||||
|
||||
Assert.That(Thread.ThreadState.X0, Is.EqualTo(UnicornEmu.X[0]));
|
||||
|
@ -257,50 +275,13 @@ namespace Ryujinx.Tests.Cpu
|
|||
|
||||
Assert.That(Thread.ThreadState.X31, Is.EqualTo(UnicornEmu.SP));
|
||||
|
||||
if (FpUseTolerance == FpUseTolerance.None)
|
||||
if (FpTolerances == FpTolerances.None)
|
||||
{
|
||||
Assert.That(Thread.ThreadState.V0, Is.EqualTo(UnicornEmu.Q[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Is.EqualTo(UnicornEmu.Q[0]).ApplyTo(Thread.ThreadState.V0).IsSuccess)
|
||||
{
|
||||
if (FpUseTolerance == FpUseTolerance.OneUlps_S)
|
||||
{
|
||||
if (float.IsNormal (VectorExtractSingle(UnicornEmu.Q[0], (byte)0)) ||
|
||||
float.IsSubnormal(VectorExtractSingle(UnicornEmu.Q[0], (byte)0)))
|
||||
{
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)0),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)0)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)1),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)1)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)2),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)2)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)3),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)3)).Within(1).Ulps);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(Thread.ThreadState.V0, Is.EqualTo(UnicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
|
||||
if (FpUseTolerance == FpUseTolerance.OneUlps_D)
|
||||
{
|
||||
if (double.IsNormal (VectorExtractDouble(UnicornEmu.Q[0], (byte)0)) ||
|
||||
double.IsSubnormal(VectorExtractDouble(UnicornEmu.Q[0], (byte)0)))
|
||||
{
|
||||
Assert.That (VectorExtractDouble(Thread.ThreadState.V0, (byte)0),
|
||||
Is.EqualTo(VectorExtractDouble(UnicornEmu.Q[0], (byte)0)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractDouble(Thread.ThreadState.V0, (byte)1),
|
||||
Is.EqualTo(VectorExtractDouble(UnicornEmu.Q[0], (byte)1)).Within(1).Ulps);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(Thread.ThreadState.V0, Is.EqualTo(UnicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
ManageFpTolerances(FpTolerances);
|
||||
}
|
||||
Assert.That(Thread.ThreadState.V1, Is.EqualTo(UnicornEmu.Q[1]));
|
||||
Assert.That(Thread.ThreadState.V2, Is.EqualTo(UnicornEmu.Q[2]));
|
||||
|
@ -344,6 +325,90 @@ namespace Ryujinx.Tests.Cpu
|
|||
Assert.That(Thread.ThreadState.Negative, Is.EqualTo(UnicornEmu.NegativeFlag));
|
||||
}
|
||||
|
||||
private void ManageFpSkips(FpSkips FpSkips)
|
||||
{
|
||||
if (FpSkips.HasFlag(FpSkips.IfNaN_S))
|
||||
{
|
||||
if (float.IsNaN(VectorExtractSingle(UnicornEmu.Q[0], (byte)0)))
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
}
|
||||
}
|
||||
else if (FpSkips.HasFlag(FpSkips.IfNaN_D))
|
||||
{
|
||||
if (double.IsNaN(VectorExtractDouble(UnicornEmu.Q[0], (byte)0)))
|
||||
{
|
||||
Assert.Ignore("NaN test.");
|
||||
}
|
||||
}
|
||||
|
||||
if (FpSkips.HasFlag(FpSkips.IfUnderflow))
|
||||
{
|
||||
if ((UnicornEmu.Fpsr & (int)FPSR.UFC) != 0)
|
||||
{
|
||||
Assert.Ignore("Underflow test.");
|
||||
}
|
||||
}
|
||||
|
||||
if (FpSkips.HasFlag(FpSkips.IfOverflow))
|
||||
{
|
||||
if ((UnicornEmu.Fpsr & (int)FPSR.OFC) != 0)
|
||||
{
|
||||
Assert.Ignore("Overflow test.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ManageFpTolerances(FpTolerances FpTolerances)
|
||||
{
|
||||
if (!Is.EqualTo(UnicornEmu.Q[0]).ApplyTo(Thread.ThreadState.V0).IsSuccess)
|
||||
{
|
||||
if (FpTolerances == FpTolerances.UpToOneUlps_S)
|
||||
{
|
||||
if (IsNormalOrSubnormal_S(VectorExtractSingle(UnicornEmu.Q[0], (byte)0)) &&
|
||||
IsNormalOrSubnormal_S(VectorExtractSingle(Thread.ThreadState.V0, (byte)0)))
|
||||
{
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)0),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)0)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)1),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)1)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)2),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)2)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractSingle(Thread.ThreadState.V0, (byte)3),
|
||||
Is.EqualTo(VectorExtractSingle(UnicornEmu.Q[0], (byte)3)).Within(1).Ulps);
|
||||
|
||||
Console.WriteLine(FpTolerances);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(Thread.ThreadState.V0, Is.EqualTo(UnicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
|
||||
if (FpTolerances == FpTolerances.UpToOneUlps_D)
|
||||
{
|
||||
if (IsNormalOrSubnormal_D(VectorExtractDouble(UnicornEmu.Q[0], (byte)0)) &&
|
||||
IsNormalOrSubnormal_D(VectorExtractDouble(Thread.ThreadState.V0, (byte)0)))
|
||||
{
|
||||
Assert.That (VectorExtractDouble(Thread.ThreadState.V0, (byte)0),
|
||||
Is.EqualTo(VectorExtractDouble(UnicornEmu.Q[0], (byte)0)).Within(1).Ulps);
|
||||
Assert.That (VectorExtractDouble(Thread.ThreadState.V0, (byte)1),
|
||||
Is.EqualTo(VectorExtractDouble(UnicornEmu.Q[0], (byte)1)).Within(1).Ulps);
|
||||
|
||||
Console.WriteLine(FpTolerances);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.That(Thread.ThreadState.V0, Is.EqualTo(UnicornEmu.Q[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsNormalOrSubnormal_S(float f) => float.IsNormal(f) || float.IsSubnormal(f);
|
||||
|
||||
bool IsNormalOrSubnormal_D(double d) => double.IsNormal(d) || double.IsSubnormal(d);
|
||||
}
|
||||
|
||||
protected static Vector128<float> MakeVectorE0(double E0)
|
||||
{
|
||||
if (!Sse2.IsSupported)
|
||||
|
@ -453,14 +518,14 @@ namespace Ryujinx.Tests.Cpu
|
|||
{
|
||||
uint Rnd;
|
||||
|
||||
do Rnd = TestContext.CurrentContext.Random.NextUInt();
|
||||
while ((Rnd & 0x7F800000u) == 0u ||
|
||||
(Rnd & 0x7F800000u) == 0x7F800000u);
|
||||
do Rnd = TestContext.CurrentContext.Random.NextUInt();
|
||||
while (( Rnd & 0x7F800000u) == 0u ||
|
||||
(~Rnd & 0x7F800000u) == 0u);
|
||||
|
||||
return Rnd;
|
||||
}
|
||||
|
||||
protected static uint GenSubNormal_S()
|
||||
protected static uint GenSubnormal_S()
|
||||
{
|
||||
uint Rnd;
|
||||
|
||||
|
@ -474,14 +539,14 @@ namespace Ryujinx.Tests.Cpu
|
|||
{
|
||||
ulong Rnd;
|
||||
|
||||
do Rnd = TestContext.CurrentContext.Random.NextULong();
|
||||
while ((Rnd & 0x7FF0000000000000ul) == 0ul ||
|
||||
(Rnd & 0x7FF0000000000000ul) == 0x7FF0000000000000ul);
|
||||
do Rnd = TestContext.CurrentContext.Random.NextULong();
|
||||
while (( Rnd & 0x7FF0000000000000ul) == 0ul ||
|
||||
(~Rnd & 0x7FF0000000000000ul) == 0ul);
|
||||
|
||||
return Rnd;
|
||||
}
|
||||
|
||||
protected static ulong GenSubNormal_D()
|
||||
protected static ulong GenSubnormal_D()
|
||||
{
|
||||
ulong Rnd;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue