AInstEmitSimdArithmetic.cs 35 KB

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