AInstEmitSimdArithmetic.cs 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  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 static ChocolArm64.Instruction.AInstEmitSimdHelper;
  8. namespace ChocolArm64.Instruction
  9. {
  10. static partial class AInstEmit
  11. {
  12. public static void Abs_S(AILEmitterCtx Context)
  13. {
  14. EmitScalarUnaryOpSx(Context, () => EmitAbs(Context));
  15. }
  16. public static void Abs_V(AILEmitterCtx Context)
  17. {
  18. EmitVectorUnaryOpSx(Context, () => EmitAbs(Context));
  19. }
  20. private static void EmitAbs(AILEmitterCtx Context)
  21. {
  22. AILLabel LblTrue = new AILLabel();
  23. Context.Emit(OpCodes.Dup);
  24. Context.Emit(OpCodes.Ldc_I4_0);
  25. Context.Emit(OpCodes.Bge_S, LblTrue);
  26. Context.Emit(OpCodes.Neg);
  27. Context.MarkLabel(LblTrue);
  28. }
  29. public static void Add_S(AILEmitterCtx Context)
  30. {
  31. EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  32. }
  33. public static void Add_V(AILEmitterCtx Context)
  34. {
  35. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  36. }
  37. public static void Addhn_V(AILEmitterCtx Context)
  38. {
  39. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Add), Round: false);
  40. }
  41. public static void Addp_S(AILEmitterCtx Context)
  42. {
  43. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  44. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  45. EmitVectorExtractZx(Context, Op.Rn, 1, Op.Size);
  46. Context.Emit(OpCodes.Add);
  47. EmitScalarSet(Context, Op.Rd, Op.Size);
  48. }
  49. public static void Addp_V(AILEmitterCtx Context)
  50. {
  51. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  52. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  53. int Elems = Bytes >> Op.Size;
  54. int Half = Elems >> 1;
  55. for (int Index = 0; Index < Elems; Index++)
  56. {
  57. int Elem = (Index & (Half - 1)) << 1;
  58. EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, Op.Size);
  59. EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, Op.Size);
  60. Context.Emit(OpCodes.Add);
  61. EmitVectorInsertTmp(Context, Index, Op.Size);
  62. }
  63. Context.EmitLdvectmp();
  64. Context.EmitStvec(Op.Rd);
  65. if (Op.RegisterSize == ARegisterSize.SIMD64)
  66. {
  67. EmitVectorZeroUpper(Context, Op.Rd);
  68. }
  69. }
  70. public static void Addv_V(AILEmitterCtx Context)
  71. {
  72. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  73. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  74. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  75. for (int Index = 1; Index < (Bytes >> Op.Size); Index++)
  76. {
  77. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  78. Context.Emit(OpCodes.Add);
  79. }
  80. EmitScalarSet(Context, Op.Rd, Op.Size);
  81. }
  82. public static void Cnt_V(AILEmitterCtx Context)
  83. {
  84. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  85. int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8;
  86. for (int Index = 0; Index < Elems; Index++)
  87. {
  88. EmitVectorExtractZx(Context, Op.Rn, Index, 0);
  89. Context.Emit(OpCodes.Conv_U1);
  90. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountSetBits8));
  91. Context.Emit(OpCodes.Conv_U8);
  92. EmitVectorInsert(Context, Op.Rd, Index, 0);
  93. }
  94. if (Op.RegisterSize == ARegisterSize.SIMD64)
  95. {
  96. EmitVectorZeroUpper(Context, Op.Rd);
  97. }
  98. }
  99. private static void EmitHighNarrow(AILEmitterCtx Context, Action Emit, bool Round)
  100. {
  101. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  102. int Elems = 8 >> Op.Size;
  103. int ESize = 8 << Op.Size;
  104. int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
  105. for (int Index = 0; Index < Elems; Index++)
  106. {
  107. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
  108. EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size + 1);
  109. Emit();
  110. if (Round)
  111. {
  112. Context.EmitLdc_I8(1L << (ESize - 1));
  113. Context.Emit(OpCodes.Add);
  114. }
  115. Context.EmitLsr(ESize);
  116. EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
  117. }
  118. if (Part == 0)
  119. {
  120. EmitVectorZeroUpper(Context, Op.Rd);
  121. }
  122. }
  123. public static void Fabd_S(AILEmitterCtx Context)
  124. {
  125. EmitScalarBinaryOpF(Context, () =>
  126. {
  127. Context.Emit(OpCodes.Sub);
  128. EmitUnaryMathCall(Context, nameof(Math.Abs));
  129. });
  130. }
  131. public static void Fabs_S(AILEmitterCtx Context)
  132. {
  133. EmitScalarUnaryOpF(Context, () =>
  134. {
  135. EmitUnaryMathCall(Context, nameof(Math.Abs));
  136. });
  137. }
  138. public static void Fadd_S(AILEmitterCtx Context)
  139. {
  140. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
  141. }
  142. public static void Fadd_V(AILEmitterCtx Context)
  143. {
  144. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
  145. }
  146. public static void Faddp_V(AILEmitterCtx Context)
  147. {
  148. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  149. int SizeF = Op.Size & 1;
  150. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  151. int Elems = Bytes >> SizeF + 2;
  152. int Half = Elems >> 1;
  153. for (int Index = 0; Index < Elems; Index++)
  154. {
  155. int Elem = (Index & (Half - 1)) << 1;
  156. EmitVectorExtractF(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, SizeF);
  157. EmitVectorExtractF(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, SizeF);
  158. Context.Emit(OpCodes.Add);
  159. EmitVectorInsertTmpF(Context, Index, SizeF);
  160. }
  161. Context.EmitLdvectmp();
  162. Context.EmitStvec(Op.Rd);
  163. if (Op.RegisterSize == ARegisterSize.SIMD64)
  164. {
  165. EmitVectorZeroUpper(Context, Op.Rd);
  166. }
  167. }
  168. public static void Fdiv_S(AILEmitterCtx Context)
  169. {
  170. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
  171. }
  172. public static void Fdiv_V(AILEmitterCtx Context)
  173. {
  174. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
  175. }
  176. public static void Fmadd_S(AILEmitterCtx Context)
  177. {
  178. EmitScalarTernaryRaOpF(Context, () =>
  179. {
  180. Context.Emit(OpCodes.Mul);
  181. Context.Emit(OpCodes.Add);
  182. });
  183. }
  184. public static void Fmax_S(AILEmitterCtx Context)
  185. {
  186. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  187. EmitScalarBinaryOpF(Context, () =>
  188. {
  189. if (Op.Size == 0)
  190. {
  191. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MaxF));
  192. }
  193. else if (Op.Size == 1)
  194. {
  195. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Max));
  196. }
  197. else
  198. {
  199. throw new InvalidOperationException();
  200. }
  201. });
  202. }
  203. public static void Fmax_V(AILEmitterCtx Context)
  204. {
  205. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  206. EmitVectorBinaryOpF(Context, () =>
  207. {
  208. if (Op.Size == 0)
  209. {
  210. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MaxF));
  211. }
  212. else if (Op.Size == 1)
  213. {
  214. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Max));
  215. }
  216. else
  217. {
  218. throw new InvalidOperationException();
  219. }
  220. });
  221. }
  222. public static void Fmin_S(AILEmitterCtx Context)
  223. {
  224. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  225. EmitScalarBinaryOpF(Context, () =>
  226. {
  227. if (Op.Size == 0)
  228. {
  229. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MinF));
  230. }
  231. else if (Op.Size == 1)
  232. {
  233. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Min));
  234. }
  235. else
  236. {
  237. throw new InvalidOperationException();
  238. }
  239. });
  240. }
  241. public static void Fmin_V(AILEmitterCtx Context)
  242. {
  243. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  244. int SizeF = Op.Size & 1;
  245. EmitVectorBinaryOpF(Context, () =>
  246. {
  247. if (SizeF == 0)
  248. {
  249. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MinF));
  250. }
  251. else if (SizeF == 1)
  252. {
  253. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Min));
  254. }
  255. else
  256. {
  257. throw new InvalidOperationException();
  258. }
  259. });
  260. }
  261. public static void Fmaxnm_S(AILEmitterCtx Context)
  262. {
  263. Fmax_S(Context);
  264. }
  265. public static void Fminnm_S(AILEmitterCtx Context)
  266. {
  267. Fmin_S(Context);
  268. }
  269. public static void Fmla_V(AILEmitterCtx Context)
  270. {
  271. EmitVectorTernaryOpF(Context, () =>
  272. {
  273. Context.Emit(OpCodes.Mul);
  274. Context.Emit(OpCodes.Add);
  275. });
  276. }
  277. public static void Fmla_Ve(AILEmitterCtx Context)
  278. {
  279. EmitVectorTernaryOpByElemF(Context, () =>
  280. {
  281. Context.Emit(OpCodes.Mul);
  282. Context.Emit(OpCodes.Add);
  283. });
  284. }
  285. public static void Fmls_V(AILEmitterCtx Context)
  286. {
  287. EmitVectorTernaryOpF(Context, () =>
  288. {
  289. Context.Emit(OpCodes.Mul);
  290. Context.Emit(OpCodes.Sub);
  291. });
  292. }
  293. public static void Fmls_Ve(AILEmitterCtx Context)
  294. {
  295. EmitVectorTernaryOpByElemF(Context, () =>
  296. {
  297. Context.Emit(OpCodes.Mul);
  298. Context.Emit(OpCodes.Sub);
  299. });
  300. }
  301. public static void Fmsub_S(AILEmitterCtx Context)
  302. {
  303. EmitScalarTernaryRaOpF(Context, () =>
  304. {
  305. Context.Emit(OpCodes.Mul);
  306. Context.Emit(OpCodes.Sub);
  307. });
  308. }
  309. public static void Fmul_S(AILEmitterCtx Context)
  310. {
  311. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
  312. }
  313. public static void Fmul_Se(AILEmitterCtx Context)
  314. {
  315. EmitScalarBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
  316. }
  317. public static void Fmul_V(AILEmitterCtx Context)
  318. {
  319. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
  320. }
  321. public static void Fmul_Ve(AILEmitterCtx Context)
  322. {
  323. EmitVectorBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
  324. }
  325. public static void Fneg_S(AILEmitterCtx Context)
  326. {
  327. EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
  328. }
  329. public static void Fneg_V(AILEmitterCtx Context)
  330. {
  331. EmitVectorUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
  332. }
  333. public static void Fnmadd_S(AILEmitterCtx Context)
  334. {
  335. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  336. int SizeF = Op.Size & 1;
  337. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  338. Context.Emit(OpCodes.Neg);
  339. EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
  340. Context.Emit(OpCodes.Mul);
  341. EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
  342. Context.Emit(OpCodes.Sub);
  343. EmitScalarSetF(Context, Op.Rd, SizeF);
  344. }
  345. public static void Fnmsub_S(AILEmitterCtx Context)
  346. {
  347. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  348. int SizeF = Op.Size & 1;
  349. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  350. EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
  351. Context.Emit(OpCodes.Mul);
  352. EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
  353. Context.Emit(OpCodes.Sub);
  354. EmitScalarSetF(Context, Op.Rd, SizeF);
  355. }
  356. public static void Fnmul_S(AILEmitterCtx Context)
  357. {
  358. EmitScalarBinaryOpF(Context, () =>
  359. {
  360. Context.Emit(OpCodes.Mul);
  361. Context.Emit(OpCodes.Neg);
  362. });
  363. }
  364. public static void Frecpe_S(AILEmitterCtx Context)
  365. {
  366. EmitFrecpe(Context, 0, Scalar: true);
  367. }
  368. public static void Frecpe_V(AILEmitterCtx Context)
  369. {
  370. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  371. int SizeF = Op.Size & 1;
  372. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  373. for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
  374. {
  375. EmitFrecpe(Context, Index, Scalar: false);
  376. }
  377. if (Op.RegisterSize == ARegisterSize.SIMD64)
  378. {
  379. EmitVectorZeroUpper(Context, Op.Rd);
  380. }
  381. }
  382. private static void EmitFrecpe(AILEmitterCtx Context, int Index, bool Scalar)
  383. {
  384. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  385. int SizeF = Op.Size & 1;
  386. if (SizeF == 0)
  387. {
  388. Context.EmitLdc_R4(1);
  389. }
  390. else /* if (SizeF == 1) */
  391. {
  392. Context.EmitLdc_R8(1);
  393. }
  394. EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
  395. Context.Emit(OpCodes.Div);
  396. if (Scalar)
  397. {
  398. EmitVectorZeroAll(Context, Op.Rd);
  399. }
  400. EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
  401. }
  402. public static void Frecps_S(AILEmitterCtx Context)
  403. {
  404. EmitFrecps(Context, 0, Scalar: true);
  405. }
  406. public static void Frecps_V(AILEmitterCtx Context)
  407. {
  408. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  409. int SizeF = Op.Size & 1;
  410. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  411. for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
  412. {
  413. EmitFrecps(Context, Index, Scalar: false);
  414. }
  415. if (Op.RegisterSize == ARegisterSize.SIMD64)
  416. {
  417. EmitVectorZeroUpper(Context, Op.Rd);
  418. }
  419. }
  420. private static void EmitFrecps(AILEmitterCtx Context, int Index, bool Scalar)
  421. {
  422. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  423. int SizeF = Op.Size & 1;
  424. if (SizeF == 0)
  425. {
  426. Context.EmitLdc_R4(2);
  427. }
  428. else /* if (SizeF == 1) */
  429. {
  430. Context.EmitLdc_R8(2);
  431. }
  432. EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
  433. EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
  434. Context.Emit(OpCodes.Mul);
  435. Context.Emit(OpCodes.Sub);
  436. if (Scalar)
  437. {
  438. EmitVectorZeroAll(Context, Op.Rd);
  439. }
  440. EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
  441. }
  442. public static void Frinta_S(AILEmitterCtx Context)
  443. {
  444. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  445. EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
  446. EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
  447. EmitScalarSetF(Context, Op.Rd, Op.Size);
  448. }
  449. public static void Frinta_V(AILEmitterCtx Context)
  450. {
  451. EmitVectorUnaryOpF(Context, () =>
  452. {
  453. EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
  454. });
  455. }
  456. public static void Frinti_S(AILEmitterCtx Context)
  457. {
  458. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  459. EmitScalarUnaryOpF(Context, () =>
  460. {
  461. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  462. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  463. if (Op.Size == 0)
  464. {
  465. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF));
  466. }
  467. else if (Op.Size == 1)
  468. {
  469. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round));
  470. }
  471. else
  472. {
  473. throw new InvalidOperationException();
  474. }
  475. });
  476. }
  477. public static void Frinti_V(AILEmitterCtx Context)
  478. {
  479. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  480. int SizeF = Op.Size & 1;
  481. EmitVectorUnaryOpF(Context, () =>
  482. {
  483. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  484. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  485. if (SizeF == 0)
  486. {
  487. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF));
  488. }
  489. else if (SizeF == 1)
  490. {
  491. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round));
  492. }
  493. else
  494. {
  495. throw new InvalidOperationException();
  496. }
  497. });
  498. }
  499. public static void Frintm_S(AILEmitterCtx Context)
  500. {
  501. EmitScalarUnaryOpF(Context, () =>
  502. {
  503. EmitUnaryMathCall(Context, nameof(Math.Floor));
  504. });
  505. }
  506. public static void Frintm_V(AILEmitterCtx Context)
  507. {
  508. EmitVectorUnaryOpF(Context, () =>
  509. {
  510. EmitUnaryMathCall(Context, nameof(Math.Floor));
  511. });
  512. }
  513. public static void Frintn_S(AILEmitterCtx Context)
  514. {
  515. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  516. EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
  517. EmitRoundMathCall(Context, MidpointRounding.ToEven);
  518. EmitScalarSetF(Context, Op.Rd, Op.Size);
  519. }
  520. public static void Frintn_V(AILEmitterCtx Context)
  521. {
  522. EmitVectorUnaryOpF(Context, () =>
  523. {
  524. EmitRoundMathCall(Context, MidpointRounding.ToEven);
  525. });
  526. }
  527. public static void Frintp_S(AILEmitterCtx Context)
  528. {
  529. EmitScalarUnaryOpF(Context, () =>
  530. {
  531. EmitUnaryMathCall(Context, nameof(Math.Ceiling));
  532. });
  533. }
  534. public static void Frintp_V(AILEmitterCtx Context)
  535. {
  536. EmitVectorUnaryOpF(Context, () =>
  537. {
  538. EmitUnaryMathCall(Context, nameof(Math.Ceiling));
  539. });
  540. }
  541. public static void Frintx_S(AILEmitterCtx Context)
  542. {
  543. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  544. EmitScalarUnaryOpF(Context, () =>
  545. {
  546. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  547. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  548. if (Op.Size == 0)
  549. {
  550. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF));
  551. }
  552. else if (Op.Size == 1)
  553. {
  554. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round));
  555. }
  556. else
  557. {
  558. throw new InvalidOperationException();
  559. }
  560. });
  561. }
  562. public static void Frintx_V(AILEmitterCtx Context)
  563. {
  564. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  565. EmitVectorUnaryOpF(Context, () =>
  566. {
  567. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  568. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  569. if (Op.Size == 0)
  570. {
  571. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF));
  572. }
  573. else if (Op.Size == 1)
  574. {
  575. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round));
  576. }
  577. else
  578. {
  579. throw new InvalidOperationException();
  580. }
  581. });
  582. }
  583. public static void Frsqrte_S(AILEmitterCtx Context)
  584. {
  585. EmitScalarUnaryOpF(Context, () =>
  586. {
  587. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
  588. });
  589. }
  590. public static void Frsqrte_V(AILEmitterCtx Context)
  591. {
  592. EmitVectorUnaryOpF(Context, () =>
  593. {
  594. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
  595. });
  596. }
  597. public static void Frsqrts_S(AILEmitterCtx Context)
  598. {
  599. EmitFrsqrts(Context, 0, Scalar: true);
  600. }
  601. public static void Frsqrts_V(AILEmitterCtx Context)
  602. {
  603. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  604. int SizeF = Op.Size & 1;
  605. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  606. for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
  607. {
  608. EmitFrsqrts(Context, Index, Scalar: false);
  609. }
  610. if (Op.RegisterSize == ARegisterSize.SIMD64)
  611. {
  612. EmitVectorZeroUpper(Context, Op.Rd);
  613. }
  614. }
  615. private static void EmitFrsqrts(AILEmitterCtx Context, int Index, bool Scalar)
  616. {
  617. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  618. int SizeF = Op.Size & 1;
  619. if (SizeF == 0)
  620. {
  621. Context.EmitLdc_R4(3);
  622. }
  623. else /* if (SizeF == 1) */
  624. {
  625. Context.EmitLdc_R8(3);
  626. }
  627. EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
  628. EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
  629. Context.Emit(OpCodes.Mul);
  630. Context.Emit(OpCodes.Sub);
  631. if (SizeF == 0)
  632. {
  633. Context.EmitLdc_R4(0.5f);
  634. }
  635. else /* if (SizeF == 1) */
  636. {
  637. Context.EmitLdc_R8(0.5);
  638. }
  639. Context.Emit(OpCodes.Mul);
  640. if (Scalar)
  641. {
  642. EmitVectorZeroAll(Context, Op.Rd);
  643. }
  644. EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
  645. }
  646. public static void Fsqrt_S(AILEmitterCtx Context)
  647. {
  648. EmitScalarUnaryOpF(Context, () =>
  649. {
  650. EmitUnaryMathCall(Context, nameof(Math.Sqrt));
  651. });
  652. }
  653. public static void Fsub_S(AILEmitterCtx Context)
  654. {
  655. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
  656. }
  657. public static void Fsub_V(AILEmitterCtx Context)
  658. {
  659. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
  660. }
  661. public static void Mla_V(AILEmitterCtx Context)
  662. {
  663. EmitVectorTernaryOpZx(Context, () =>
  664. {
  665. Context.Emit(OpCodes.Mul);
  666. Context.Emit(OpCodes.Add);
  667. });
  668. }
  669. public static void Mla_Ve(AILEmitterCtx Context)
  670. {
  671. EmitVectorTernaryOpByElemZx(Context, () =>
  672. {
  673. Context.Emit(OpCodes.Mul);
  674. Context.Emit(OpCodes.Add);
  675. });
  676. }
  677. public static void Mls_V(AILEmitterCtx Context)
  678. {
  679. EmitVectorTernaryOpZx(Context, () =>
  680. {
  681. Context.Emit(OpCodes.Mul);
  682. Context.Emit(OpCodes.Sub);
  683. });
  684. }
  685. public static void Mul_V(AILEmitterCtx Context)
  686. {
  687. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
  688. }
  689. public static void Mul_Ve(AILEmitterCtx Context)
  690. {
  691. EmitVectorBinaryOpByElemZx(Context, () => Context.Emit(OpCodes.Mul));
  692. }
  693. public static void Neg_S(AILEmitterCtx Context)
  694. {
  695. EmitScalarUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  696. }
  697. public static void Neg_V(AILEmitterCtx Context)
  698. {
  699. EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  700. }
  701. public static void Raddhn_V(AILEmitterCtx Context)
  702. {
  703. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Add), Round: true);
  704. }
  705. public static void Rsubhn_V(AILEmitterCtx Context)
  706. {
  707. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: true);
  708. }
  709. public static void Saddw_V(AILEmitterCtx Context)
  710. {
  711. EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
  712. }
  713. public static void Smax_V(AILEmitterCtx Context)
  714. {
  715. Type[] Types = new Type[] { typeof(long), typeof(long) };
  716. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  717. EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
  718. }
  719. public static void Smin_V(AILEmitterCtx Context)
  720. {
  721. Type[] Types = new Type[] { typeof(long), typeof(long) };
  722. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  723. EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
  724. }
  725. public static void Smlal_V(AILEmitterCtx Context)
  726. {
  727. EmitVectorWidenRnRmTernaryOpSx(Context, () =>
  728. {
  729. Context.Emit(OpCodes.Mul);
  730. Context.Emit(OpCodes.Add);
  731. });
  732. }
  733. public static void Smull_V(AILEmitterCtx Context)
  734. {
  735. EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul));
  736. }
  737. public static void Sub_S(AILEmitterCtx Context)
  738. {
  739. EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  740. }
  741. public static void Sub_V(AILEmitterCtx Context)
  742. {
  743. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  744. }
  745. public static void Subhn_V(AILEmitterCtx Context)
  746. {
  747. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: false);
  748. }
  749. public static void Uabd_V(AILEmitterCtx Context)
  750. {
  751. EmitVectorBinaryOpZx(Context, () => EmitAbd(Context));
  752. }
  753. public static void Uabdl_V(AILEmitterCtx Context)
  754. {
  755. EmitVectorWidenRnRmBinaryOpZx(Context, () => EmitAbd(Context));
  756. }
  757. private static void EmitAbd(AILEmitterCtx Context)
  758. {
  759. Context.Emit(OpCodes.Sub);
  760. Type[] Types = new Type[] { typeof(long) };
  761. Context.EmitCall(typeof(Math).GetMethod(nameof(Math.Abs), Types));
  762. }
  763. public static void Uaddl_V(AILEmitterCtx Context)
  764. {
  765. EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  766. }
  767. public static void Uaddlv_V(AILEmitterCtx Context)
  768. {
  769. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  770. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  771. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  772. for (int Index = 1; Index < (Bytes >> Op.Size); Index++)
  773. {
  774. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  775. Context.Emit(OpCodes.Add);
  776. }
  777. EmitScalarSet(Context, Op.Rd, Op.Size + 1);
  778. }
  779. public static void Uaddw_V(AILEmitterCtx Context)
  780. {
  781. EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  782. }
  783. public static void Uhadd_V(AILEmitterCtx Context)
  784. {
  785. EmitVectorBinaryOpZx(Context, () =>
  786. {
  787. Context.Emit(OpCodes.Add);
  788. Context.EmitLdc_I4(1);
  789. Context.Emit(OpCodes.Shr_Un);
  790. });
  791. }
  792. public static void Umull_V(AILEmitterCtx Context)
  793. {
  794. EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
  795. }
  796. }
  797. }