| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- using ChocolArm64.State;
- using ChocolArm64.Translation;
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.Intrinsics;
- using System.Runtime.Intrinsics.X86;
- namespace ChocolArm64.Instructions
- {
- static class VectorHelper
- {
- public static void EmitCall(ILEmitterCtx context, string name64, string name128)
- {
- bool isSimd64 = context.CurrOp.RegisterSize == RegisterSize.Simd64;
- context.EmitCall(typeof(VectorHelper), isSimd64 ? name64 : name128);
- }
- public static void EmitCall(ILEmitterCtx context, string mthdName)
- {
- context.EmitCall(typeof(VectorHelper), mthdName);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int SatF32ToS32(float value)
- {
- if (float.IsNaN(value)) return 0;
- return value >= int.MaxValue ? int.MaxValue :
- value <= int.MinValue ? int.MinValue : (int)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long SatF32ToS64(float value)
- {
- if (float.IsNaN(value)) return 0;
- return value >= long.MaxValue ? long.MaxValue :
- value <= long.MinValue ? long.MinValue : (long)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint SatF32ToU32(float value)
- {
- if (float.IsNaN(value)) return 0;
- return value >= uint.MaxValue ? uint.MaxValue :
- value <= uint.MinValue ? uint.MinValue : (uint)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong SatF32ToU64(float value)
- {
- if (float.IsNaN(value)) return 0;
- return value >= ulong.MaxValue ? ulong.MaxValue :
- value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int SatF64ToS32(double value)
- {
- if (double.IsNaN(value)) return 0;
- return value >= int.MaxValue ? int.MaxValue :
- value <= int.MinValue ? int.MinValue : (int)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long SatF64ToS64(double value)
- {
- if (double.IsNaN(value)) return 0;
- return value >= long.MaxValue ? long.MaxValue :
- value <= long.MinValue ? long.MinValue : (long)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint SatF64ToU32(double value)
- {
- if (double.IsNaN(value)) return 0;
- return value >= uint.MaxValue ? uint.MaxValue :
- value <= uint.MinValue ? uint.MinValue : (uint)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong SatF64ToU64(double value)
- {
- if (double.IsNaN(value)) return 0;
- return value >= ulong.MaxValue ? ulong.MaxValue :
- value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double Round(double value, CpuThreadState state)
- {
- RoundMode roundMode = state.FPRoundingMode();
- if (roundMode == RoundMode.ToNearest)
- {
- return Math.Round(value); // even
- }
- else if (roundMode == RoundMode.TowardsPlusInfinity)
- {
- return Math.Ceiling(value);
- }
- else if (roundMode == RoundMode.TowardsMinusInfinity)
- {
- return Math.Floor(value);
- }
- else /* if (roundMode == RoundMode.TowardsZero) */
- {
- return Math.Truncate(value);
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static float RoundF(float value, CpuThreadState state)
- {
- RoundMode roundMode = state.FPRoundingMode();
- if (roundMode == RoundMode.ToNearest)
- {
- return MathF.Round(value); // even
- }
- else if (roundMode == RoundMode.TowardsPlusInfinity)
- {
- return MathF.Ceiling(value);
- }
- else if (roundMode == RoundMode.TowardsMinusInfinity)
- {
- return MathF.Floor(value);
- }
- else /* if (roundMode == RoundMode.TowardsZero) */
- {
- return MathF.Truncate(value);
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<double> Sse41ScalarRound(Vector128<double> upper, Vector128<double> value, CpuThreadState state)
- {
- if (!Sse41.IsSupported)
- {
- throw new PlatformNotSupportedException();
- }
- RoundMode roundMode = state.FPRoundingMode();
- if (roundMode == RoundMode.ToNearest)
- {
- return Sse41.RoundToNearestIntegerScalar(upper, value); // even
- }
- else if (roundMode == RoundMode.TowardsPlusInfinity)
- {
- return Sse41.RoundToPositiveInfinityScalar(upper, value);
- }
- else if (roundMode == RoundMode.TowardsMinusInfinity)
- {
- return Sse41.RoundToNegativeInfinityScalar(upper, value);
- }
- else /* if (roundMode == RoundMode.TowardsZero) */
- {
- return Sse41.RoundToZeroScalar(upper, value);
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<float> Sse41ScalarRoundF(Vector128<float> upper, Vector128<float> value, CpuThreadState state)
- {
- if (!Sse41.IsSupported)
- {
- throw new PlatformNotSupportedException();
- }
- RoundMode roundMode = state.FPRoundingMode();
- if (roundMode == RoundMode.ToNearest)
- {
- return Sse41.RoundToNearestIntegerScalar(upper, value); // even
- }
- else if (roundMode == RoundMode.TowardsPlusInfinity)
- {
- return Sse41.RoundToPositiveInfinityScalar(upper, value);
- }
- else if (roundMode == RoundMode.TowardsMinusInfinity)
- {
- return Sse41.RoundToNegativeInfinityScalar(upper, value);
- }
- else /* if (roundMode == RoundMode.TowardsZero) */
- {
- return Sse41.RoundToZeroScalar(upper, value);
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<double> Sse41VectorRound(Vector128<double> value, CpuThreadState state)
- {
- if (!Sse41.IsSupported)
- {
- throw new PlatformNotSupportedException();
- }
- RoundMode roundMode = state.FPRoundingMode();
- if (roundMode == RoundMode.ToNearest)
- {
- return Sse41.RoundToNearestInteger(value); // even
- }
- else if (roundMode == RoundMode.TowardsPlusInfinity)
- {
- return Sse41.RoundToPositiveInfinity(value);
- }
- else if (roundMode == RoundMode.TowardsMinusInfinity)
- {
- return Sse41.RoundToNegativeInfinity(value);
- }
- else /* if (roundMode == RoundMode.TowardsZero) */
- {
- return Sse41.RoundToZero(value);
- }
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<float> Sse41VectorRoundF(Vector128<float> value, CpuThreadState state)
- {
- if (!Sse41.IsSupported)
- {
- throw new PlatformNotSupportedException();
- }
- RoundMode roundMode = state.FPRoundingMode();
- if (roundMode == RoundMode.ToNearest)
- {
- return Sse41.RoundToNearestInteger(value); // even
- }
- else if (roundMode == RoundMode.TowardsPlusInfinity)
- {
- return Sse41.RoundToPositiveInfinity(value);
- }
- else if (roundMode == RoundMode.TowardsMinusInfinity)
- {
- return Sse41.RoundToNegativeInfinity(value);
- }
- else /* if (roundMode == RoundMode.TowardsZero) */
- {
- return Sse41.RoundToZero(value);
- }
- }
- public static Vector128<float> Tbl1_V64(
- Vector128<float> vector,
- Vector128<float> tb0)
- {
- return Tbl(vector, 8, tb0);
- }
- public static Vector128<float> Tbl1_V128(
- Vector128<float> vector,
- Vector128<float> tb0)
- {
- return Tbl(vector, 16, tb0);
- }
- public static Vector128<float> Tbl2_V64(
- Vector128<float> vector,
- Vector128<float> tb0,
- Vector128<float> tb1)
- {
- return Tbl(vector, 8, tb0, tb1);
- }
- public static Vector128<float> Tbl2_V128(
- Vector128<float> vector,
- Vector128<float> tb0,
- Vector128<float> tb1)
- {
- return Tbl(vector, 16, tb0, tb1);
- }
- public static Vector128<float> Tbl3_V64(
- Vector128<float> vector,
- Vector128<float> tb0,
- Vector128<float> tb1,
- Vector128<float> tb2)
- {
- return Tbl(vector, 8, tb0, tb1, tb2);
- }
- public static Vector128<float> Tbl3_V128(
- Vector128<float> vector,
- Vector128<float> tb0,
- Vector128<float> tb1,
- Vector128<float> tb2)
- {
- return Tbl(vector, 16, tb0, tb1, tb2);
- }
- public static Vector128<float> Tbl4_V64(
- Vector128<float> vector,
- Vector128<float> tb0,
- Vector128<float> tb1,
- Vector128<float> tb2,
- Vector128<float> tb3)
- {
- return Tbl(vector, 8, tb0, tb1, tb2, tb3);
- }
- public static Vector128<float> Tbl4_V128(
- Vector128<float> vector,
- Vector128<float> tb0,
- Vector128<float> tb1,
- Vector128<float> tb2,
- Vector128<float> tb3)
- {
- return Tbl(vector, 16, tb0, tb1, tb2, tb3);
- }
- private static Vector128<float> Tbl(Vector128<float> vector, int bytes, params Vector128<float>[] tb)
- {
- Vector128<float> res = new Vector128<float>();
- byte[] table = new byte[tb.Length * 16];
- for (byte index = 0; index < tb.Length; index++)
- for (byte index2 = 0; index2 < 16; index2++)
- {
- table[index * 16 + index2] = (byte)VectorExtractIntZx(tb[index], index2, 0);
- }
- for (byte index = 0; index < bytes; index++)
- {
- byte tblIdx = (byte)VectorExtractIntZx(vector, index, 0);
- if (tblIdx < table.Length)
- {
- res = VectorInsertInt(table[tblIdx], res, index, 0);
- }
- }
- return res;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double VectorExtractDouble(Vector128<float> vector, byte index)
- {
- if (Sse41.IsSupported)
- {
- return BitConverter.Int64BitsToDouble(Sse41.Extract(Sse.StaticCast<float, long>(vector), index));
- }
- else if (Sse2.IsSupported)
- {
- return BitConverter.Int64BitsToDouble((long)VectorExtractIntZx(vector, index, 3));
- }
- throw new PlatformNotSupportedException();
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long VectorExtractIntSx(Vector128<float> vector, byte index, int size)
- {
- if (Sse41.IsSupported)
- {
- if (size == 0)
- {
- return (sbyte)Sse41.Extract(Sse.StaticCast<float, byte>(vector), index);
- }
- else if (size == 1)
- {
- return (short)Sse2.Extract(Sse.StaticCast<float, ushort>(vector), index);
- }
- else if (size == 2)
- {
- return Sse41.Extract(Sse.StaticCast<float, int>(vector), index);
- }
- else if (size == 3)
- {
- return Sse41.Extract(Sse.StaticCast<float, long>(vector), index);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- }
- else if (Sse2.IsSupported)
- {
- if (size == 0)
- {
- return (sbyte)VectorExtractIntZx(vector, index, size);
- }
- else if (size == 1)
- {
- return (short)VectorExtractIntZx(vector, index, size);
- }
- else if (size == 2)
- {
- return (int)VectorExtractIntZx(vector, index, size);
- }
- else if (size == 3)
- {
- return (long)VectorExtractIntZx(vector, index, size);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- }
- throw new PlatformNotSupportedException();
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong VectorExtractIntZx(Vector128<float> vector, byte index, int size)
- {
- if (Sse41.IsSupported)
- {
- if (size == 0)
- {
- return Sse41.Extract(Sse.StaticCast<float, byte>(vector), index);
- }
- else if (size == 1)
- {
- return Sse2.Extract(Sse.StaticCast<float, ushort>(vector), index);
- }
- else if (size == 2)
- {
- return Sse41.Extract(Sse.StaticCast<float, uint>(vector), index);
- }
- else if (size == 3)
- {
- return Sse41.Extract(Sse.StaticCast<float, ulong>(vector), index);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- }
- else if (Sse2.IsSupported)
- {
- int shortIdx = size == 0
- ? index >> 1
- : index << (size - 1);
- ushort value = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)shortIdx);
- if (size == 0)
- {
- return (byte)(value >> (index & 1) * 8);
- }
- else if (size == 1)
- {
- return value;
- }
- else if (size == 2 || size == 3)
- {
- ushort value1 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 1));
- if (size == 2)
- {
- return (uint)(value | (value1 << 16));
- }
- ushort value2 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 2));
- ushort value3 = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)(shortIdx + 3));
- return ((ulong)value << 0) |
- ((ulong)value1 << 16) |
- ((ulong)value2 << 32) |
- ((ulong)value3 << 48);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- }
- throw new PlatformNotSupportedException();
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static float VectorExtractSingle(Vector128<float> vector, byte index)
- {
- if (Sse41.IsSupported)
- {
- return Sse41.Extract(vector, index);
- }
- else if (Sse2.IsSupported)
- {
- Vector128<ushort> shortVector = Sse.StaticCast<float, ushort>(vector);
- int low = Sse2.Extract(shortVector, (byte)(index * 2 + 0));
- int high = Sse2.Extract(shortVector, (byte)(index * 2 + 1));
- return BitConverter.Int32BitsToSingle(low | (high << 16));
- }
- throw new PlatformNotSupportedException();
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<float> VectorInsertDouble(double value, Vector128<float> vector, byte index)
- {
- return VectorInsertInt((ulong)BitConverter.DoubleToInt64Bits(value), vector, index, 3);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<float> VectorInsertInt(ulong value, Vector128<float> vector, byte index, int size)
- {
- if (Sse41.IsSupported)
- {
- if (size == 0)
- {
- return Sse.StaticCast<byte, float>(Sse41.Insert(Sse.StaticCast<float, byte>(vector), (byte)value, index));
- }
- else if (size == 1)
- {
- return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(vector), (ushort)value, index));
- }
- else if (size == 2)
- {
- return Sse.StaticCast<uint, float>(Sse41.Insert(Sse.StaticCast<float, uint>(vector), (uint)value, index));
- }
- else if (size == 3)
- {
- return Sse.StaticCast<ulong, float>(Sse41.Insert(Sse.StaticCast<float, ulong>(vector), value, index));
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- }
- else if (Sse2.IsSupported)
- {
- Vector128<ushort> shortVector = Sse.StaticCast<float, ushort>(vector);
- int shortIdx = size == 0
- ? index >> 1
- : index << (size - 1);
- if (size == 0)
- {
- ushort shortVal = Sse2.Extract(Sse.StaticCast<float, ushort>(vector), (byte)shortIdx);
- int shift = (index & 1) * 8;
- shortVal &= (ushort)(0xff00 >> shift);
- shortVal |= (ushort)((byte)value << shift);
- return Sse.StaticCast<ushort, float>(Sse2.Insert(shortVector, shortVal, (byte)shortIdx));
- }
- else if (size == 1)
- {
- return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(vector), (ushort)value, index));
- }
- else if (size == 2 || size == 3)
- {
- shortVector = Sse2.Insert(shortVector, (ushort)(value >> 0), (byte)(shortIdx + 0));
- shortVector = Sse2.Insert(shortVector, (ushort)(value >> 16), (byte)(shortIdx + 1));
- if (size == 3)
- {
- shortVector = Sse2.Insert(shortVector, (ushort)(value >> 32), (byte)(shortIdx + 2));
- shortVector = Sse2.Insert(shortVector, (ushort)(value >> 48), (byte)(shortIdx + 3));
- }
- return Sse.StaticCast<ushort, float>(shortVector);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(size));
- }
- }
- throw new PlatformNotSupportedException();
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<float> VectorInsertSingle(float value, Vector128<float> vector, byte index)
- {
- if (Sse41.IsSupported)
- {
- // Note: The if/else if is necessary to enable the JIT to
- // produce a single INSERTPS instruction instead of the
- // jump table fallback.
- if (index == 0)
- {
- return Sse41.Insert(vector, value, 0x00);
- }
- else if (index == 1)
- {
- return Sse41.Insert(vector, value, 0x10);
- }
- else if (index == 2)
- {
- return Sse41.Insert(vector, value, 0x20);
- }
- else if (index == 3)
- {
- return Sse41.Insert(vector, value, 0x30);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
- else if (Sse2.IsSupported)
- {
- int intValue = BitConverter.SingleToInt32Bits(value);
- ushort low = (ushort)(intValue >> 0);
- ushort high = (ushort)(intValue >> 16);
- Vector128<ushort> shortVector = Sse.StaticCast<float, ushort>(vector);
- shortVector = Sse2.Insert(shortVector, low, (byte)(index * 2 + 0));
- shortVector = Sse2.Insert(shortVector, high, (byte)(index * 2 + 1));
- return Sse.StaticCast<ushort, float>(shortVector);
- }
- throw new PlatformNotSupportedException();
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<float> Sse41VectorInsertScalarSingle(float value, Vector128<float> vector)
- {
- // Note: 0b1110 is the mask to zero the upper bits.
- return Sse41.Insert(vector, value, 0b1110);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Vector128<float> VectorSingleZero()
- {
- if (Sse.IsSupported)
- {
- return Sse.SetZeroVector128();
- }
- throw new PlatformNotSupportedException();
- }
- }
- }
|