From 1e35b99f74eed1d33b9b52f2bd517a3b40788437 Mon Sep 17 00:00:00 2001 From: Merry Date: Thu, 12 Jul 2018 19:51:02 +0100 Subject: [PATCH] AInstEmitSimdCvt: Half-precision to single-precision conversion (#235) --- Instruction/AInstEmitSimdCvt.cs | 8 ++++---- Instruction/ASoftFloat.cs | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Instruction/AInstEmitSimdCvt.cs b/Instruction/AInstEmitSimdCvt.cs index 98bb972..da58474 100644 --- a/Instruction/AInstEmitSimdCvt.cs +++ b/Instruction/AInstEmitSimdCvt.cs @@ -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) */ { diff --git a/Instruction/ASoftFloat.cs b/Instruction/ASoftFloat.cs index e63c82b..27f4f7f 100644 --- a/Instruction/ASoftFloat.cs +++ b/Instruction/ASoftFloat.cs @@ -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))); + } } } \ No newline at end of file