AInstEmitSimdArithmetic.cs 25 KB

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