AInstEmitSimdArithmetic.cs 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487
  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. public static void Fabd_S(AILEmitterCtx Context)
  111. {
  112. EmitScalarBinaryOpF(Context, () =>
  113. {
  114. Context.Emit(OpCodes.Sub);
  115. EmitUnaryMathCall(Context, nameof(Math.Abs));
  116. });
  117. }
  118. public static void Fabs_S(AILEmitterCtx Context)
  119. {
  120. EmitScalarUnaryOpF(Context, () =>
  121. {
  122. EmitUnaryMathCall(Context, nameof(Math.Abs));
  123. });
  124. }
  125. public static void Fabs_V(AILEmitterCtx Context)
  126. {
  127. EmitVectorUnaryOpF(Context, () =>
  128. {
  129. EmitUnaryMathCall(Context, nameof(Math.Abs));
  130. });
  131. }
  132. public static void Fadd_S(AILEmitterCtx Context)
  133. {
  134. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  135. {
  136. EmitScalarSseOrSse2CallF(Context, nameof(Sse.AddScalar));
  137. }
  138. else
  139. {
  140. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
  141. }
  142. }
  143. public static void Fadd_V(AILEmitterCtx Context)
  144. {
  145. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  146. {
  147. EmitVectorSseOrSse2CallF(Context, nameof(Sse.Add));
  148. }
  149. else
  150. {
  151. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
  152. }
  153. }
  154. public static void Faddp_S(AILEmitterCtx Context)
  155. {
  156. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  157. int SizeF = Op.Size & 1;
  158. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  159. EmitVectorExtractF(Context, Op.Rn, 1, SizeF);
  160. Context.Emit(OpCodes.Add);
  161. EmitScalarSetF(Context, Op.Rd, SizeF);
  162. }
  163. public static void Faddp_V(AILEmitterCtx Context)
  164. {
  165. EmitVectorPairwiseOpF(Context, () => Context.Emit(OpCodes.Add));
  166. }
  167. public static void Fdiv_S(AILEmitterCtx Context)
  168. {
  169. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  170. {
  171. EmitScalarSseOrSse2CallF(Context, nameof(Sse.DivideScalar));
  172. }
  173. else
  174. {
  175. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
  176. }
  177. }
  178. public static void Fdiv_V(AILEmitterCtx Context)
  179. {
  180. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  181. {
  182. EmitVectorSseOrSse2CallF(Context, nameof(Sse.Divide));
  183. }
  184. else
  185. {
  186. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
  187. }
  188. }
  189. public static void Fmadd_S(AILEmitterCtx Context)
  190. {
  191. EmitScalarTernaryRaOpF(Context, () =>
  192. {
  193. Context.Emit(OpCodes.Mul);
  194. Context.Emit(OpCodes.Add);
  195. });
  196. }
  197. public static void Fmax_S(AILEmitterCtx Context)
  198. {
  199. EmitScalarBinaryOpF(Context, () =>
  200. {
  201. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.Max));
  202. });
  203. }
  204. public static void Fmax_V(AILEmitterCtx Context)
  205. {
  206. EmitVectorBinaryOpF(Context, () =>
  207. {
  208. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.Max));
  209. });
  210. }
  211. public static void Fmaxnm_S(AILEmitterCtx Context)
  212. {
  213. EmitScalarBinaryOpF(Context, () =>
  214. {
  215. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.MaxNum));
  216. });
  217. }
  218. public static void Fmaxnm_V(AILEmitterCtx Context)
  219. {
  220. EmitVectorBinaryOpF(Context, () =>
  221. {
  222. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.MaxNum));
  223. });
  224. }
  225. public static void Fmaxp_V(AILEmitterCtx Context)
  226. {
  227. EmitVectorPairwiseOpF(Context, () => EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.Max)));
  228. }
  229. public static void Fmin_S(AILEmitterCtx Context)
  230. {
  231. EmitScalarBinaryOpF(Context, () =>
  232. {
  233. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.Min));
  234. });
  235. }
  236. public static void Fmin_V(AILEmitterCtx Context)
  237. {
  238. EmitVectorBinaryOpF(Context, () =>
  239. {
  240. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.Min));
  241. });
  242. }
  243. public static void Fminnm_S(AILEmitterCtx Context)
  244. {
  245. EmitScalarBinaryOpF(Context, () =>
  246. {
  247. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.MinNum));
  248. });
  249. }
  250. public static void Fminnm_V(AILEmitterCtx Context)
  251. {
  252. EmitVectorBinaryOpF(Context, () =>
  253. {
  254. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.MinNum));
  255. });
  256. }
  257. public static void Fminp_V(AILEmitterCtx Context)
  258. {
  259. EmitVectorPairwiseOpF(Context, () => EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.Min)));
  260. }
  261. public static void Fmla_Se(AILEmitterCtx Context)
  262. {
  263. EmitScalarTernaryOpByElemF(Context, () =>
  264. {
  265. Context.Emit(OpCodes.Mul);
  266. Context.Emit(OpCodes.Add);
  267. });
  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. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  312. {
  313. EmitScalarSseOrSse2CallF(Context, nameof(Sse.MultiplyScalar));
  314. }
  315. else
  316. {
  317. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
  318. }
  319. }
  320. public static void Fmul_Se(AILEmitterCtx Context)
  321. {
  322. EmitScalarBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
  323. }
  324. public static void Fmul_V(AILEmitterCtx Context)
  325. {
  326. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  327. {
  328. EmitVectorSseOrSse2CallF(Context, nameof(Sse.Multiply));
  329. }
  330. else
  331. {
  332. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
  333. }
  334. }
  335. public static void Fmul_Ve(AILEmitterCtx Context)
  336. {
  337. EmitVectorBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
  338. }
  339. public static void Fneg_S(AILEmitterCtx Context)
  340. {
  341. EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
  342. }
  343. public static void Fneg_V(AILEmitterCtx Context)
  344. {
  345. EmitVectorUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
  346. }
  347. public static void Fnmadd_S(AILEmitterCtx Context)
  348. {
  349. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  350. int SizeF = Op.Size & 1;
  351. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  352. Context.Emit(OpCodes.Neg);
  353. EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
  354. Context.Emit(OpCodes.Mul);
  355. EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
  356. Context.Emit(OpCodes.Sub);
  357. EmitScalarSetF(Context, Op.Rd, SizeF);
  358. }
  359. public static void Fnmsub_S(AILEmitterCtx Context)
  360. {
  361. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  362. int SizeF = Op.Size & 1;
  363. EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
  364. EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
  365. Context.Emit(OpCodes.Mul);
  366. EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
  367. Context.Emit(OpCodes.Sub);
  368. EmitScalarSetF(Context, Op.Rd, SizeF);
  369. }
  370. public static void Fnmul_S(AILEmitterCtx Context)
  371. {
  372. EmitScalarBinaryOpF(Context, () =>
  373. {
  374. Context.Emit(OpCodes.Mul);
  375. Context.Emit(OpCodes.Neg);
  376. });
  377. }
  378. public static void Frecpe_S(AILEmitterCtx Context)
  379. {
  380. EmitScalarUnaryOpF(Context, () =>
  381. {
  382. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.RecipEstimate));
  383. });
  384. }
  385. public static void Frecpe_V(AILEmitterCtx Context)
  386. {
  387. EmitVectorUnaryOpF(Context, () =>
  388. {
  389. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.RecipEstimate));
  390. });
  391. }
  392. public static void Frecps_S(AILEmitterCtx Context)
  393. {
  394. EmitScalarBinaryOpF(Context, () =>
  395. {
  396. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.RecipStep));
  397. });
  398. }
  399. public static void Frecps_V(AILEmitterCtx Context)
  400. {
  401. EmitVectorBinaryOpF(Context, () =>
  402. {
  403. EmitBinarySoftFloatCall(Context, nameof(ASoftFloat.RecipStep));
  404. });
  405. }
  406. public static void Frinta_S(AILEmitterCtx Context)
  407. {
  408. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  409. EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
  410. EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
  411. EmitScalarSetF(Context, Op.Rd, Op.Size);
  412. }
  413. public static void Frinta_V(AILEmitterCtx Context)
  414. {
  415. EmitVectorUnaryOpF(Context, () =>
  416. {
  417. EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
  418. });
  419. }
  420. public static void Frinti_S(AILEmitterCtx Context)
  421. {
  422. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  423. EmitScalarUnaryOpF(Context, () =>
  424. {
  425. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  426. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  427. if (Op.Size == 0)
  428. {
  429. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  430. }
  431. else if (Op.Size == 1)
  432. {
  433. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  434. }
  435. else
  436. {
  437. throw new InvalidOperationException();
  438. }
  439. });
  440. }
  441. public static void Frinti_V(AILEmitterCtx Context)
  442. {
  443. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  444. int SizeF = Op.Size & 1;
  445. EmitVectorUnaryOpF(Context, () =>
  446. {
  447. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  448. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  449. if (SizeF == 0)
  450. {
  451. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  452. }
  453. else if (SizeF == 1)
  454. {
  455. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  456. }
  457. else
  458. {
  459. throw new InvalidOperationException();
  460. }
  461. });
  462. }
  463. public static void Frintm_S(AILEmitterCtx Context)
  464. {
  465. EmitScalarUnaryOpF(Context, () =>
  466. {
  467. EmitUnaryMathCall(Context, nameof(Math.Floor));
  468. });
  469. }
  470. public static void Frintm_V(AILEmitterCtx Context)
  471. {
  472. EmitVectorUnaryOpF(Context, () =>
  473. {
  474. EmitUnaryMathCall(Context, nameof(Math.Floor));
  475. });
  476. }
  477. public static void Frintn_S(AILEmitterCtx Context)
  478. {
  479. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  480. EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
  481. EmitRoundMathCall(Context, MidpointRounding.ToEven);
  482. EmitScalarSetF(Context, Op.Rd, Op.Size);
  483. }
  484. public static void Frintn_V(AILEmitterCtx Context)
  485. {
  486. EmitVectorUnaryOpF(Context, () =>
  487. {
  488. EmitRoundMathCall(Context, MidpointRounding.ToEven);
  489. });
  490. }
  491. public static void Frintp_S(AILEmitterCtx Context)
  492. {
  493. EmitScalarUnaryOpF(Context, () =>
  494. {
  495. EmitUnaryMathCall(Context, nameof(Math.Ceiling));
  496. });
  497. }
  498. public static void Frintp_V(AILEmitterCtx Context)
  499. {
  500. EmitVectorUnaryOpF(Context, () =>
  501. {
  502. EmitUnaryMathCall(Context, nameof(Math.Ceiling));
  503. });
  504. }
  505. public static void Frintx_S(AILEmitterCtx Context)
  506. {
  507. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  508. EmitScalarUnaryOpF(Context, () =>
  509. {
  510. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  511. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  512. if (Op.Size == 0)
  513. {
  514. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  515. }
  516. else if (Op.Size == 1)
  517. {
  518. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  519. }
  520. else
  521. {
  522. throw new InvalidOperationException();
  523. }
  524. });
  525. }
  526. public static void Frintx_V(AILEmitterCtx Context)
  527. {
  528. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  529. EmitVectorUnaryOpF(Context, () =>
  530. {
  531. Context.EmitLdarg(ATranslatedSub.StateArgIdx);
  532. Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
  533. if (Op.Size == 0)
  534. {
  535. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.RoundF));
  536. }
  537. else if (Op.Size == 1)
  538. {
  539. AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Round));
  540. }
  541. else
  542. {
  543. throw new InvalidOperationException();
  544. }
  545. });
  546. }
  547. public static void Frsqrte_S(AILEmitterCtx Context)
  548. {
  549. EmitScalarUnaryOpF(Context, () =>
  550. {
  551. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
  552. });
  553. }
  554. public static void Frsqrte_V(AILEmitterCtx Context)
  555. {
  556. EmitVectorUnaryOpF(Context, () =>
  557. {
  558. EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
  559. });
  560. }
  561. public static void Frsqrts_S(AILEmitterCtx Context)
  562. {
  563. EmitFrsqrts(Context, 0, Scalar: true);
  564. }
  565. public static void Frsqrts_V(AILEmitterCtx Context)
  566. {
  567. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  568. int SizeF = Op.Size & 1;
  569. int Bytes = Op.GetBitsCount() >> 3;
  570. for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
  571. {
  572. EmitFrsqrts(Context, Index, Scalar: false);
  573. }
  574. if (Op.RegisterSize == ARegisterSize.SIMD64)
  575. {
  576. EmitVectorZeroUpper(Context, Op.Rd);
  577. }
  578. }
  579. private static void EmitFrsqrts(AILEmitterCtx Context, int Index, bool Scalar)
  580. {
  581. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  582. int SizeF = Op.Size & 1;
  583. if (SizeF == 0)
  584. {
  585. Context.EmitLdc_R4(3);
  586. }
  587. else /* if (SizeF == 1) */
  588. {
  589. Context.EmitLdc_R8(3);
  590. }
  591. EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
  592. EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
  593. Context.Emit(OpCodes.Mul);
  594. Context.Emit(OpCodes.Sub);
  595. if (SizeF == 0)
  596. {
  597. Context.EmitLdc_R4(0.5f);
  598. }
  599. else /* if (SizeF == 1) */
  600. {
  601. Context.EmitLdc_R8(0.5);
  602. }
  603. Context.Emit(OpCodes.Mul);
  604. if (Scalar)
  605. {
  606. EmitVectorZeroAll(Context, Op.Rd);
  607. }
  608. EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
  609. }
  610. public static void Fsqrt_S(AILEmitterCtx Context)
  611. {
  612. EmitScalarUnaryOpF(Context, () =>
  613. {
  614. EmitUnaryMathCall(Context, nameof(Math.Sqrt));
  615. });
  616. }
  617. public static void Fsub_S(AILEmitterCtx Context)
  618. {
  619. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  620. {
  621. EmitScalarSseOrSse2CallF(Context, nameof(Sse.SubtractScalar));
  622. }
  623. else
  624. {
  625. EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
  626. }
  627. }
  628. public static void Fsub_V(AILEmitterCtx Context)
  629. {
  630. if (AOptimizations.UseSse && AOptimizations.UseSse2)
  631. {
  632. EmitVectorSseOrSse2CallF(Context, nameof(Sse.Subtract));
  633. }
  634. else
  635. {
  636. EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Sub));
  637. }
  638. }
  639. public static void Mla_V(AILEmitterCtx Context)
  640. {
  641. EmitVectorTernaryOpZx(Context, () =>
  642. {
  643. Context.Emit(OpCodes.Mul);
  644. Context.Emit(OpCodes.Add);
  645. });
  646. }
  647. public static void Mla_Ve(AILEmitterCtx Context)
  648. {
  649. EmitVectorTernaryOpByElemZx(Context, () =>
  650. {
  651. Context.Emit(OpCodes.Mul);
  652. Context.Emit(OpCodes.Add);
  653. });
  654. }
  655. public static void Mls_V(AILEmitterCtx Context)
  656. {
  657. EmitVectorTernaryOpZx(Context, () =>
  658. {
  659. Context.Emit(OpCodes.Mul);
  660. Context.Emit(OpCodes.Sub);
  661. });
  662. }
  663. public static void Mls_Ve(AILEmitterCtx Context)
  664. {
  665. EmitVectorTernaryOpByElemZx(Context, () =>
  666. {
  667. Context.Emit(OpCodes.Mul);
  668. Context.Emit(OpCodes.Sub);
  669. });
  670. }
  671. public static void Mul_V(AILEmitterCtx Context)
  672. {
  673. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
  674. }
  675. public static void Mul_Ve(AILEmitterCtx Context)
  676. {
  677. EmitVectorBinaryOpByElemZx(Context, () => Context.Emit(OpCodes.Mul));
  678. }
  679. public static void Neg_S(AILEmitterCtx Context)
  680. {
  681. EmitScalarUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  682. }
  683. public static void Neg_V(AILEmitterCtx Context)
  684. {
  685. EmitVectorUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  686. }
  687. public static void Raddhn_V(AILEmitterCtx Context)
  688. {
  689. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Add), Round: true);
  690. }
  691. public static void Rsubhn_V(AILEmitterCtx Context)
  692. {
  693. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: true);
  694. }
  695. public static void Saba_V(AILEmitterCtx Context)
  696. {
  697. EmitVectorTernaryOpSx(Context, () =>
  698. {
  699. Context.Emit(OpCodes.Sub);
  700. EmitAbs(Context);
  701. Context.Emit(OpCodes.Add);
  702. });
  703. }
  704. public static void Sabal_V(AILEmitterCtx Context)
  705. {
  706. EmitVectorWidenRnRmTernaryOpSx(Context, () =>
  707. {
  708. Context.Emit(OpCodes.Sub);
  709. EmitAbs(Context);
  710. Context.Emit(OpCodes.Add);
  711. });
  712. }
  713. public static void Sabd_V(AILEmitterCtx Context)
  714. {
  715. EmitVectorBinaryOpSx(Context, () =>
  716. {
  717. Context.Emit(OpCodes.Sub);
  718. EmitAbs(Context);
  719. });
  720. }
  721. public static void Sabdl_V(AILEmitterCtx Context)
  722. {
  723. EmitVectorWidenRnRmBinaryOpSx(Context, () =>
  724. {
  725. Context.Emit(OpCodes.Sub);
  726. EmitAbs(Context);
  727. });
  728. }
  729. public static void Sadalp_V(AILEmitterCtx Context)
  730. {
  731. EmitAddLongPairwise(Context, Signed: true, Accumulate: true);
  732. }
  733. public static void Saddl_V(AILEmitterCtx Context)
  734. {
  735. EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
  736. }
  737. public static void Saddlp_V(AILEmitterCtx Context)
  738. {
  739. EmitAddLongPairwise(Context, Signed: true, Accumulate: false);
  740. }
  741. public static void Saddw_V(AILEmitterCtx Context)
  742. {
  743. EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Add));
  744. }
  745. public static void Shadd_V(AILEmitterCtx Context)
  746. {
  747. EmitVectorBinaryOpSx(Context, () =>
  748. {
  749. Context.Emit(OpCodes.Add);
  750. Context.Emit(OpCodes.Ldc_I4_1);
  751. Context.Emit(OpCodes.Shr);
  752. });
  753. }
  754. public static void Shsub_V(AILEmitterCtx Context)
  755. {
  756. EmitVectorBinaryOpSx(Context, () =>
  757. {
  758. Context.Emit(OpCodes.Sub);
  759. Context.Emit(OpCodes.Ldc_I4_1);
  760. Context.Emit(OpCodes.Shr);
  761. });
  762. }
  763. public static void Smax_V(AILEmitterCtx Context)
  764. {
  765. Type[] Types = new Type[] { typeof(long), typeof(long) };
  766. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  767. EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
  768. }
  769. public static void Smaxp_V(AILEmitterCtx Context)
  770. {
  771. Type[] Types = new Type[] { typeof(long), typeof(long) };
  772. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  773. EmitVectorPairwiseOpSx(Context, () => Context.EmitCall(MthdInfo));
  774. }
  775. public static void Smin_V(AILEmitterCtx Context)
  776. {
  777. Type[] Types = new Type[] { typeof(long), typeof(long) };
  778. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  779. EmitVectorBinaryOpSx(Context, () => Context.EmitCall(MthdInfo));
  780. }
  781. public static void Sminp_V(AILEmitterCtx Context)
  782. {
  783. Type[] Types = new Type[] { typeof(long), typeof(long) };
  784. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  785. EmitVectorPairwiseOpSx(Context, () => Context.EmitCall(MthdInfo));
  786. }
  787. public static void Smlal_V(AILEmitterCtx Context)
  788. {
  789. EmitVectorWidenRnRmTernaryOpSx(Context, () =>
  790. {
  791. Context.Emit(OpCodes.Mul);
  792. Context.Emit(OpCodes.Add);
  793. });
  794. }
  795. public static void Smlsl_V(AILEmitterCtx Context)
  796. {
  797. EmitVectorWidenRnRmTernaryOpSx(Context, () =>
  798. {
  799. Context.Emit(OpCodes.Mul);
  800. Context.Emit(OpCodes.Sub);
  801. });
  802. }
  803. public static void Smull_V(AILEmitterCtx Context)
  804. {
  805. EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul));
  806. }
  807. public static void Sqabs_S(AILEmitterCtx Context)
  808. {
  809. EmitScalarSaturatingUnaryOpSx(Context, () => EmitAbs(Context));
  810. }
  811. public static void Sqabs_V(AILEmitterCtx Context)
  812. {
  813. EmitVectorSaturatingUnaryOpSx(Context, () => EmitAbs(Context));
  814. }
  815. public static void Sqadd_S(AILEmitterCtx Context)
  816. {
  817. EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Add);
  818. }
  819. public static void Sqadd_V(AILEmitterCtx Context)
  820. {
  821. EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Add);
  822. }
  823. public static void Sqdmulh_S(AILEmitterCtx Context)
  824. {
  825. EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: false), SaturatingFlags.ScalarSx);
  826. }
  827. public static void Sqdmulh_V(AILEmitterCtx Context)
  828. {
  829. EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: false), SaturatingFlags.VectorSx);
  830. }
  831. public static void Sqneg_S(AILEmitterCtx Context)
  832. {
  833. EmitScalarSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  834. }
  835. public static void Sqneg_V(AILEmitterCtx Context)
  836. {
  837. EmitVectorSaturatingUnaryOpSx(Context, () => Context.Emit(OpCodes.Neg));
  838. }
  839. public static void Sqrdmulh_S(AILEmitterCtx Context)
  840. {
  841. EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: true), SaturatingFlags.ScalarSx);
  842. }
  843. public static void Sqrdmulh_V(AILEmitterCtx Context)
  844. {
  845. EmitSaturatingBinaryOp(Context, () => EmitDoublingMultiplyHighHalf(Context, Round: true), SaturatingFlags.VectorSx);
  846. }
  847. public static void Sqsub_S(AILEmitterCtx Context)
  848. {
  849. EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Sub);
  850. }
  851. public static void Sqsub_V(AILEmitterCtx Context)
  852. {
  853. EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Sub);
  854. }
  855. public static void Sqxtn_S(AILEmitterCtx Context)
  856. {
  857. EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.ScalarSxSx);
  858. }
  859. public static void Sqxtn_V(AILEmitterCtx Context)
  860. {
  861. EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.VectorSxSx);
  862. }
  863. public static void Sqxtun_S(AILEmitterCtx Context)
  864. {
  865. EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.ScalarSxZx);
  866. }
  867. public static void Sqxtun_V(AILEmitterCtx Context)
  868. {
  869. EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.VectorSxZx);
  870. }
  871. public static void Srhadd_V(AILEmitterCtx Context)
  872. {
  873. EmitVectorBinaryOpSx(Context, () =>
  874. {
  875. Context.Emit(OpCodes.Add);
  876. Context.Emit(OpCodes.Ldc_I4_1);
  877. Context.Emit(OpCodes.Add);
  878. Context.Emit(OpCodes.Ldc_I4_1);
  879. Context.Emit(OpCodes.Shr);
  880. });
  881. }
  882. public static void Ssubl_V(AILEmitterCtx Context)
  883. {
  884. EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Sub));
  885. }
  886. public static void Ssubw_V(AILEmitterCtx Context)
  887. {
  888. EmitVectorWidenRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Sub));
  889. }
  890. public static void Sub_S(AILEmitterCtx Context)
  891. {
  892. EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  893. }
  894. public static void Sub_V(AILEmitterCtx Context)
  895. {
  896. if (AOptimizations.UseSse2)
  897. {
  898. EmitSse2Call(Context, nameof(Sse2.Subtract));
  899. }
  900. else
  901. {
  902. EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  903. }
  904. }
  905. public static void Subhn_V(AILEmitterCtx Context)
  906. {
  907. EmitHighNarrow(Context, () => Context.Emit(OpCodes.Sub), Round: false);
  908. }
  909. public static void Suqadd_S(AILEmitterCtx Context)
  910. {
  911. EmitScalarSaturatingBinaryOpSx(Context, SaturatingFlags.Accumulate);
  912. }
  913. public static void Suqadd_V(AILEmitterCtx Context)
  914. {
  915. EmitVectorSaturatingBinaryOpSx(Context, SaturatingFlags.Accumulate);
  916. }
  917. public static void Uaba_V(AILEmitterCtx Context)
  918. {
  919. EmitVectorTernaryOpZx(Context, () =>
  920. {
  921. Context.Emit(OpCodes.Sub);
  922. EmitAbs(Context);
  923. Context.Emit(OpCodes.Add);
  924. });
  925. }
  926. public static void Uabal_V(AILEmitterCtx Context)
  927. {
  928. EmitVectorWidenRnRmTernaryOpZx(Context, () =>
  929. {
  930. Context.Emit(OpCodes.Sub);
  931. EmitAbs(Context);
  932. Context.Emit(OpCodes.Add);
  933. });
  934. }
  935. public static void Uabd_V(AILEmitterCtx Context)
  936. {
  937. EmitVectorBinaryOpZx(Context, () =>
  938. {
  939. Context.Emit(OpCodes.Sub);
  940. EmitAbs(Context);
  941. });
  942. }
  943. public static void Uabdl_V(AILEmitterCtx Context)
  944. {
  945. EmitVectorWidenRnRmBinaryOpZx(Context, () =>
  946. {
  947. Context.Emit(OpCodes.Sub);
  948. EmitAbs(Context);
  949. });
  950. }
  951. public static void Uadalp_V(AILEmitterCtx Context)
  952. {
  953. EmitAddLongPairwise(Context, Signed: false, Accumulate: true);
  954. }
  955. public static void Uaddl_V(AILEmitterCtx Context)
  956. {
  957. EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  958. }
  959. public static void Uaddlp_V(AILEmitterCtx Context)
  960. {
  961. EmitAddLongPairwise(Context, Signed: false, Accumulate: false);
  962. }
  963. public static void Uaddlv_V(AILEmitterCtx Context)
  964. {
  965. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  966. int Bytes = Op.GetBitsCount() >> 3;
  967. int Elems = Bytes >> Op.Size;
  968. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  969. for (int Index = 1; Index < Elems; Index++)
  970. {
  971. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  972. Context.Emit(OpCodes.Add);
  973. }
  974. EmitScalarSet(Context, Op.Rd, Op.Size + 1);
  975. }
  976. public static void Uaddw_V(AILEmitterCtx Context)
  977. {
  978. EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
  979. }
  980. public static void Uhadd_V(AILEmitterCtx Context)
  981. {
  982. EmitVectorBinaryOpZx(Context, () =>
  983. {
  984. Context.Emit(OpCodes.Add);
  985. Context.Emit(OpCodes.Ldc_I4_1);
  986. Context.Emit(OpCodes.Shr_Un);
  987. });
  988. }
  989. public static void Uhsub_V(AILEmitterCtx Context)
  990. {
  991. EmitVectorBinaryOpZx(Context, () =>
  992. {
  993. Context.Emit(OpCodes.Sub);
  994. Context.Emit(OpCodes.Ldc_I4_1);
  995. Context.Emit(OpCodes.Shr_Un);
  996. });
  997. }
  998. public static void Umax_V(AILEmitterCtx Context)
  999. {
  1000. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  1001. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  1002. EmitVectorBinaryOpZx(Context, () => Context.EmitCall(MthdInfo));
  1003. }
  1004. public static void Umaxp_V(AILEmitterCtx Context)
  1005. {
  1006. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  1007. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  1008. EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
  1009. }
  1010. public static void Umin_V(AILEmitterCtx Context)
  1011. {
  1012. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  1013. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  1014. EmitVectorBinaryOpZx(Context, () => Context.EmitCall(MthdInfo));
  1015. }
  1016. public static void Uminp_V(AILEmitterCtx Context)
  1017. {
  1018. Type[] Types = new Type[] { typeof(ulong), typeof(ulong) };
  1019. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  1020. EmitVectorPairwiseOpZx(Context, () => Context.EmitCall(MthdInfo));
  1021. }
  1022. public static void Umlal_V(AILEmitterCtx Context)
  1023. {
  1024. EmitVectorWidenRnRmTernaryOpZx(Context, () =>
  1025. {
  1026. Context.Emit(OpCodes.Mul);
  1027. Context.Emit(OpCodes.Add);
  1028. });
  1029. }
  1030. public static void Umlsl_V(AILEmitterCtx Context)
  1031. {
  1032. EmitVectorWidenRnRmTernaryOpZx(Context, () =>
  1033. {
  1034. Context.Emit(OpCodes.Mul);
  1035. Context.Emit(OpCodes.Sub);
  1036. });
  1037. }
  1038. public static void Umull_V(AILEmitterCtx Context)
  1039. {
  1040. EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
  1041. }
  1042. public static void Uqadd_S(AILEmitterCtx Context)
  1043. {
  1044. EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Add);
  1045. }
  1046. public static void Uqadd_V(AILEmitterCtx Context)
  1047. {
  1048. EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Add);
  1049. }
  1050. public static void Uqsub_S(AILEmitterCtx Context)
  1051. {
  1052. EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Sub);
  1053. }
  1054. public static void Uqsub_V(AILEmitterCtx Context)
  1055. {
  1056. EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Sub);
  1057. }
  1058. public static void Uqxtn_S(AILEmitterCtx Context)
  1059. {
  1060. EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.ScalarZxZx);
  1061. }
  1062. public static void Uqxtn_V(AILEmitterCtx Context)
  1063. {
  1064. EmitSaturatingNarrowOp(Context, SaturatingNarrowFlags.VectorZxZx);
  1065. }
  1066. public static void Urhadd_V(AILEmitterCtx Context)
  1067. {
  1068. EmitVectorBinaryOpZx(Context, () =>
  1069. {
  1070. Context.Emit(OpCodes.Add);
  1071. Context.Emit(OpCodes.Ldc_I4_1);
  1072. Context.Emit(OpCodes.Add);
  1073. Context.Emit(OpCodes.Ldc_I4_1);
  1074. Context.Emit(OpCodes.Shr_Un);
  1075. });
  1076. }
  1077. public static void Usqadd_S(AILEmitterCtx Context)
  1078. {
  1079. EmitScalarSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
  1080. }
  1081. public static void Usqadd_V(AILEmitterCtx Context)
  1082. {
  1083. EmitVectorSaturatingBinaryOpZx(Context, SaturatingFlags.Accumulate);
  1084. }
  1085. public static void Usubl_V(AILEmitterCtx Context)
  1086. {
  1087. EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  1088. }
  1089. public static void Usubw_V(AILEmitterCtx Context)
  1090. {
  1091. EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
  1092. }
  1093. private static void EmitAbs(AILEmitterCtx Context)
  1094. {
  1095. AILLabel LblTrue = new AILLabel();
  1096. Context.Emit(OpCodes.Dup);
  1097. Context.Emit(OpCodes.Ldc_I4_0);
  1098. Context.Emit(OpCodes.Bge_S, LblTrue);
  1099. Context.Emit(OpCodes.Neg);
  1100. Context.MarkLabel(LblTrue);
  1101. }
  1102. private static void EmitAddLongPairwise(AILEmitterCtx Context, bool Signed, bool Accumulate)
  1103. {
  1104. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  1105. int Words = Op.GetBitsCount() >> 4;
  1106. int Pairs = Words >> Op.Size;
  1107. for (int Index = 0; Index < Pairs; Index++)
  1108. {
  1109. int Idx = Index << 1;
  1110. EmitVectorExtract(Context, Op.Rn, Idx, Op.Size, Signed);
  1111. EmitVectorExtract(Context, Op.Rn, Idx + 1, Op.Size, Signed);
  1112. Context.Emit(OpCodes.Add);
  1113. if (Accumulate)
  1114. {
  1115. EmitVectorExtract(Context, Op.Rd, Index, Op.Size + 1, Signed);
  1116. Context.Emit(OpCodes.Add);
  1117. }
  1118. EmitVectorInsertTmp(Context, Index, Op.Size + 1);
  1119. }
  1120. Context.EmitLdvectmp();
  1121. Context.EmitStvec(Op.Rd);
  1122. if (Op.RegisterSize == ARegisterSize.SIMD64)
  1123. {
  1124. EmitVectorZeroUpper(Context, Op.Rd);
  1125. }
  1126. }
  1127. private static void EmitDoublingMultiplyHighHalf(AILEmitterCtx Context, bool Round)
  1128. {
  1129. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  1130. int ESize = 8 << Op.Size;
  1131. Context.Emit(OpCodes.Mul);
  1132. if (!Round)
  1133. {
  1134. Context.EmitAsr(ESize - 1);
  1135. }
  1136. else
  1137. {
  1138. long RoundConst = 1L << (ESize - 1);
  1139. AILLabel LblTrue = new AILLabel();
  1140. Context.EmitLsl(1);
  1141. Context.EmitLdc_I8(RoundConst);
  1142. Context.Emit(OpCodes.Add);
  1143. Context.EmitAsr(ESize);
  1144. Context.Emit(OpCodes.Dup);
  1145. Context.EmitLdc_I8((long)int.MinValue);
  1146. Context.Emit(OpCodes.Bne_Un_S, LblTrue);
  1147. Context.Emit(OpCodes.Neg);
  1148. Context.MarkLabel(LblTrue);
  1149. }
  1150. }
  1151. private static void EmitHighNarrow(AILEmitterCtx Context, Action Emit, bool Round)
  1152. {
  1153. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  1154. int Elems = 8 >> Op.Size;
  1155. int ESize = 8 << Op.Size;
  1156. int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
  1157. long RoundConst = 1L << (ESize - 1);
  1158. if (Part != 0)
  1159. {
  1160. Context.EmitLdvec(Op.Rd);
  1161. Context.EmitStvectmp();
  1162. }
  1163. for (int Index = 0; Index < Elems; Index++)
  1164. {
  1165. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
  1166. EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size + 1);
  1167. Emit();
  1168. if (Round)
  1169. {
  1170. Context.EmitLdc_I8(RoundConst);
  1171. Context.Emit(OpCodes.Add);
  1172. }
  1173. Context.EmitLsr(ESize);
  1174. EmitVectorInsertTmp(Context, Part + Index, Op.Size);
  1175. }
  1176. Context.EmitLdvectmp();
  1177. Context.EmitStvec(Op.Rd);
  1178. if (Part == 0)
  1179. {
  1180. EmitVectorZeroUpper(Context, Op.Rd);
  1181. }
  1182. }
  1183. }
  1184. }