AVectorHelper.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. using ChocolArm64.State;
  2. using ChocolArm64.Translation;
  3. using System;
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.Intrinsics;
  6. using System.Runtime.Intrinsics.X86;
  7. namespace ChocolArm64.Instruction
  8. {
  9. static class AVectorHelper
  10. {
  11. public static void EmitCall(AILEmitterCtx Context, string Name64, string Name128)
  12. {
  13. bool IsSimd64 = Context.CurrOp.RegisterSize == ARegisterSize.SIMD64;
  14. Context.EmitCall(typeof(AVectorHelper), IsSimd64 ? Name64 : Name128);
  15. }
  16. public static void EmitCall(AILEmitterCtx Context, string MthdName)
  17. {
  18. Context.EmitCall(typeof(AVectorHelper), MthdName);
  19. }
  20. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  21. public static int SatF32ToS32(float Value)
  22. {
  23. if (float.IsNaN(Value)) return 0;
  24. return Value > int.MaxValue ? int.MaxValue :
  25. Value < int.MinValue ? int.MinValue : (int)Value;
  26. }
  27. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  28. public static long SatF32ToS64(float Value)
  29. {
  30. if (float.IsNaN(Value)) return 0;
  31. return Value > long.MaxValue ? long.MaxValue :
  32. Value < long.MinValue ? long.MinValue : (long)Value;
  33. }
  34. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  35. public static uint SatF32ToU32(float Value)
  36. {
  37. if (float.IsNaN(Value)) return 0;
  38. return Value > uint.MaxValue ? uint.MaxValue :
  39. Value < uint.MinValue ? uint.MinValue : (uint)Value;
  40. }
  41. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  42. public static ulong SatF32ToU64(float Value)
  43. {
  44. if (float.IsNaN(Value)) return 0;
  45. return Value > ulong.MaxValue ? ulong.MaxValue :
  46. Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
  47. }
  48. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  49. public static int SatF64ToS32(double Value)
  50. {
  51. if (double.IsNaN(Value)) return 0;
  52. return Value > int.MaxValue ? int.MaxValue :
  53. Value < int.MinValue ? int.MinValue : (int)Value;
  54. }
  55. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  56. public static long SatF64ToS64(double Value)
  57. {
  58. if (double.IsNaN(Value)) return 0;
  59. return Value > long.MaxValue ? long.MaxValue :
  60. Value < long.MinValue ? long.MinValue : (long)Value;
  61. }
  62. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  63. public static uint SatF64ToU32(double Value)
  64. {
  65. if (double.IsNaN(Value)) return 0;
  66. return Value > uint.MaxValue ? uint.MaxValue :
  67. Value < uint.MinValue ? uint.MinValue : (uint)Value;
  68. }
  69. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  70. public static ulong SatF64ToU64(double Value)
  71. {
  72. if (double.IsNaN(Value)) return 0;
  73. return Value > ulong.MaxValue ? ulong.MaxValue :
  74. Value < ulong.MinValue ? ulong.MinValue : (ulong)Value;
  75. }
  76. public static int CountSetBits8(byte Value)
  77. {
  78. return ((Value >> 0) & 1) + ((Value >> 1) & 1) +
  79. ((Value >> 2) & 1) + ((Value >> 3) & 1) +
  80. ((Value >> 4) & 1) + ((Value >> 5) & 1) +
  81. ((Value >> 6) & 1) + (Value >> 7);
  82. }
  83. public static double Max(double LHS, double RHS)
  84. {
  85. if (LHS == 0.0 && RHS == 0.0)
  86. {
  87. if (BitConverter.DoubleToInt64Bits(LHS) < 0 &&
  88. BitConverter.DoubleToInt64Bits(RHS) < 0)
  89. return -0.0;
  90. return 0.0;
  91. }
  92. if (LHS > RHS)
  93. return LHS;
  94. if (double.IsNaN(LHS))
  95. return LHS;
  96. return RHS;
  97. }
  98. public static float MaxF(float LHS, float RHS)
  99. {
  100. if (LHS == 0.0 && RHS == 0.0)
  101. {
  102. if (BitConverter.SingleToInt32Bits(LHS) < 0 &&
  103. BitConverter.SingleToInt32Bits(RHS) < 0)
  104. return -0.0f;
  105. return 0.0f;
  106. }
  107. if (LHS > RHS)
  108. return LHS;
  109. if (float.IsNaN(LHS))
  110. return LHS;
  111. return RHS;
  112. }
  113. public static double Min(double LHS, double RHS)
  114. {
  115. if (LHS == 0.0 && RHS == 0.0)
  116. {
  117. if (BitConverter.DoubleToInt64Bits(LHS) < 0 ||
  118. BitConverter.DoubleToInt64Bits(RHS) < 0)
  119. return -0.0;
  120. return 0.0;
  121. }
  122. if (LHS < RHS)
  123. return LHS;
  124. if (double.IsNaN(LHS))
  125. return LHS;
  126. return RHS;
  127. }
  128. public static float MinF(float LHS, float RHS)
  129. {
  130. if (LHS == 0.0 && RHS == 0.0)
  131. {
  132. if (BitConverter.SingleToInt32Bits(LHS) < 0 ||
  133. BitConverter.SingleToInt32Bits(RHS) < 0)
  134. return -0.0f;
  135. return 0.0f;
  136. }
  137. if (LHS < RHS)
  138. return LHS;
  139. if (float.IsNaN(LHS))
  140. return LHS;
  141. return RHS;
  142. }
  143. public static double Round(double Value, int Fpcr)
  144. {
  145. switch ((ARoundMode)((Fpcr >> 22) & 3))
  146. {
  147. case ARoundMode.ToNearest: return Math.Round (Value);
  148. case ARoundMode.TowardsPlusInfinity: return Math.Ceiling (Value);
  149. case ARoundMode.TowardsMinusInfinity: return Math.Floor (Value);
  150. case ARoundMode.TowardsZero: return Math.Truncate(Value);
  151. }
  152. throw new InvalidOperationException();
  153. }
  154. public static float RoundF(float Value, int Fpcr)
  155. {
  156. switch ((ARoundMode)((Fpcr >> 22) & 3))
  157. {
  158. case ARoundMode.ToNearest: return MathF.Round (Value);
  159. case ARoundMode.TowardsPlusInfinity: return MathF.Ceiling (Value);
  160. case ARoundMode.TowardsMinusInfinity: return MathF.Floor (Value);
  161. case ARoundMode.TowardsZero: return MathF.Truncate(Value);
  162. }
  163. throw new InvalidOperationException();
  164. }
  165. public static Vector128<float> Tbl1_V64(
  166. Vector128<float> Vector,
  167. Vector128<float> Tb0)
  168. {
  169. return Tbl(Vector, 8, Tb0);
  170. }
  171. public static Vector128<float> Tbl1_V128(
  172. Vector128<float> Vector,
  173. Vector128<float> Tb0)
  174. {
  175. return Tbl(Vector, 16, Tb0);
  176. }
  177. public static Vector128<float> Tbl2_V64(
  178. Vector128<float> Vector,
  179. Vector128<float> Tb0,
  180. Vector128<float> Tb1)
  181. {
  182. return Tbl(Vector, 8, Tb0, Tb1);
  183. }
  184. public static Vector128<float> Tbl2_V128(
  185. Vector128<float> Vector,
  186. Vector128<float> Tb0,
  187. Vector128<float> Tb1)
  188. {
  189. return Tbl(Vector, 16, Tb0, Tb1);
  190. }
  191. public static Vector128<float> Tbl3_V64(
  192. Vector128<float> Vector,
  193. Vector128<float> Tb0,
  194. Vector128<float> Tb1,
  195. Vector128<float> Tb2)
  196. {
  197. return Tbl(Vector, 8, Tb0, Tb1, Tb2);
  198. }
  199. public static Vector128<float> Tbl3_V128(
  200. Vector128<float> Vector,
  201. Vector128<float> Tb0,
  202. Vector128<float> Tb1,
  203. Vector128<float> Tb2)
  204. {
  205. return Tbl(Vector, 16, Tb0, Tb1, Tb2);
  206. }
  207. public static Vector128<float> Tbl4_V64(
  208. Vector128<float> Vector,
  209. Vector128<float> Tb0,
  210. Vector128<float> Tb1,
  211. Vector128<float> Tb2,
  212. Vector128<float> Tb3)
  213. {
  214. return Tbl(Vector, 8, Tb0, Tb1, Tb2, Tb3);
  215. }
  216. public static Vector128<float> Tbl4_V128(
  217. Vector128<float> Vector,
  218. Vector128<float> Tb0,
  219. Vector128<float> Tb1,
  220. Vector128<float> Tb2,
  221. Vector128<float> Tb3)
  222. {
  223. return Tbl(Vector, 16, Tb0, Tb1, Tb2, Tb3);
  224. }
  225. private static Vector128<float> Tbl(Vector128<float> Vector, int Bytes, params Vector128<float>[] Tb)
  226. {
  227. Vector128<float> Res = new Vector128<float>();
  228. byte[] Table = new byte[Tb.Length * 16];
  229. for (byte Index = 0; Index < Tb.Length; Index++)
  230. for (byte Index2 = 0; Index2 < 16; Index2++)
  231. {
  232. Table[Index * 16 + Index2] = (byte)VectorExtractIntZx(Tb[Index], Index2, 0);
  233. }
  234. for (byte Index = 0; Index < Bytes; Index++)
  235. {
  236. byte TblIdx = (byte)VectorExtractIntZx(Vector, Index, 0);
  237. if (TblIdx < Table.Length)
  238. {
  239. Res = VectorInsertInt(Table[TblIdx], Res, Index, 0);
  240. }
  241. }
  242. return Res;
  243. }
  244. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  245. public static double VectorExtractDouble(Vector128<float> Vector, byte Index)
  246. {
  247. return BitConverter.Int64BitsToDouble(VectorExtractIntSx(Vector, Index, 3));
  248. }
  249. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  250. public static long VectorExtractIntSx(Vector128<float> Vector, byte Index, int Size)
  251. {
  252. if (Sse41.IsSupported)
  253. {
  254. switch (Size)
  255. {
  256. case 0:
  257. return (sbyte)Sse41.Extract(Sse.StaticCast<float, byte>(Vector), Index);
  258. case 1:
  259. return (short)Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), Index);
  260. case 2:
  261. return Sse41.Extract(Sse.StaticCast<float, int>(Vector), Index);
  262. case 3:
  263. return Sse41.Extract(Sse.StaticCast<float, long>(Vector), Index);
  264. }
  265. throw new ArgumentOutOfRangeException(nameof(Size));
  266. }
  267. else if (Sse2.IsSupported)
  268. {
  269. switch (Size)
  270. {
  271. case 0:
  272. return (sbyte)VectorExtractIntZx(Vector, Index, Size);
  273. case 1:
  274. return (short)VectorExtractIntZx(Vector, Index, Size);
  275. case 2:
  276. return (int)VectorExtractIntZx(Vector, Index, Size);
  277. case 3:
  278. return (long)VectorExtractIntZx(Vector, Index, Size);
  279. }
  280. throw new ArgumentOutOfRangeException(nameof(Size));
  281. }
  282. throw new PlatformNotSupportedException();
  283. }
  284. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  285. public static ulong VectorExtractIntZx(Vector128<float> Vector, byte Index, int Size)
  286. {
  287. if (Sse41.IsSupported)
  288. {
  289. switch (Size)
  290. {
  291. case 0:
  292. return Sse41.Extract(Sse.StaticCast<float, byte>(Vector), Index);
  293. case 1:
  294. return Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), Index);
  295. case 2:
  296. return Sse41.Extract(Sse.StaticCast<float, uint>(Vector), Index);
  297. case 3:
  298. return Sse41.Extract(Sse.StaticCast<float, ulong>(Vector), Index);
  299. }
  300. throw new ArgumentOutOfRangeException(nameof(Size));
  301. }
  302. else if (Sse2.IsSupported)
  303. {
  304. int ShortIdx = Size == 0
  305. ? Index >> 1
  306. : Index << (Size - 1);
  307. ushort Value = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)ShortIdx);
  308. switch (Size)
  309. {
  310. case 0:
  311. return (byte)(Value >> (Index & 1) * 8);
  312. case 1:
  313. return Value;
  314. case 2:
  315. case 3:
  316. {
  317. ushort Value1 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 1));
  318. if (Size == 2)
  319. {
  320. return (uint)(Value | (Value1 << 16));
  321. }
  322. ushort Value2 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 2));
  323. ushort Value3 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 3));
  324. return ((ulong)Value << 0) |
  325. ((ulong)Value1 << 16) |
  326. ((ulong)Value2 << 32) |
  327. ((ulong)Value3 << 48);
  328. }
  329. }
  330. throw new ArgumentOutOfRangeException(nameof(Size));
  331. }
  332. throw new PlatformNotSupportedException();
  333. }
  334. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  335. public static float VectorExtractSingle(Vector128<float> Vector, byte Index)
  336. {
  337. if (Sse41.IsSupported)
  338. {
  339. return Sse41.Extract(Vector, Index);
  340. }
  341. else if (Sse2.IsSupported)
  342. {
  343. Vector128<ushort> ShortVector = Sse.StaticCast<float, ushort>(Vector);
  344. int Low = Sse2.Extract(ShortVector, (byte)(Index * 2 + 0));
  345. int High = Sse2.Extract(ShortVector, (byte)(Index * 2 + 1));
  346. return BitConverter.Int32BitsToSingle(Low | (High << 16));
  347. }
  348. throw new PlatformNotSupportedException();
  349. }
  350. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  351. public static Vector128<float> VectorInsertDouble(double Value, Vector128<float> Vector, byte Index)
  352. {
  353. return VectorInsertInt((ulong)BitConverter.DoubleToInt64Bits(Value), Vector, Index, 3);
  354. }
  355. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  356. public static Vector128<float> VectorInsertInt(ulong Value, Vector128<float> Vector, byte Index, int Size)
  357. {
  358. if (Sse41.IsSupported)
  359. {
  360. switch (Size)
  361. {
  362. case 0:
  363. return Sse.StaticCast<byte, float>(Sse41.Insert(Sse.StaticCast<float, byte>(Vector), (byte)Value, Index));
  364. case 1:
  365. return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(Vector), (ushort)Value, Index));
  366. case 2:
  367. return Sse.StaticCast<uint, float>(Sse41.Insert(Sse.StaticCast<float, uint>(Vector), (uint)Value, Index));
  368. case 3:
  369. return Sse.StaticCast<ulong, float>(Sse41.Insert(Sse.StaticCast<float, ulong>(Vector), Value, Index));
  370. }
  371. throw new ArgumentOutOfRangeException(nameof(Size));
  372. }
  373. else if (Sse2.IsSupported)
  374. {
  375. Vector128<ushort> ShortVector = Sse.StaticCast<float, ushort>(Vector);
  376. int ShortIdx = Size == 0
  377. ? Index >> 1
  378. : Index << (Size - 1);
  379. switch (Size)
  380. {
  381. case 0:
  382. {
  383. ushort ShortVal = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)ShortIdx);
  384. int Shift = (Index & 1) * 8;
  385. ShortVal &= (ushort)(0xff00 >> Shift);
  386. ShortVal |= (ushort)((byte)Value << Shift);
  387. return Sse.StaticCast<ushort, float>(Sse2.Insert(ShortVector, ShortVal, (byte)ShortIdx));
  388. }
  389. case 1:
  390. return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(Vector), (ushort)Value, Index));
  391. case 2:
  392. case 3:
  393. {
  394. ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 0), (byte)(ShortIdx + 0));
  395. ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 16), (byte)(ShortIdx + 1));
  396. if (Size == 3)
  397. {
  398. ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 32), (byte)(ShortIdx + 2));
  399. ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 48), (byte)(ShortIdx + 3));
  400. }
  401. return Sse.StaticCast<ushort, float>(ShortVector);
  402. }
  403. }
  404. throw new ArgumentOutOfRangeException(nameof(Size));
  405. }
  406. throw new PlatformNotSupportedException();
  407. }
  408. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  409. public static Vector128<float> VectorInsertSingle(float Value, Vector128<float> Vector, byte Index)
  410. {
  411. if (Sse41.IsSupported)
  412. {
  413. return Sse41.Insert(Vector, Value, (byte)(Index << 4));
  414. }
  415. else if (Sse2.IsSupported)
  416. {
  417. int IntValue = BitConverter.SingleToInt32Bits(Value);
  418. ushort Low = (ushort)(IntValue >> 0);
  419. ushort High = (ushort)(IntValue >> 16);
  420. Vector128<ushort> ShortVector = Sse.StaticCast<float, ushort>(Vector);
  421. ShortVector = Sse2.Insert(ShortVector, Low, (byte)(Index * 2 + 0));
  422. ShortVector = Sse2.Insert(ShortVector, High, (byte)(Index * 2 + 1));
  423. return Sse.StaticCast<ushort, float>(ShortVector);
  424. }
  425. throw new PlatformNotSupportedException();
  426. }
  427. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  428. public static Vector128<sbyte> VectorSingleToSByte(Vector128<float> Vector)
  429. {
  430. if (Sse.IsSupported)
  431. {
  432. return Sse.StaticCast<float, sbyte>(Vector);
  433. }
  434. throw new PlatformNotSupportedException();
  435. }
  436. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  437. public static Vector128<short> VectorSingleToInt16(Vector128<float> Vector)
  438. {
  439. if (Sse.IsSupported)
  440. {
  441. return Sse.StaticCast<float, short>(Vector);
  442. }
  443. throw new PlatformNotSupportedException();
  444. }
  445. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  446. public static Vector128<int> VectorSingleToInt32(Vector128<float> Vector)
  447. {
  448. if (Sse.IsSupported)
  449. {
  450. return Sse.StaticCast<float, int>(Vector);
  451. }
  452. throw new PlatformNotSupportedException();
  453. }
  454. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  455. public static Vector128<long> VectorSingleToInt64(Vector128<float> Vector)
  456. {
  457. if (Sse.IsSupported)
  458. {
  459. return Sse.StaticCast<float, long>(Vector);
  460. }
  461. throw new PlatformNotSupportedException();
  462. }
  463. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  464. public static Vector128<double> VectorSingleToDouble(Vector128<float> Vector)
  465. {
  466. if (Sse.IsSupported)
  467. {
  468. return Sse.StaticCast<float, double>(Vector);
  469. }
  470. throw new PlatformNotSupportedException();
  471. }
  472. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  473. public static Vector128<float> VectorSByteToSingle(Vector128<sbyte> Vector)
  474. {
  475. if (Sse.IsSupported)
  476. {
  477. return Sse.StaticCast<sbyte, float>(Vector);
  478. }
  479. throw new PlatformNotSupportedException();
  480. }
  481. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  482. public static Vector128<float> VectorInt16ToSingle(Vector128<short> Vector)
  483. {
  484. if (Sse.IsSupported)
  485. {
  486. return Sse.StaticCast<short, float>(Vector);
  487. }
  488. throw new PlatformNotSupportedException();
  489. }
  490. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  491. public static Vector128<float> VectorInt32ToSingle(Vector128<int> Vector)
  492. {
  493. if (Sse.IsSupported)
  494. {
  495. return Sse.StaticCast<int, float>(Vector);
  496. }
  497. throw new PlatformNotSupportedException();
  498. }
  499. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  500. public static Vector128<float> VectorInt64ToSingle(Vector128<long> Vector)
  501. {
  502. if (Sse.IsSupported)
  503. {
  504. return Sse.StaticCast<long, float>(Vector);
  505. }
  506. throw new PlatformNotSupportedException();
  507. }
  508. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  509. public static Vector128<float> VectorDoubleToSingle(Vector128<double> Vector)
  510. {
  511. if (Sse.IsSupported)
  512. {
  513. return Sse.StaticCast<double, float>(Vector);
  514. }
  515. throw new PlatformNotSupportedException();
  516. }
  517. }
  518. }