AInstEmitSimdArithmetic.cs 37 KB

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