mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-12-23 07:05:29 +00:00
AInstEmitSimdCvt: Half-precision to single-precision conversion (#235)
This commit is contained in:
parent
cd18ab29df
commit
b233ae964f
|
@ -45,10 +45,10 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (SizeF == 0)
|
||||
{
|
||||
//TODO: This need the half precision floating point type,
|
||||
//that is not yet supported on .NET. We should probably
|
||||
//do our own implementation on the meantime.
|
||||
throw new NotImplementedException();
|
||||
EmitVectorExtractZx(Context, Op.Rn, Part + Index, 1);
|
||||
Context.Emit(OpCodes.Conv_U2);
|
||||
|
||||
Context.EmitCall(typeof(ASoftFloat), nameof(ASoftFloat.ConvertHalfToSingle));
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
|
|
|
@ -225,5 +225,41 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
return 2.0 + op1 * op2;
|
||||
}
|
||||
|
||||
public static float ConvertHalfToSingle(ushort x)
|
||||
{
|
||||
uint x_sign = (uint)(x >> 15) & 0x0001;
|
||||
uint x_exp = (uint)(x >> 10) & 0x001F;
|
||||
uint x_mantissa = (uint)x & 0x03FF;
|
||||
|
||||
if (x_exp == 0 && x_mantissa == 0)
|
||||
{
|
||||
// Zero
|
||||
return BitConverter.Int32BitsToSingle((int)(x_sign << 31));
|
||||
}
|
||||
|
||||
if (x_exp == 0x1F)
|
||||
{
|
||||
// NaN or Infinity
|
||||
return BitConverter.Int32BitsToSingle((int)((x_sign << 31) | 0x7F800000 | (x_mantissa << 13)));
|
||||
}
|
||||
|
||||
int exponent = (int)x_exp - 15;
|
||||
|
||||
if (x_exp == 0)
|
||||
{
|
||||
// Denormal
|
||||
x_mantissa <<= 1;
|
||||
while ((x_mantissa & 0x0400) == 0)
|
||||
{
|
||||
x_mantissa <<= 1;
|
||||
exponent--;
|
||||
}
|
||||
x_mantissa &= 0x03FF;
|
||||
}
|
||||
|
||||
uint new_exp = (uint)((exponent + 127) & 0xFF) << 23;
|
||||
return BitConverter.Int32BitsToSingle((int)((x_sign << 31) | new_exp | (x_mantissa << 13)));
|
||||
}
|
||||
}
|
||||
}
|
40
Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs
Normal file
40
Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using ChocolArm64.State;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
public class CpuTestSimdCvt : CpuTest
|
||||
{
|
||||
[TestCase((ushort)0x0000, 0x00000000u)] // Positive Zero
|
||||
[TestCase((ushort)0x8000, 0x80000000u)] // Negative Zero
|
||||
[TestCase((ushort)0x3E00, 0x3FC00000u)] // +1.5
|
||||
[TestCase((ushort)0xBE00, 0xBFC00000u)] // -1.5
|
||||
[TestCase((ushort)0xFFFF, 0xFFFFE000u)] // -QNaN
|
||||
[TestCase((ushort)0x7C00, 0x7F800000u)] // +Inf
|
||||
[TestCase((ushort)0x3C00, 0x3F800000u)] // 1.0
|
||||
[TestCase((ushort)0x3C01, 0x3F802000u)] // 1.0009765625
|
||||
[TestCase((ushort)0xC000, 0xC0000000u)] // -2.0
|
||||
[TestCase((ushort)0x7BFF, 0x477FE000u)] // 65504.0 (Largest Normal)
|
||||
[TestCase((ushort)0x03FF, 0x387FC000u)] // 0.00006097555 (Largest Subnormal)
|
||||
[TestCase((ushort)0x0001, 0x33800000u)] // 5.96046448e-8 (Smallest Subnormal)
|
||||
public void Fcvtl_V_f16(ushort Value, uint Result)
|
||||
{
|
||||
uint Opcode = 0x0E217801;
|
||||
Vector128<float> V0 = Sse.StaticCast<ushort, float>(Sse2.SetAllVector128(Value));
|
||||
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)0), Is.EqualTo(Result));
|
||||
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)1), Is.EqualTo(Result));
|
||||
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)2), Is.EqualTo(Result));
|
||||
Assert.That(Sse41.Extract(Sse.StaticCast<float, uint>(ThreadState.V1), (byte)3), Is.EqualTo(Result));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue