InstEmitSimdCvt.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. using ChocolArm64.Decoders;
  2. using ChocolArm64.State;
  3. using ChocolArm64.Translation;
  4. using System;
  5. using System.Reflection.Emit;
  6. using System.Runtime.Intrinsics;
  7. using System.Runtime.Intrinsics.X86;
  8. using static ChocolArm64.Instructions.InstEmitSimdHelper;
  9. namespace ChocolArm64.Instructions
  10. {
  11. static partial class InstEmit
  12. {
  13. public static void Fcvt_S(ILEmitterCtx context)
  14. {
  15. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  16. if (Optimizations.UseSse2)
  17. {
  18. if (op.Size == 1 && op.Opc == 0)
  19. {
  20. //Double -> Single.
  21. Type[] typesCvt = new Type[] { typeof(Vector128<float>), typeof(Vector128<double>) };
  22. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  23. context.EmitLdvec(op.Rn);
  24. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), typesCvt));
  25. context.EmitStvec(op.Rd);
  26. }
  27. else if (op.Size == 0 && op.Opc == 1)
  28. {
  29. //Single -> Double.
  30. Type[] typesCvt = new Type[] { typeof(Vector128<double>), typeof(Vector128<float>) };
  31. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  32. context.EmitLdvec(op.Rn);
  33. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), typesCvt));
  34. context.EmitStvec(op.Rd);
  35. }
  36. else
  37. {
  38. //Invalid encoding.
  39. throw new InvalidOperationException();
  40. }
  41. }
  42. else
  43. {
  44. EmitVectorExtractF(context, op.Rn, 0, op.Size);
  45. EmitFloatCast(context, op.Opc);
  46. EmitScalarSetF(context, op.Rd, op.Opc);
  47. }
  48. }
  49. public static void Fcvtas_Gp(ILEmitterCtx context)
  50. {
  51. EmitFcvt_s_Gp(context, () => EmitRoundMathCall(context, MidpointRounding.AwayFromZero));
  52. }
  53. public static void Fcvtau_Gp(ILEmitterCtx context)
  54. {
  55. EmitFcvt_u_Gp(context, () => EmitRoundMathCall(context, MidpointRounding.AwayFromZero));
  56. }
  57. public static void Fcvtl_V(ILEmitterCtx context)
  58. {
  59. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  60. int sizeF = op.Size & 1;
  61. if (Optimizations.UseSse2 && sizeF == 1)
  62. {
  63. Type[] typesCvt = new Type[] { typeof(Vector128<float>) };
  64. context.EmitLdvec(op.Rn);
  65. if (op.RegisterSize == RegisterSize.Simd128)
  66. {
  67. context.EmitLdvec(op.Rn);
  68. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveHighToLow)));
  69. }
  70. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Double), typesCvt));
  71. context.EmitStvec(op.Rd);
  72. }
  73. else
  74. {
  75. int elems = 4 >> sizeF;
  76. int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0;
  77. for (int index = 0; index < elems; index++)
  78. {
  79. if (sizeF == 0)
  80. {
  81. EmitVectorExtractZx(context, op.Rn, part + index, 1);
  82. context.Emit(OpCodes.Conv_U2);
  83. context.EmitLdarg(TranslatedSub.StateArgIdx);
  84. context.EmitCall(typeof(SoftFloat16_32), nameof(SoftFloat16_32.FPConvert));
  85. }
  86. else /* if (sizeF == 1) */
  87. {
  88. EmitVectorExtractF(context, op.Rn, part + index, 0);
  89. context.Emit(OpCodes.Conv_R8);
  90. }
  91. EmitVectorInsertTmpF(context, index, sizeF);
  92. }
  93. context.EmitLdvectmp();
  94. context.EmitStvec(op.Rd);
  95. }
  96. }
  97. public static void Fcvtms_Gp(ILEmitterCtx context)
  98. {
  99. if (Optimizations.UseSse41)
  100. {
  101. EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsMinusInfinity, isFixed: false);
  102. }
  103. else
  104. {
  105. EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor)));
  106. }
  107. }
  108. public static void Fcvtmu_Gp(ILEmitterCtx context)
  109. {
  110. EmitFcvt_u_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor)));
  111. }
  112. public static void Fcvtn_V(ILEmitterCtx context)
  113. {
  114. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  115. int sizeF = op.Size & 1;
  116. if (Optimizations.UseSse2 && sizeF == 1)
  117. {
  118. Type[] typesCvt = new Type[] { typeof(Vector128<double>) };
  119. string nameMov = op.RegisterSize == RegisterSize.Simd128
  120. ? nameof(Sse.MoveLowToHigh)
  121. : nameof(Sse.MoveHighToLow);
  122. context.EmitLdvec(op.Rd);
  123. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  124. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh)));
  125. context.EmitLdvec(op.Rn);
  126. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt));
  127. context.Emit(OpCodes.Dup);
  128. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh)));
  129. context.EmitCall(typeof(Sse).GetMethod(nameMov));
  130. context.EmitStvec(op.Rd);
  131. }
  132. else
  133. {
  134. int elems = 4 >> sizeF;
  135. int part = op.RegisterSize == RegisterSize.Simd128 ? elems : 0;
  136. if (part != 0)
  137. {
  138. context.EmitLdvec(op.Rd);
  139. context.EmitStvectmp();
  140. }
  141. for (int index = 0; index < elems; index++)
  142. {
  143. EmitVectorExtractF(context, op.Rn, index, sizeF);
  144. if (sizeF == 0)
  145. {
  146. context.EmitLdarg(TranslatedSub.StateArgIdx);
  147. context.EmitCall(typeof(SoftFloat32_16), nameof(SoftFloat32_16.FPConvert));
  148. context.Emit(OpCodes.Conv_U8);
  149. EmitVectorInsertTmp(context, part + index, 1);
  150. }
  151. else /* if (sizeF == 1) */
  152. {
  153. context.Emit(OpCodes.Conv_R4);
  154. EmitVectorInsertTmpF(context, part + index, 0);
  155. }
  156. }
  157. context.EmitLdvectmp();
  158. context.EmitStvec(op.Rd);
  159. if (part == 0)
  160. {
  161. EmitVectorZeroUpper(context, op.Rd);
  162. }
  163. }
  164. }
  165. public static void Fcvtns_S(ILEmitterCtx context)
  166. {
  167. if (Optimizations.UseSse41)
  168. {
  169. EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, isFixed: false, scalar: true);
  170. }
  171. else
  172. {
  173. EmitFcvtn(context, signed: true, scalar: true);
  174. }
  175. }
  176. public static void Fcvtns_V(ILEmitterCtx context)
  177. {
  178. if (Optimizations.UseSse41)
  179. {
  180. EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, isFixed: false, scalar: false);
  181. }
  182. else
  183. {
  184. EmitFcvtn(context, signed: true, scalar: false);
  185. }
  186. }
  187. public static void Fcvtnu_S(ILEmitterCtx context)
  188. {
  189. EmitFcvtn(context, signed: false, scalar: true);
  190. }
  191. public static void Fcvtnu_V(ILEmitterCtx context)
  192. {
  193. EmitFcvtn(context, signed: false, scalar: false);
  194. }
  195. public static void Fcvtps_Gp(ILEmitterCtx context)
  196. {
  197. if (Optimizations.UseSse41)
  198. {
  199. EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsPlusInfinity, isFixed: false);
  200. }
  201. else
  202. {
  203. EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling)));
  204. }
  205. }
  206. public static void Fcvtpu_Gp(ILEmitterCtx context)
  207. {
  208. EmitFcvt_u_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling)));
  209. }
  210. public static void Fcvtzs_Gp(ILEmitterCtx context)
  211. {
  212. if (Optimizations.UseSse41)
  213. {
  214. EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsZero, isFixed: false);
  215. }
  216. else
  217. {
  218. EmitFcvt_s_Gp(context, () => { });
  219. }
  220. }
  221. public static void Fcvtzs_Gp_Fixed(ILEmitterCtx context)
  222. {
  223. if (Optimizations.UseSse41)
  224. {
  225. EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsZero, isFixed: true);
  226. }
  227. else
  228. {
  229. EmitFcvtzs_Gp_Fixed(context);
  230. }
  231. }
  232. public static void Fcvtzs_S(ILEmitterCtx context)
  233. {
  234. if (Optimizations.UseSse41)
  235. {
  236. EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: false, scalar: true);
  237. }
  238. else
  239. {
  240. EmitFcvtz(context, signed: true, scalar: true);
  241. }
  242. }
  243. public static void Fcvtzs_V(ILEmitterCtx context)
  244. {
  245. if (Optimizations.UseSse41)
  246. {
  247. EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: false, scalar: false);
  248. }
  249. else
  250. {
  251. EmitFcvtz(context, signed: true, scalar: false);
  252. }
  253. }
  254. public static void Fcvtzs_V_Fixed(ILEmitterCtx context)
  255. {
  256. if (Optimizations.UseSse41)
  257. {
  258. EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: true, scalar: false);
  259. }
  260. else
  261. {
  262. EmitFcvtz(context, signed: true, scalar: false);
  263. }
  264. }
  265. public static void Fcvtzu_Gp(ILEmitterCtx context)
  266. {
  267. EmitFcvt_u_Gp(context, () => { });
  268. }
  269. public static void Fcvtzu_Gp_Fixed(ILEmitterCtx context)
  270. {
  271. EmitFcvtzu_Gp_Fixed(context);
  272. }
  273. public static void Fcvtzu_S(ILEmitterCtx context)
  274. {
  275. EmitFcvtz(context, signed: false, scalar: true);
  276. }
  277. public static void Fcvtzu_V(ILEmitterCtx context)
  278. {
  279. EmitFcvtz(context, signed: false, scalar: false);
  280. }
  281. public static void Fcvtzu_V_Fixed(ILEmitterCtx context)
  282. {
  283. EmitFcvtz(context, signed: false, scalar: false);
  284. }
  285. public static void Scvtf_Gp(ILEmitterCtx context)
  286. {
  287. OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;
  288. context.EmitLdintzr(op.Rn);
  289. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  290. {
  291. context.Emit(OpCodes.Conv_U4);
  292. }
  293. EmitFloatCast(context, op.Size);
  294. EmitScalarSetF(context, op.Rd, op.Size);
  295. }
  296. public static void Scvtf_Gp_Fixed(ILEmitterCtx context)
  297. {
  298. OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;
  299. context.EmitLdintzr(op.Rn);
  300. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  301. {
  302. context.Emit(OpCodes.Conv_I4);
  303. }
  304. EmitFloatCast(context, op.Size);
  305. EmitI2fFBitsMul(context, op.Size, op.FBits);
  306. EmitScalarSetF(context, op.Rd, op.Size);
  307. }
  308. public static void Scvtf_S(ILEmitterCtx context)
  309. {
  310. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  311. EmitVectorExtractSx(context, op.Rn, 0, op.Size + 2);
  312. EmitFloatCast(context, op.Size);
  313. EmitScalarSetF(context, op.Rd, op.Size);
  314. }
  315. public static void Scvtf_V(ILEmitterCtx context)
  316. {
  317. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  318. int sizeF = op.Size & 1;
  319. if (Optimizations.UseSse2 && sizeF == 0)
  320. {
  321. Type[] typesCvt = new Type[] { typeof(Vector128<int>) };
  322. context.EmitLdvec(op.Rn);
  323. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt));
  324. context.EmitStvec(op.Rd);
  325. if (op.RegisterSize == RegisterSize.Simd64)
  326. {
  327. EmitVectorZeroUpper(context, op.Rd);
  328. }
  329. }
  330. else
  331. {
  332. EmitVectorCvtf(context, signed: true);
  333. }
  334. }
  335. public static void Ucvtf_Gp(ILEmitterCtx context)
  336. {
  337. OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;
  338. context.EmitLdintzr(op.Rn);
  339. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  340. {
  341. context.Emit(OpCodes.Conv_U4);
  342. }
  343. context.Emit(OpCodes.Conv_R_Un);
  344. EmitFloatCast(context, op.Size);
  345. EmitScalarSetF(context, op.Rd, op.Size);
  346. }
  347. public static void Ucvtf_Gp_Fixed(ILEmitterCtx context)
  348. {
  349. OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;
  350. context.EmitLdintzr(op.Rn);
  351. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  352. {
  353. context.Emit(OpCodes.Conv_U4);
  354. }
  355. context.Emit(OpCodes.Conv_R_Un);
  356. EmitFloatCast(context, op.Size);
  357. EmitI2fFBitsMul(context, op.Size, op.FBits);
  358. EmitScalarSetF(context, op.Rd, op.Size);
  359. }
  360. public static void Ucvtf_S(ILEmitterCtx context)
  361. {
  362. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  363. EmitVectorExtractZx(context, op.Rn, 0, op.Size + 2);
  364. context.Emit(OpCodes.Conv_R_Un);
  365. EmitFloatCast(context, op.Size);
  366. EmitScalarSetF(context, op.Rd, op.Size);
  367. }
  368. public static void Ucvtf_V(ILEmitterCtx context)
  369. {
  370. EmitVectorCvtf(context, signed: false);
  371. }
  372. private static void EmitFcvtn(ILEmitterCtx context, bool signed, bool scalar)
  373. {
  374. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  375. int sizeF = op.Size & 1;
  376. int sizeI = sizeF + 2;
  377. int bytes = op.GetBitsCount() >> 3;
  378. int elems = !scalar ? bytes >> sizeI : 1;
  379. for (int index = 0; index < elems; index++)
  380. {
  381. EmitVectorExtractF(context, op.Rn, index, sizeF);
  382. EmitRoundMathCall(context, MidpointRounding.ToEven);
  383. if (sizeF == 0)
  384. {
  385. VectorHelper.EmitCall(context, signed
  386. ? nameof(VectorHelper.SatF32ToS32)
  387. : nameof(VectorHelper.SatF32ToU32));
  388. context.Emit(OpCodes.Conv_U8);
  389. }
  390. else /* if (sizeF == 1) */
  391. {
  392. VectorHelper.EmitCall(context, signed
  393. ? nameof(VectorHelper.SatF64ToS64)
  394. : nameof(VectorHelper.SatF64ToU64));
  395. }
  396. if (scalar)
  397. {
  398. EmitVectorZeroAll(context, op.Rd);
  399. }
  400. EmitVectorInsert(context, op.Rd, index, sizeI);
  401. }
  402. if (op.RegisterSize == RegisterSize.Simd64)
  403. {
  404. EmitVectorZeroUpper(context, op.Rd);
  405. }
  406. }
  407. private static void EmitFcvtz(ILEmitterCtx context, bool signed, bool scalar)
  408. {
  409. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  410. int sizeF = op.Size & 1;
  411. int sizeI = sizeF + 2;
  412. int fBits = GetFBits(context);
  413. int bytes = op.GetBitsCount() >> 3;
  414. int elems = !scalar ? bytes >> sizeI : 1;
  415. for (int index = 0; index < elems; index++)
  416. {
  417. EmitVectorExtractF(context, op.Rn, index, sizeF);
  418. EmitF2iFBitsMul(context, sizeF, fBits);
  419. if (sizeF == 0)
  420. {
  421. VectorHelper.EmitCall(context, signed
  422. ? nameof(VectorHelper.SatF32ToS32)
  423. : nameof(VectorHelper.SatF32ToU32));
  424. context.Emit(OpCodes.Conv_U8);
  425. }
  426. else /* if (sizeF == 1) */
  427. {
  428. VectorHelper.EmitCall(context, signed
  429. ? nameof(VectorHelper.SatF64ToS64)
  430. : nameof(VectorHelper.SatF64ToU64));
  431. }
  432. if (scalar)
  433. {
  434. EmitVectorZeroAll(context, op.Rd);
  435. }
  436. EmitVectorInsert(context, op.Rd, index, sizeI);
  437. }
  438. if (op.RegisterSize == RegisterSize.Simd64)
  439. {
  440. EmitVectorZeroUpper(context, op.Rd);
  441. }
  442. }
  443. private static void EmitFcvt_s_Gp(ILEmitterCtx context, Action emit)
  444. {
  445. EmitFcvt___Gp(context, emit, true);
  446. }
  447. private static void EmitFcvt_u_Gp(ILEmitterCtx context, Action emit)
  448. {
  449. EmitFcvt___Gp(context, emit, false);
  450. }
  451. private static void EmitFcvt___Gp(ILEmitterCtx context, Action emit, bool signed)
  452. {
  453. OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;
  454. EmitVectorExtractF(context, op.Rn, 0, op.Size);
  455. emit();
  456. if (signed)
  457. {
  458. EmitScalarFcvts(context, op.Size, 0);
  459. }
  460. else
  461. {
  462. EmitScalarFcvtu(context, op.Size, 0);
  463. }
  464. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  465. {
  466. context.Emit(OpCodes.Conv_U8);
  467. }
  468. context.EmitStintzr(op.Rd);
  469. }
  470. private static void EmitFcvtzs_Gp_Fixed(ILEmitterCtx context)
  471. {
  472. EmitFcvtz__Gp_Fixed(context, true);
  473. }
  474. private static void EmitFcvtzu_Gp_Fixed(ILEmitterCtx context)
  475. {
  476. EmitFcvtz__Gp_Fixed(context, false);
  477. }
  478. private static void EmitFcvtz__Gp_Fixed(ILEmitterCtx context, bool signed)
  479. {
  480. OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;
  481. EmitVectorExtractF(context, op.Rn, 0, op.Size);
  482. if (signed)
  483. {
  484. EmitScalarFcvts(context, op.Size, op.FBits);
  485. }
  486. else
  487. {
  488. EmitScalarFcvtu(context, op.Size, op.FBits);
  489. }
  490. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  491. {
  492. context.Emit(OpCodes.Conv_U8);
  493. }
  494. context.EmitStintzr(op.Rd);
  495. }
  496. private static void EmitVectorCvtf(ILEmitterCtx context, bool signed)
  497. {
  498. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  499. int sizeF = op.Size & 1;
  500. int sizeI = sizeF + 2;
  501. int fBits = GetFBits(context);
  502. int bytes = op.GetBitsCount() >> 3;
  503. int elems = bytes >> sizeI;
  504. for (int index = 0; index < elems; index++)
  505. {
  506. EmitVectorExtract(context, op.Rn, index, sizeI, signed);
  507. if (!signed)
  508. {
  509. context.Emit(OpCodes.Conv_R_Un);
  510. }
  511. EmitFloatCast(context, sizeF);
  512. EmitI2fFBitsMul(context, sizeF, fBits);
  513. EmitVectorInsertF(context, op.Rd, index, sizeF);
  514. }
  515. if (op.RegisterSize == RegisterSize.Simd64)
  516. {
  517. EmitVectorZeroUpper(context, op.Rd);
  518. }
  519. }
  520. private static int GetFBits(ILEmitterCtx context)
  521. {
  522. if (context.CurrOp is OpCodeSimdShImm64 op)
  523. {
  524. return GetImmShr(op);
  525. }
  526. return 0;
  527. }
  528. private static void EmitFloatCast(ILEmitterCtx context, int size)
  529. {
  530. if (size == 0)
  531. {
  532. context.Emit(OpCodes.Conv_R4);
  533. }
  534. else if (size == 1)
  535. {
  536. context.Emit(OpCodes.Conv_R8);
  537. }
  538. else
  539. {
  540. throw new ArgumentOutOfRangeException(nameof(size));
  541. }
  542. }
  543. private static void EmitScalarFcvts(ILEmitterCtx context, int size, int fBits)
  544. {
  545. if (size < 0 || size > 1)
  546. {
  547. throw new ArgumentOutOfRangeException(nameof(size));
  548. }
  549. EmitF2iFBitsMul(context, size, fBits);
  550. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  551. {
  552. if (size == 0)
  553. {
  554. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToS32));
  555. }
  556. else /* if (size == 1) */
  557. {
  558. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToS32));
  559. }
  560. }
  561. else
  562. {
  563. if (size == 0)
  564. {
  565. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToS64));
  566. }
  567. else /* if (size == 1) */
  568. {
  569. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToS64));
  570. }
  571. }
  572. }
  573. private static void EmitScalarFcvtu(ILEmitterCtx context, int size, int fBits)
  574. {
  575. if (size < 0 || size > 1)
  576. {
  577. throw new ArgumentOutOfRangeException(nameof(size));
  578. }
  579. EmitF2iFBitsMul(context, size, fBits);
  580. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  581. {
  582. if (size == 0)
  583. {
  584. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToU32));
  585. }
  586. else /* if (size == 1) */
  587. {
  588. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToU32));
  589. }
  590. }
  591. else
  592. {
  593. if (size == 0)
  594. {
  595. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF32ToU64));
  596. }
  597. else /* if (size == 1) */
  598. {
  599. VectorHelper.EmitCall(context, nameof(VectorHelper.SatF64ToU64));
  600. }
  601. }
  602. }
  603. private static void EmitF2iFBitsMul(ILEmitterCtx context, int size, int fBits)
  604. {
  605. if (fBits != 0)
  606. {
  607. if (size == 0)
  608. {
  609. context.EmitLdc_R4(MathF.Pow(2f, fBits));
  610. }
  611. else if (size == 1)
  612. {
  613. context.EmitLdc_R8(Math.Pow(2d, fBits));
  614. }
  615. else
  616. {
  617. throw new ArgumentOutOfRangeException(nameof(size));
  618. }
  619. context.Emit(OpCodes.Mul);
  620. }
  621. }
  622. private static void EmitI2fFBitsMul(ILEmitterCtx context, int size, int fBits)
  623. {
  624. if (fBits != 0)
  625. {
  626. if (size == 0)
  627. {
  628. context.EmitLdc_R4(1f / MathF.Pow(2f, fBits));
  629. }
  630. else if (size == 1)
  631. {
  632. context.EmitLdc_R8(1d / Math.Pow(2d, fBits));
  633. }
  634. else
  635. {
  636. throw new ArgumentOutOfRangeException(nameof(size));
  637. }
  638. context.Emit(OpCodes.Mul);
  639. }
  640. }
  641. private static void EmitSse41Fcvt_Signed_Gp(ILEmitterCtx context, RoundMode roundMode, bool isFixed)
  642. {
  643. OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp;
  644. if (op.Size == 0)
  645. {
  646. Type[] typesCmpMul = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) };
  647. Type[] typesAnd = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) };
  648. Type[] typesRndCvt = new Type[] { typeof(Vector128<float>) };
  649. Type[] typesCvt = new Type[] { typeof(Vector128<int>) };
  650. Type[] typesSav = new Type[] { typeof(int) };
  651. //string nameCvt;
  652. int fpMaxVal;
  653. if (op.RegisterSize == RegisterSize.Int32)
  654. {
  655. //nameCvt = nameof(Sse.ConvertToInt32);
  656. fpMaxVal = 0x4F000000; // 2.14748365E9f (2147483648)
  657. }
  658. else
  659. {
  660. //nameCvt = nameof(Sse.ConvertToInt64);
  661. fpMaxVal = 0x5F000000; // 9.223372E18f (9223372036854775808)
  662. }
  663. context.EmitLdvec(op.Rn);
  664. context.EmitLdvec(op.Rn);
  665. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), typesCmpMul));
  666. context.EmitLdvec(op.Rn);
  667. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAnd));
  668. if (isFixed)
  669. {
  670. // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, op.FBits)
  671. int fpScaled = 0x40000000 + (op.FBits - 1) * 0x800000;
  672. context.EmitLdc_I4(fpScaled);
  673. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  674. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesCmpMul));
  675. }
  676. context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt));
  677. context.EmitStvectmp();
  678. context.EmitLdvectmp();
  679. // TODO: Use Sse.ConvertToInt64 once it is fixed (in .NET Core 3.0),
  680. // remove the following if/else and uncomment the code.
  681. //context.EmitCall(typeof(Sse).GetMethod(nameCvt, typesRndCvt));
  682. if (op.RegisterSize == RegisterSize.Int32)
  683. {
  684. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.ConvertToInt32), typesRndCvt));
  685. }
  686. else
  687. {
  688. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Double), typesRndCvt));
  689. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), new Type[] { typeof(Vector128<double>) }));
  690. }
  691. context.EmitLdvectmp();
  692. context.EmitLdc_I4(fpMaxVal);
  693. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  694. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), typesCmpMul));
  695. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt32), typesCvt));
  696. if (op.RegisterSize == RegisterSize.Int32)
  697. {
  698. context.Emit(OpCodes.Xor);
  699. context.Emit(OpCodes.Conv_U8);
  700. }
  701. else
  702. {
  703. context.Emit(OpCodes.Conv_I8);
  704. context.Emit(OpCodes.Xor);
  705. }
  706. context.EmitStintzr(op.Rd);
  707. }
  708. else /* if (op.Size == 1) */
  709. {
  710. Type[] typesCmpMul = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) };
  711. Type[] typesAnd = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) };
  712. Type[] typesRndCvt = new Type[] { typeof(Vector128<double>) };
  713. Type[] typesCvt = new Type[] { typeof(Vector128<int>) };
  714. Type[] typesSav = new Type[] { typeof(long) };
  715. string nameCvt;
  716. long fpMaxVal;
  717. if (op.RegisterSize == RegisterSize.Int32)
  718. {
  719. nameCvt = nameof(Sse2.ConvertToInt32);
  720. fpMaxVal = 0x41E0000000000000L; // 2147483648.0000000d (2147483648)
  721. }
  722. else
  723. {
  724. nameCvt = nameof(Sse2.ConvertToInt64);
  725. fpMaxVal = 0x43E0000000000000L; // 9.2233720368547760E18d (9223372036854775808)
  726. }
  727. context.EmitLdvec(op.Rn);
  728. context.EmitLdvec(op.Rn);
  729. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), typesCmpMul));
  730. context.EmitLdvec(op.Rn);
  731. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAnd));
  732. if (isFixed)
  733. {
  734. // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, op.FBits)
  735. long fpScaled = 0x4000000000000000L + (op.FBits - 1) * 0x10000000000000L;
  736. context.EmitLdc_I8(fpScaled);
  737. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  738. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesCmpMul));
  739. }
  740. context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt));
  741. context.EmitStvectmp();
  742. context.EmitLdvectmp();
  743. context.EmitCall(typeof(Sse2).GetMethod(nameCvt, typesRndCvt));
  744. context.EmitLdvectmp();
  745. context.EmitLdc_I8(fpMaxVal);
  746. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  747. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), typesCmpMul));
  748. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt32), typesCvt));
  749. if (op.RegisterSize == RegisterSize.Int32)
  750. {
  751. context.Emit(OpCodes.Xor);
  752. context.Emit(OpCodes.Conv_U8);
  753. }
  754. else
  755. {
  756. context.Emit(OpCodes.Conv_I8);
  757. context.Emit(OpCodes.Xor);
  758. }
  759. context.EmitStintzr(op.Rd);
  760. }
  761. }
  762. private static void EmitSse41Fcvt_Signed(ILEmitterCtx context, RoundMode roundMode, bool isFixed, bool scalar)
  763. {
  764. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  765. // sizeF == ((OpCodeSimdShImm64)op).Size - 2
  766. int sizeF = op.Size & 1;
  767. if (sizeF == 0)
  768. {
  769. Type[] typesCmpMul = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) };
  770. Type[] typesAndXor = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) };
  771. Type[] typesRndCvt = new Type[] { typeof(Vector128<float>) };
  772. Type[] typesSav = new Type[] { typeof(int) };
  773. context.EmitLdvec(op.Rn);
  774. context.EmitLdvec(op.Rn);
  775. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), typesCmpMul));
  776. context.EmitLdvec(op.Rn);
  777. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXor));
  778. if (isFixed)
  779. {
  780. int fBits = GetImmShr((OpCodeSimdShImm64)op);
  781. // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits)
  782. int fpScaled = 0x40000000 + (fBits - 1) * 0x800000;
  783. context.EmitLdc_I4(fpScaled);
  784. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  785. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesCmpMul));
  786. }
  787. context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt));
  788. context.EmitStvectmp();
  789. context.EmitLdvectmp();
  790. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt));
  791. context.EmitLdvectmp();
  792. context.EmitLdc_I4(0x4F000000); // 2.14748365E9f (2147483648)
  793. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  794. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), typesCmpMul));
  795. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXor));
  796. context.EmitStvec(op.Rd);
  797. if (scalar)
  798. {
  799. EmitVectorZero32_128(context, op.Rd);
  800. }
  801. else if (op.RegisterSize == RegisterSize.Simd64)
  802. {
  803. EmitVectorZeroUpper(context, op.Rd);
  804. }
  805. }
  806. else /* if (sizeF == 1) */
  807. {
  808. Type[] typesCmpMulUpk = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) };
  809. Type[] typesAndXor = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) };
  810. Type[] typesRndCvt = new Type[] { typeof(Vector128<double>) };
  811. Type[] typesSv = new Type[] { typeof(long), typeof(long) };
  812. Type[] typesSav = new Type[] { typeof(long) };
  813. context.EmitLdvec(op.Rn);
  814. context.EmitLdvec(op.Rn);
  815. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), typesCmpMulUpk));
  816. context.EmitLdvec(op.Rn);
  817. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXor));
  818. if (isFixed)
  819. {
  820. int fBits = GetImmShr((OpCodeSimdShImm64)op);
  821. // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits)
  822. long fpScaled = 0x4000000000000000L + (fBits - 1) * 0x10000000000000L;
  823. context.EmitLdc_I8(fpScaled);
  824. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  825. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesCmpMulUpk));
  826. }
  827. context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt));
  828. context.EmitStvectmp();
  829. context.EmitLdvectmp();
  830. context.EmitLdvectmp();
  831. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), typesCmpMulUpk));
  832. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt));
  833. context.EmitLdvectmp();
  834. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt));
  835. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv));
  836. context.EmitLdvectmp();
  837. context.EmitLdc_I8(0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808)
  838. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  839. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), typesCmpMulUpk));
  840. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXor));
  841. context.EmitStvec(op.Rd);
  842. if (scalar)
  843. {
  844. EmitVectorZeroUpper(context, op.Rd);
  845. }
  846. }
  847. }
  848. private static string GetSse41NameRnd(RoundMode roundMode)
  849. {
  850. switch (roundMode)
  851. {
  852. case RoundMode.ToNearest:
  853. return nameof(Sse41.RoundToNearestInteger); // even
  854. case RoundMode.TowardsMinusInfinity:
  855. return nameof(Sse41.RoundToNegativeInfinity);
  856. case RoundMode.TowardsPlusInfinity:
  857. return nameof(Sse41.RoundToPositiveInfinity);
  858. case RoundMode.TowardsZero:
  859. return nameof(Sse41.RoundToZero);
  860. default: throw new ArgumentException(nameof(roundMode));
  861. }
  862. }
  863. }
  864. }