AInstEmitSimdArithmetic.cs 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219
  1. using ChocolArm64.Decoder;
  2. using ChocolArm64.State;
  3. using ChocolArm64.Translation;
  4. using System;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using System.Runtime.Intrinsics.X86;
  8. using static ChocolArm64.Instruction.AInstEmitSimdHelper;
  9. namespace ChocolArm64.Instruction
  10. {
  11. static partial class AInstEmit
  12. {
  13. public static void Abs_S(AILEmitterCtx Context)
  14. {
  15. EmitScalarUnaryOpSx(Context, () => EmitAbs(Context));
  16. }
  17. public static void Abs_V(AILEmitterCtx Context)
  18. {
  19. EmitVectorUnaryOpSx(Context, () => EmitAbs(Context));
  20. }
  21. public static void Add_S(AILEmitterCtx Context)
  22. {
  23. EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  24. }
  25. public static void Add_V(AILEmitterCtx Context)
  26. {
  27. if (AOptimizations.UseSse2)
  28. {
  29. EmitSse2Call(Context, nameof(Sse2.Add));
  30. }
  31. else
  32. {
  33. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  34. }
  35. }
  36. public static void Addhn_V(AILEmitterCtx Context)
  37. {
  38. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Add), Round: false);
  39. }
  40. public static void Addp_S(AILEmitterCtx Context)
  41. {
  42. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  43. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  44. EmitVectorExtractZx(Context, Op.Rn, 1, Op.Size);
  45. Context.Emit(OpCodes.Add);
  46. EmitScalarSet(Context, Op.Rd, Op.Size);
  47. }
  48. public static void Addp_V(AILEmitterCtx Context)
  49. {
  50. EmitVectorPairwiseOpZx(Context, () => Context.Emit(OpCodes.Add));
  51. }
  52. public static void Addv_V(AILEmitterCtx Context)
  53. {
  54. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  55. int Bytes = Op.GetBitsCount() >> 3;
  56. int Elems = Bytes >> Op.Size;
  57. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  58. for (int Index = 1; Index < Elems; Index++)
  59. {
  60. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  61. Context.Emit(OpCodes.Add);
  62. }
  63. EmitScalarSet(Context, Op.Rd, Op.Size);
  64. }
  65. public static void Cls_V(AILEmitterCtx Context)
  66. {
  67. MethodInfo MthdInfo = typeof(ASoftFallback).GetMethod(nameof(ASoftFallback.CountLeadingSigns));
  68. EmitCountLeadingBits(Context, () => Context.EmitCall(MthdInfo));
  69. }
  70. public static void Clz_V(AILEmitterCtx Context)
  71. {
  72. MethodInfo MthdInfo = typeof(ASoftFallback).GetMethod(nameof(ASoftFallback.CountLeadingZeros));
  73. EmitCountLeadingBits(Context, () => Context.EmitCall(MthdInfo));
  74. }
  75. private static void EmitCountLeadingBits(AILEmitterCtx Context, Action Emit)
  76. {
  77. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  78. int Bytes = Op.GetBitsCount() >> 3;
  79. int Elems = Bytes >> Op.Size;
  80. int ESize = 8 << Op.Size;
  81. for (int Index = 0; Index < Elems; Index++)
  82. {
  83. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  84. Context.EmitLdc_I4(ESize);
  85. Emit();
  86. EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
  87. }
  88. if (Op.RegisterSize == ARegisterSize.SIMD64)
  89. {
  90. EmitVectorZeroUpper(Context, Op.Rd);
  91. }
  92. }
  93. public static void Cnt_V(AILEmitterCtx Context)
  94. {
  95. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  96. int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8;
  97. for (int Index = 0; Index < Elems; Index++)
  98. {
  99. EmitVectorExtractZx(Context, Op.Rn, Index, 0);
  100. Context.Emit(OpCodes.Conv_U4);
  101. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8));
  102. Context.Emit(OpCodes.Conv_U8);
  103. EmitVectorInsert(Context, Op.Rd, Index, 0);
  104. }
  105. if (Op.RegisterSize == ARegisterSize.SIMD64)
  106. {
  107. EmitVectorZeroUpper(Context, Op.Rd);
  108. }
  109. }
  110. private static void EmitAbs(AILEmitterCtx Context)
  111. {
  112. AILLabel LblTrue = new AILLabel();
  113. Context.Emit(OpCodes.Dup);
  114. Context.Emit(OpCodes.Ldc_I4_0);
  115. Context.Emit(OpCodes.Bge_S, LblTrue);
  116. Context.Emit(OpCodes.Neg);
  117. Context.MarkLabel(LblTrue);
  118. }
  119. private static void EmitHighNarrow(AILEmitterCtx Context, Action Emit, bool Round)
  120. {
  121. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  122. int Elems = 8 >> Op.Size;
  123. int ESize = 8 << Op.Size;
  124. int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
  125. long RoundConst = 1L << (ESize - 1);
  126. for (int Index = 0; Index < Elems; Index++)
  127. {
  128. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
  129. EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size + 1);
  130. Emit();
  131. if (Round)
  132. {
  133. Context.EmitLdc_I8(RoundConst);
  134. Context.Emit(OpCodes.Add);
  135. }
  136. Context.EmitLsr(ESize);
  137. EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
  138. }
  139. if (Part == 0)
  140. {
  141. EmitVectorZeroUpper(Context, Op.Rd);
  142. }
  143. }
  144. public static void Fabd_S(AILEmitterCtx Context)
  145. {
  146. EmitScalarBinaryOpF(Context, () =>
  147. {
  148. Context.Emit(OpCodes.Sub);
  149. EmitUnaryMathCall(Context, nameof(Math.Abs));
  150. });
  151. }
  152. public static void Fabs_S(AILEmitterCtx Context)
  153. {
  154. EmitScalarUnaryOpF(Context, () =>
  155. {
  156. EmitUnaryMathCall(Context, nameof(Math.Abs));
  157. });
  158. }
  159. public static void Fabs_V(AILEmitterCtx Context)
  160. {
  161. EmitVectorUnaryOpF(Context, () =>
  162. {
  163. EmitUnaryMathCall(Context, nameof(Math.Abs));
  164. });
  165. }
  166. public static void Fadd_S(AILEmitterCtx Context)
  167. {
  168. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  169. {
  170. EmitSseOrSse2CallF(Context, nameof(Sse.AddScalar));
  171. }
  172. else
  173. {
  174. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
  175. }
  176. }
  177. public static void Fadd_V(AILEmitterCtx Context)
  178. {
  179. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  180. {
  181. EmitSseOrSse2CallF(Context, nameof(Sse.Add));
  182. }
  183. else
  184. {
  185. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
  186. }
  187. }
  188. public static void Faddp_S(AILEmitterCtx Context)
  189. {
  190. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  191. int SizeF = Op.Size & 1;
  192. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  193. EmitVectorExtractF(Context, Op.Rn, 1, SizeF);
  194. Context.Emit(OpCodes.Add);
  195. EmitScalarSetF(Context, Op.Rd, SizeF);
  196. }
  197. public static void Faddp_V(AILEmitterCtx Context)
  198. {
  199. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  200. int SizeF = Op.Size & 1;
  201. int Bytes = Op.GetBitsCount() >> 3;
  202. int Elems = Bytes >> SizeF + 2;
  203. int Half = Elems >> 1;
  204. for (int Index = 0; Index < Elems; Index++)
  205. {
  206. int Elem = (Index & (Half - 1)) << 1;
  207. EmitVectorExtractF(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, SizeF);
  208. EmitVectorExtractF(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, SizeF);
  209. Context.Emit(OpCodes.Add);
  210. EmitVectorInsertTmpF(Context, Index, SizeF);
  211. }
  212. Context.EmitLdvectmp();
  213. Context.EmitStvec(Op.Rd);
  214. if (Op.RegisterSize == ARegisterSize.SIMD64)
  215. {
  216. EmitVectorZeroUpper(Context, Op.Rd);
  217. }
  218. }
  219. public static void Fdiv_S(AILEmitterCtx Context)
  220. {
  221. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  222. {
  223. EmitSseOrSse2CallF(Context, nameof(Sse.DivideScalar));
  224. }
  225. else
  226. {
  227. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
  228. }
  229. }
  230. public static void Fdiv_V(AILEmitterCtx Context)
  231. {
  232. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  233. {
  234. EmitSseOrSse2CallF(Context, nameof(Sse.Divide));
  235. }
  236. else
  237. {
  238. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
  239. }
  240. }
  241. public static void Fmadd_S(AILEmitterCtx Context)
  242. {
  243. EmitScalarTernaryRaOpF(Context, () =>
  244. {
  245. Context.Emit(OpCodes.Mul);
  246. Context.Emit(OpCodes.Add);
  247. });
  248. }
  249. public static void Fmax_S(AILEmitterCtx Context)
  250. {
  251. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  252. EmitScalarBinaryOpF(Context, () =>
  253. {
  254. if (Op.Size == 0)
  255. {
  256. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.MaxF));
  257. }
  258. else if (Op.Size == 1)
  259. {
  260. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Max));
  261. }
  262. else
  263. {
  264. throw new InvalidOperationException();
  265. }
  266. });
  267. }
  268. public static void Fmax_V(AILEmitterCtx Context)
  269. {
  270. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  271. EmitVectorBinaryOpF(Context, () =>
  272. {
  273. if (Op.Size == 0)
  274. {
  275. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.MaxF));
  276. }
  277. else if (Op.Size == 1)
  278. {
  279. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Max));
  280. }
  281. else
  282. {
  283. throw new InvalidOperationException();
  284. }
  285. });
  286. }
  287. public static void Fmin_S(AILEmitterCtx Context)
  288. {
  289. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  290. EmitScalarBinaryOpF(Context, () =>
  291. {
  292. if (Op.Size == 0)
  293. {
  294. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.MinF));
  295. }
  296. else if (Op.Size == 1)
  297. {
  298. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Min));
  299. }
  300. else
  301. {
  302. throw new InvalidOperationException();
  303. }
  304. });
  305. }
  306. public static void Fmin_V(AILEmitterCtx Context)
  307. {
  308. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  309. int SizeF = Op.Size & 1;
  310. EmitVectorBinaryOpF(Context, () =>
  311. {
  312. if (SizeF == 0)
  313. {
  314. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.MinF));
  315. }
  316. else if (SizeF == 1)
  317. {
  318. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Min));
  319. }
  320. else
  321. {
  322. throw new InvalidOperationException();
  323. }
  324. });
  325. }
  326. public static void Fmaxnm_S(AILEmitterCtx Context)
  327. {
  328. Fmax_S(Context);
  329. }
  330. public static void Fminnm_S(AILEmitterCtx Context)
  331. {
  332. Fmin_S(Context);
  333. }
  334. public static void Fmla_Se(AILEmitterCtx Context)
  335. {
  336. EmitScalarTernaryOpByElemF(Context, () =>
  337. {
  338. Context.Emit(OpCodes.Mul);
  339. Context.Emit(OpCodes.Add);
  340. });
  341. }
  342. public static void Fmla_V(AILEmitterCtx Context)
  343. {
  344. EmitVectorTernaryOpF(Context, () =>
  345. {
  346. Context.Emit(OpCodes.Mul);
  347. Context.Emit(OpCodes.Add);
  348. });
  349. }
  350. public static void Fmla_Ve(AILEmitterCtx Context)
  351. {
  352. EmitVectorTernaryOpByElemF(Context, () =>
  353. {
  354. Context.Emit(OpCodes.Mul);
  355. Context.Emit(OpCodes.Add);
  356. });
  357. }
  358. public static void Fmls_V(AILEmitterCtx Context)
  359. {
  360. EmitVectorTernaryOpF(Context, () =>
  361. {
  362. Context.Emit(OpCodes.Mul);
  363. Context.Emit(OpCodes.Sub);
  364. });
  365. }
  366. public static void Fmls_Ve(AILEmitterCtx Context)
  367. {
  368. EmitVectorTernaryOpByElemF(Context, () =>
  369. {
  370. Context.Emit(OpCodes.Mul);
  371. Context.Emit(OpCodes.Sub);
  372. });
  373. }
  374. public static void Fmsub_S(AILEmitterCtx Context)
  375. {
  376. EmitScalarTernaryRaOpF(Context, () =>
  377. {
  378. Context.Emit(OpCodes.Mul);
  379. Context.Emit(OpCodes.Sub);
  380. });
  381. }
  382. public static void Fmul_S(AILEmitterCtx Context)
  383. {
  384. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  385. {
  386. EmitSseOrSse2CallF(Context, nameof(Sse.MultiplyScalar));
  387. }
  388. else
  389. {
  390. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
  391. }
  392. }
  393. public static void Fmul_Se(AILEmitterCtx Context)
  394. {
  395. EmitScalarBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
  396. }
  397. public static void Fmul_V(AILEmitterCtx Context)
  398. {
  399. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  400. {
  401. EmitSseOrSse2CallF(Context, nameof(Sse.Multiply));
  402. }
  403. else
  404. {
  405. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
  406. }
  407. }
  408. public static void Fmul_Ve(AILEmitterCtx Context)
  409. {
  410. EmitVectorBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
  411. }
  412. public static void Fneg_S(AILEmitterCtx Context)
  413. {
  414. EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
  415. }
  416. public static void Fneg_V(AILEmitterCtx Context)
  417. {
  418. EmitVectorUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
  419. }
  420. public static void Fnmadd_S(AILEmitterCtx Context)
  421. {
  422. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  423. int SizeF = Op.Size & 1;
  424. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  425. Context.Emit(OpCodes.Neg);
  426. EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
  427. Context.Emit(OpCodes.Mul);
  428. EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
  429. Context.Emit(OpCodes.Sub);
  430. EmitScalarSetF(Context, Op.Rd, SizeF);
  431. }
  432. public static void Fnmsub_S(AILEmitterCtx Context)
  433. {
  434. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  435. int SizeF = Op.Size & 1;
  436. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  437. EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
  438. Context.Emit(OpCodes.Mul);
  439. EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
  440. Context.Emit(OpCodes.Sub);
  441. EmitScalarSetF(Context, Op.Rd, SizeF);
  442. }
  443. public static void Fnmul_S(AILEmitterCtx Context)
  444. {
  445. EmitScalarBinaryOpF(Context, () =>
  446. {
  447. Context.Emit(OpCodes.Mul);
  448. Context.Emit(OpCodes.Neg);
  449. });
  450. }
  451. public static void Frecpe_S(AILEmitterCtx Context)
  452. {
  453. EmitScalarUnaryOpF(Context, () =>
  454. {
  455. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.RecipEstimate));
  456. });
  457. }
  458. public static void Frecpe_V(AILEmitterCtx Context)
  459. {
  460. EmitVectorUnaryOpF(Context, () =>
  461. {
  462. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.RecipEstimate));
  463. });
  464. }
  465. public static void Frecps_S(AILEmitterCtx Context)
  466. {
  467. EmitScalarBinaryOpF(Context, () =>
  468. {
  469. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.RecipStep));
  470. });
  471. }
  472. public static void Frecps_V(AILEmitterCtx Context)
  473. {
  474. EmitVectorBinaryOpF(Context, () =>
  475. {
  476. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.RecipStep));
  477. });
  478. }
  479. public static void Frinta_S(AILEmitterCtx Context)
  480. {
  481. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  482. EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
  483. EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
  484. EmitScalarSetF(Context, Op.Rd, Op.Size);
  485. }
  486. public static void Frinta_V(AILEmitterCtx Context)
  487. {
  488. EmitVectorUnaryOpF(Context, () =>
  489. {
  490. EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
  491. });
  492. }
  493. public static void Frinti_S(AILEmitterCtx Context)
  494. {
  495. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  496. EmitScalarUnaryOpF(Context, () =>
  497. {
  498. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  499. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  500. if (Op.Size == 0)
  501. {
  502. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  503. }
  504. else if (Op.Size == 1)
  505. {
  506. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  507. }
  508. else
  509. {
  510. throw new InvalidOperationException();
  511. }
  512. });
  513. }
  514. public static void Frinti_V(AILEmitterCtx Context)
  515. {
  516. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  517. int SizeF = Op.Size & 1;
  518. EmitVectorUnaryOpF(Context, () =>
  519. {
  520. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  521. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  522. if (SizeF == 0)
  523. {
  524. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  525. }
  526. else if (SizeF == 1)
  527. {
  528. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  529. }
  530. else
  531. {
  532. throw new InvalidOperationException();
  533. }
  534. });
  535. }
  536. public static void Frintm_S(AILEmitterCtx Context)
  537. {
  538. EmitScalarUnaryOpF(Context, () =>
  539. {
  540. EmitUnaryMathCall(Context, nameof(Math.Floor));
  541. });
  542. }
  543. public static void Frintm_V(AILEmitterCtx Context)
  544. {
  545. EmitVectorUnaryOpF(Context, () =>
  546. {
  547. EmitUnaryMathCall(Context, nameof(Math.Floor));
  548. });
  549. }
  550. public static void Frintn_S(AILEmitterCtx Context)
  551. {
  552. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  553. EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
  554. EmitRoundMathCall(Context, MidpointRounding.ToEven);
  555. EmitScalarSetF(Context, Op.Rd, Op.Size);
  556. }
  557. public static void Frintn_V(AILEmitterCtx Context)
  558. {
  559. EmitVectorUnaryOpF(Context, () =>
  560. {
  561. EmitRoundMathCall(Context, MidpointRounding.ToEven);
  562. });
  563. }
  564. public static void Frintp_S(AILEmitterCtx Context)
  565. {
  566. EmitScalarUnaryOpF(Context, () =>
  567. {
  568. EmitUnaryMathCall(Context, nameof(Math.Ceiling));
  569. });
  570. }
  571. public static void Frintp_V(AILEmitterCtx Context)
  572. {
  573. EmitVectorUnaryOpF(Context, () =>
  574. {
  575. EmitUnaryMathCall(Context, nameof(Math.Ceiling));
  576. });
  577. }
  578. public static void Frintx_S(AILEmitterCtx Context)
  579. {
  580. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  581. EmitScalarUnaryOpF(Context, () =>
  582. {
  583. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  584. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  585. if (Op.Size == 0)
  586. {
  587. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  588. }
  589. else if (Op.Size == 1)
  590. {
  591. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  592. }
  593. else
  594. {
  595. throw new InvalidOperationException();
  596. }
  597. });
  598. }
  599. public static void Frintx_V(AILEmitterCtx Context)
  600. {
  601. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  602. EmitVectorUnaryOpF(Context, () =>
  603. {
  604. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  605. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  606. if (Op.Size == 0)
  607. {
  608. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  609. }
  610. else if (Op.Size == 1)
  611. {
  612. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  613. }
  614. else
  615. {
  616. throw new InvalidOperationException();
  617. }
  618. });
  619. }
  620. public static void Frsqrte_S(AILEmitterCtx Context)
  621. {
  622. EmitScalarUnaryOpF(Context, () =>
  623. {
  624. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
  625. });
  626. }
  627. public static void Frsqrte_V(AILEmitterCtx Context)
  628. {
  629. EmitVectorUnaryOpF(Context, () =>
  630. {
  631. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
  632. });
  633. }
  634. public static void Frsqrts_S(AILEmitterCtx Context)
  635. {
  636. EmitFrsqrts(Context, 0, Scalar: true);
  637. }
  638. public static void Frsqrts_V(AILEmitterCtx Context)
  639. {
  640. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  641. int SizeF = Op.Size & 1;
  642. int Bytes = Op.GetBitsCount() >> 3;
  643. for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
  644. {
  645. EmitFrsqrts(Context, Index, Scalar: false);
  646. }
  647. if (Op.RegisterSize == ARegisterSize.SIMD64)
  648. {
  649. EmitVectorZeroUpper(Context, Op.Rd);
  650. }
  651. }
  652. private static void EmitFrsqrts(AILEmitterCtx Context, int Index, bool Scalar)
  653. {
  654. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  655. int SizeF = Op.Size & 1;
  656. if (SizeF == 0)
  657. {
  658. Context.EmitLdc_R4(3);
  659. }
  660. else /* if (SizeF == 1) */
  661. {
  662. Context.EmitLdc_R8(3);
  663. }
  664. EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
  665. EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
  666. Context.Emit(OpCodes.Mul);
  667. Context.Emit(OpCodes.Sub);
  668. if (SizeF == 0)
  669. {
  670. Context.EmitLdc_R4(0.5f);
  671. }
  672. else /* if (SizeF == 1) */
  673. {
  674. Context.EmitLdc_R8(0.5);
  675. }
  676. Context.Emit(OpCodes.Mul);
  677. if (Scalar)
  678. {
  679. EmitVectorZeroAll(Context, Op.Rd);
  680. }
  681. EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
  682. }
  683. public static void Fsqrt_S(AILEmitterCtx Context)
  684. {
  685. EmitScalarUnaryOpF(Context, () =>
  686. {
  687. EmitUnaryMathCall(Context, nameof(Math.Sqrt));
  688. });
  689. }
  690. public static void Fsub_S(AILEmitterCtx Context)
  691. {
  692. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  693. {
  694. EmitSseOrSse2CallF(Context, nameof(Sse.SubtractScalar));
  695. }
  696. else
  697. {
  698. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
  699. }
  700. }
  701. public static void Fsub_V(AILEmitterCtx Context)
  702. {
  703. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  704. {
  705. EmitSseOrSse2CallF(Context, nameof(Sse.Subtract));
  706. }
  707. else
  708. {
  709. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
  710. }
  711. }
  712. public static void Mla_V(AILEmitterCtx Context)
  713. {
  714. EmitVectorTernaryOpZx(Context, () =>
  715. {
  716. Context.Emit(OpCodes.Mul);
  717. Context.Emit(OpCodes.Add);
  718. });
  719. }
  720. public static void Mla_Ve(AILEmitterCtx Context)
  721. {
  722. EmitVectorTernaryOpByElemZx(Context, () =>
  723. {
  724. Context.Emit(OpCodes.Mul);
  725. Context.Emit(OpCodes.Add);
  726. });
  727. }
  728. public static void Mls_V(AILEmitterCtx Context)
  729. {
  730. EmitVectorTernaryOpZx(Context, () =>
  731. {
  732. Context.Emit(OpCodes.Mul);
  733. Context.Emit(OpCodes.Sub);
  734. });
  735. }
  736. public static void Mul_V(AILEmitterCtx Context)
  737. {
  738. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
  739. }
  740. public static void Mul_Ve(AILEmitterCtx Context)
  741. {
  742. EmitVectorBinaryOpByElemZx(Context, () => Context.Emit(OpCodes.Mul));
  743. }
  744. public static void Neg_S(AILEmitterCtx Context)
  745. {
  746. EmitScalarUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  747. }
  748. public static void Neg_V(AILEmitterCtx Context)
  749. {
  750. EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  751. }
  752. public static void Raddhn_V(AILEmitterCtx Context)
  753. {
  754. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Add), Round: true);
  755. }
  756. public static void Rsubhn_V(AILEmitterCtx Context)
  757. {
  758. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: true);
  759. }
  760. public static void Saba_V(AILEmitterCtx Context)
  761. {
  762. EmitVectorTernaryOpSx(Context, () =>
  763. {
  764. Context.Emit(OpCodes.Sub);
  765. EmitAbs(Context);
  766. Context.Emit(OpCodes.Add);
  767. });
  768. }
  769. public static void Sabal_V(AILEmitterCtx Context)
  770. {
  771. EmitVectorWidenRnRmTernaryOpSx(Context, () =>
  772. {
  773. Context.Emit(OpCodes.Sub);
  774. EmitAbs(Context);
  775. Context.Emit(OpCodes.Add);
  776. });
  777. }
  778. public static void Sabd_V(AILEmitterCtx Context)
  779. {
  780. EmitVectorBinaryOpSx(Context, () =>
  781. {
  782. Context.Emit(OpCodes.Sub);
  783. EmitAbs(Context);
  784. });
  785. }
  786. public static void Sabdl_V(AILEmitterCtx Context)
  787. {
  788. EmitVectorWidenRnRmBinaryOpSx(Context, () =>
  789. {
  790. Context.Emit(OpCodes.Sub);
  791. EmitAbs(Context);
  792. });
  793. }
  794. public static void Saddw_V(AILEmitterCtx Context)
  795. {
  796. EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
  797. }
  798. public static void Smax_V(AILEmitterCtx Context)
  799. {
  800. Type[] Types = new Type[] { typeof(long), typeof(long) };
  801. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  802. EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
  803. }
  804. public static void Smaxp_V(AILEmitterCtx Context)
  805. {
  806. Type[] Types = new Type[] { typeof(long), typeof(long) };
  807. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  808. EmitVectorPairwiseOpSx(Context, () => Context.EmitCall(MthdInfo));
  809. }
  810. public static void Smin_V(AILEmitterCtx Context)
  811. {
  812. Type[] Types = new Type[] { typeof(long), typeof(long) };
  813. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  814. EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
  815. }
  816. public static void Sminp_V(AILEmitterCtx Context)
  817. {
  818. Type[] Types = new Type[] { typeof(long), typeof(long) };
  819. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  820. EmitVectorPairwiseOpSx(Context, () => Context.EmitCall(MthdInfo));
  821. }
  822. public static void Smlal_V(AILEmitterCtx Context)
  823. {
  824. EmitVectorWidenRnRmTernaryOpSx(Context, () =>
  825. {
  826. Context.Emit(OpCodes.Mul);
  827. Context.Emit(OpCodes.Add);
  828. });
  829. }
  830. public static void Smlsl_V(AILEmitterCtx Context)
  831. {
  832. EmitVectorWidenRnRmTernaryOpSx(Context, () =>
  833. {
  834. Context.Emit(OpCodes.Mul);
  835. Context.Emit(OpCodes.Sub);
  836. });
  837. }
  838. public static void Smull_V(AILEmitterCtx Context)
  839. {
  840. EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul));
  841. }
  842. public static void Sqxtn_S(AILEmitterCtx Context)
  843. {
  844. EmitScalarSaturatingNarrowOpSxSx(Context, () => { });
  845. }
  846. public static void Sqxtn_V(AILEmitterCtx Context)
  847. {
  848. EmitVectorSaturatingNarrowOpSxSx(Context, () => { });
  849. }
  850. public static void Sqxtun_S(AILEmitterCtx Context)
  851. {
  852. EmitScalarSaturatingNarrowOpSxZx(Context, () => { });
  853. }
  854. public static void Sqxtun_V(AILEmitterCtx Context)
  855. {
  856. EmitVectorSaturatingNarrowOpSxZx(Context, () => { });
  857. }
  858. public static void Sub_S(AILEmitterCtx Context)
  859. {
  860. EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  861. }
  862. public static void Sub_V(AILEmitterCtx Context)
  863. {
  864. if (AOptimizations.UseSse2)
  865. {
  866. EmitSse2Call(Context, nameof(Sse2.Subtract));
  867. }
  868. else
  869. {
  870. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  871. }
  872. }
  873. public static void Subhn_V(AILEmitterCtx Context)
  874. {
  875. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: false);
  876. }
  877. public static void Uaba_V(AILEmitterCtx Context)
  878. {
  879. EmitVectorTernaryOpZx(Context, () =>
  880. {
  881. Context.Emit(OpCodes.Sub);
  882. EmitAbs(Context);
  883. Context.Emit(OpCodes.Add);
  884. });
  885. }
  886. public static void Uabal_V(AILEmitterCtx Context)
  887. {
  888. EmitVectorWidenRnRmTernaryOpZx(Context, () =>
  889. {
  890. Context.Emit(OpCodes.Sub);
  891. EmitAbs(Context);
  892. Context.Emit(OpCodes.Add);
  893. });
  894. }
  895. public static void Uabd_V(AILEmitterCtx Context)
  896. {
  897. EmitVectorBinaryOpZx(Context, () =>
  898. {
  899. Context.Emit(OpCodes.Sub);
  900. EmitAbs(Context);
  901. });
  902. }
  903. public static void Uabdl_V(AILEmitterCtx Context)
  904. {
  905. EmitVectorWidenRnRmBinaryOpZx(Context, () =>
  906. {
  907. Context.Emit(OpCodes.Sub);
  908. EmitAbs(Context);
  909. });
  910. }
  911. public static void Uaddl_V(AILEmitterCtx Context)
  912. {
  913. EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  914. }
  915. public static void Uaddlv_V(AILEmitterCtx Context)
  916. {
  917. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  918. int Bytes = Op.GetBitsCount() >> 3;
  919. int Elems = Bytes >> Op.Size;
  920. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  921. for (int Index = 1; Index < Elems; Index++)
  922. {
  923. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  924. Context.Emit(OpCodes.Add);
  925. }
  926. EmitScalarSet(Context, Op.Rd, Op.Size + 1);
  927. }
  928. public static void Uaddw_V(AILEmitterCtx Context)
  929. {
  930. EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  931. }
  932. public static void Uhadd_V(AILEmitterCtx Context)
  933. {
  934. EmitVectorBinaryOpZx(Context, () =>
  935. {
  936. Context.Emit(OpCodes.Add);
  937. Context.EmitLdc_I4(1);
  938. Context.Emit(OpCodes.Shr_Un);
  939. });
  940. }
  941. public static void Umin_V(AILEmitterCtx Context)
  942. {
  943. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  944. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  945. EmitVectorBinaryOpZx(Context, () => Context.EmitCall(MthdInfo));
  946. }
  947. public static void Uminp_V(AILEmitterCtx Context)
  948. {
  949. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  950. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  951. EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
  952. }
  953. public static void Umax_V(AILEmitterCtx Context)
  954. {
  955. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  956. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  957. EmitVectorBinaryOpZx(Context, () => Context.EmitCall(MthdInfo));
  958. }
  959. public static void Umaxp_V(AILEmitterCtx Context)
  960. {
  961. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  962. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  963. EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
  964. }
  965. public static void Umull_V(AILEmitterCtx Context)
  966. {
  967. EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
  968. }
  969. public static void Uqxtn_S(AILEmitterCtx Context)
  970. {
  971. EmitScalarSaturatingNarrowOpZxZx(Context, () => { });
  972. }
  973. public static void Uqxtn_V(AILEmitterCtx Context)
  974. {
  975. EmitVectorSaturatingNarrowOpZxZx(Context, () => { });
  976. }
  977. }
  978. }