InstEmitSimdCmp.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  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.InstEmitAluHelper;
  9. using static ChocolArm64.Instructions.InstEmitSimdHelper;
  10. namespace ChocolArm64.Instructions
  11. {
  12. static partial class InstEmit
  13. {
  14. public static void Cmeq_S(ILEmitterCtx context)
  15. {
  16. EmitCmpOp(context, OpCodes.Beq_S, scalar: true);
  17. }
  18. public static void Cmeq_V(ILEmitterCtx context)
  19. {
  20. if (Optimizations.UseSse41)
  21. {
  22. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  23. Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] };
  24. Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse41);
  25. context.EmitLdvec(op.Rn);
  26. if (op is OpCodeSimdReg64 binOp)
  27. {
  28. context.EmitLdvec(binOp.Rm);
  29. }
  30. else
  31. {
  32. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  33. }
  34. context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareEqual), typesCmp));
  35. context.EmitStvec(op.Rd);
  36. if (op.RegisterSize == RegisterSize.Simd64)
  37. {
  38. EmitVectorZeroUpper(context, op.Rd);
  39. }
  40. }
  41. else
  42. {
  43. EmitCmpOp(context, OpCodes.Beq_S, scalar: false);
  44. }
  45. }
  46. public static void Cmge_S(ILEmitterCtx context)
  47. {
  48. EmitCmpOp(context, OpCodes.Bge_S, scalar: true);
  49. }
  50. public static void Cmge_V(ILEmitterCtx context)
  51. {
  52. if (Optimizations.UseSse42)
  53. {
  54. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  55. Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] };
  56. Type[] typesAnt = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) };
  57. Type[] typesSav = new Type[] { typeof(long) };
  58. Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42);
  59. if (op is OpCodeSimdReg64 binOp)
  60. {
  61. context.EmitLdvec(binOp.Rm);
  62. }
  63. else
  64. {
  65. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  66. }
  67. context.EmitLdvec(op.Rn);
  68. context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp));
  69. context.EmitLdc_I8(-1L);
  70. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  71. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt));
  72. context.EmitStvec(op.Rd);
  73. if (op.RegisterSize == RegisterSize.Simd64)
  74. {
  75. EmitVectorZeroUpper(context, op.Rd);
  76. }
  77. }
  78. else
  79. {
  80. EmitCmpOp(context, OpCodes.Bge_S, scalar: false);
  81. }
  82. }
  83. public static void Cmgt_S(ILEmitterCtx context)
  84. {
  85. EmitCmpOp(context, OpCodes.Bgt_S, scalar: true);
  86. }
  87. public static void Cmgt_V(ILEmitterCtx context)
  88. {
  89. if (Optimizations.UseSse42)
  90. {
  91. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  92. Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] };
  93. Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42);
  94. context.EmitLdvec(op.Rn);
  95. if (op is OpCodeSimdReg64 binOp)
  96. {
  97. context.EmitLdvec(binOp.Rm);
  98. }
  99. else
  100. {
  101. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  102. }
  103. context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp));
  104. context.EmitStvec(op.Rd);
  105. if (op.RegisterSize == RegisterSize.Simd64)
  106. {
  107. EmitVectorZeroUpper(context, op.Rd);
  108. }
  109. }
  110. else
  111. {
  112. EmitCmpOp(context, OpCodes.Bgt_S, scalar: false);
  113. }
  114. }
  115. public static void Cmhi_S(ILEmitterCtx context)
  116. {
  117. EmitCmpOp(context, OpCodes.Bgt_Un_S, scalar: true);
  118. }
  119. public static void Cmhi_V(ILEmitterCtx context)
  120. {
  121. OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;
  122. if (Optimizations.UseSse41 && op.Size < 3)
  123. {
  124. Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] };
  125. Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] };
  126. Type[] typesAnt = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) };
  127. Type[] typesSav = new Type[] { typeof(long) };
  128. Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41);
  129. context.EmitLdvec(op.Rm);
  130. context.EmitLdvec(op.Rn);
  131. context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax));
  132. context.EmitLdvec(op.Rm);
  133. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmp));
  134. context.EmitLdc_I8(-1L);
  135. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  136. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt));
  137. context.EmitStvec(op.Rd);
  138. if (op.RegisterSize == RegisterSize.Simd64)
  139. {
  140. EmitVectorZeroUpper(context, op.Rd);
  141. }
  142. }
  143. else
  144. {
  145. EmitCmpOp(context, OpCodes.Bgt_Un_S, scalar: false);
  146. }
  147. }
  148. public static void Cmhs_S(ILEmitterCtx context)
  149. {
  150. EmitCmpOp(context, OpCodes.Bge_Un_S, scalar: true);
  151. }
  152. public static void Cmhs_V(ILEmitterCtx context)
  153. {
  154. OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;
  155. if (Optimizations.UseSse41 && op.Size < 3)
  156. {
  157. Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] };
  158. Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] };
  159. Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41);
  160. context.EmitLdvec(op.Rn);
  161. context.EmitLdvec(op.Rm);
  162. context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax));
  163. context.EmitLdvec(op.Rn);
  164. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmp));
  165. context.EmitStvec(op.Rd);
  166. if (op.RegisterSize == RegisterSize.Simd64)
  167. {
  168. EmitVectorZeroUpper(context, op.Rd);
  169. }
  170. }
  171. else
  172. {
  173. EmitCmpOp(context, OpCodes.Bge_Un_S, scalar: false);
  174. }
  175. }
  176. public static void Cmle_S(ILEmitterCtx context)
  177. {
  178. EmitCmpOp(context, OpCodes.Ble_S, scalar: true);
  179. }
  180. public static void Cmle_V(ILEmitterCtx context)
  181. {
  182. if (Optimizations.UseSse42)
  183. {
  184. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  185. Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] };
  186. Type[] typesAnt = new Type[] { typeof(Vector128<long>), typeof(Vector128<long>) };
  187. Type[] typesSav = new Type[] { typeof(long) };
  188. Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42);
  189. context.EmitLdvec(op.Rn);
  190. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  191. context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp));
  192. context.EmitLdc_I8(-1L);
  193. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav));
  194. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt));
  195. context.EmitStvec(op.Rd);
  196. if (op.RegisterSize == RegisterSize.Simd64)
  197. {
  198. EmitVectorZeroUpper(context, op.Rd);
  199. }
  200. }
  201. else
  202. {
  203. EmitCmpOp(context, OpCodes.Ble_S, scalar: false);
  204. }
  205. }
  206. public static void Cmlt_S(ILEmitterCtx context)
  207. {
  208. EmitCmpOp(context, OpCodes.Blt_S, scalar: true);
  209. }
  210. public static void Cmlt_V(ILEmitterCtx context)
  211. {
  212. if (Optimizations.UseSse42)
  213. {
  214. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  215. Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] };
  216. Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42);
  217. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  218. context.EmitLdvec(op.Rn);
  219. context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp));
  220. context.EmitStvec(op.Rd);
  221. if (op.RegisterSize == RegisterSize.Simd64)
  222. {
  223. EmitVectorZeroUpper(context, op.Rd);
  224. }
  225. }
  226. else
  227. {
  228. EmitCmpOp(context, OpCodes.Blt_S, scalar: false);
  229. }
  230. }
  231. public static void Cmtst_S(ILEmitterCtx context)
  232. {
  233. EmitCmtstOp(context, scalar: true);
  234. }
  235. public static void Cmtst_V(ILEmitterCtx context)
  236. {
  237. EmitCmtstOp(context, scalar: false);
  238. }
  239. public static void Fccmp_S(ILEmitterCtx context)
  240. {
  241. OpCodeSimdFcond64 op = (OpCodeSimdFcond64)context.CurrOp;
  242. ILLabel lblTrue = new ILLabel();
  243. ILLabel lblEnd = new ILLabel();
  244. context.EmitCondBranch(lblTrue, op.Cond);
  245. context.EmitLdc_I4(op.Nzcv);
  246. EmitSetNzcv(context);
  247. context.Emit(OpCodes.Br, lblEnd);
  248. context.MarkLabel(lblTrue);
  249. EmitFcmpOrFcmpe(context, signalNaNs: false);
  250. context.MarkLabel(lblEnd);
  251. }
  252. public static void Fccmpe_S(ILEmitterCtx context)
  253. {
  254. OpCodeSimdFcond64 op = (OpCodeSimdFcond64)context.CurrOp;
  255. ILLabel lblTrue = new ILLabel();
  256. ILLabel lblEnd = new ILLabel();
  257. context.EmitCondBranch(lblTrue, op.Cond);
  258. context.EmitLdc_I4(op.Nzcv);
  259. EmitSetNzcv(context);
  260. context.Emit(OpCodes.Br, lblEnd);
  261. context.MarkLabel(lblTrue);
  262. EmitFcmpOrFcmpe(context, signalNaNs: true);
  263. context.MarkLabel(lblEnd);
  264. }
  265. public static void Fcmeq_S(ILEmitterCtx context)
  266. {
  267. if (Optimizations.FastFP && Optimizations.UseSse2)
  268. {
  269. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareEqualScalar), scalar: true);
  270. }
  271. else
  272. {
  273. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: true);
  274. }
  275. }
  276. public static void Fcmeq_V(ILEmitterCtx context)
  277. {
  278. if (Optimizations.FastFP && Optimizations.UseSse2)
  279. {
  280. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareEqual), scalar: false);
  281. }
  282. else
  283. {
  284. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: false);
  285. }
  286. }
  287. public static void Fcmge_S(ILEmitterCtx context)
  288. {
  289. if (Optimizations.FastFP && Optimizations.UseSse2)
  290. {
  291. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqualScalar), scalar: true);
  292. }
  293. else
  294. {
  295. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true);
  296. }
  297. }
  298. public static void Fcmge_V(ILEmitterCtx context)
  299. {
  300. if (Optimizations.FastFP && Optimizations.UseSse2)
  301. {
  302. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqual), scalar: false);
  303. }
  304. else
  305. {
  306. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false);
  307. }
  308. }
  309. public static void Fcmgt_S(ILEmitterCtx context)
  310. {
  311. if (Optimizations.FastFP && Optimizations.UseSse2)
  312. {
  313. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanScalar), scalar: true);
  314. }
  315. else
  316. {
  317. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true);
  318. }
  319. }
  320. public static void Fcmgt_V(ILEmitterCtx context)
  321. {
  322. if (Optimizations.FastFP && Optimizations.UseSse2)
  323. {
  324. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThan), scalar: false);
  325. }
  326. else
  327. {
  328. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false);
  329. }
  330. }
  331. public static void Fcmle_S(ILEmitterCtx context)
  332. {
  333. if (Optimizations.FastFP && Optimizations.UseSse2)
  334. {
  335. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqualScalar), scalar: true, isLeOrLt: true);
  336. }
  337. else
  338. {
  339. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: true);
  340. }
  341. }
  342. public static void Fcmle_V(ILEmitterCtx context)
  343. {
  344. if (Optimizations.FastFP && Optimizations.UseSse2)
  345. {
  346. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqual), scalar: false, isLeOrLt: true);
  347. }
  348. else
  349. {
  350. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: false);
  351. }
  352. }
  353. public static void Fcmlt_S(ILEmitterCtx context)
  354. {
  355. if (Optimizations.FastFP && Optimizations.UseSse2)
  356. {
  357. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanScalar), scalar: true, isLeOrLt: true);
  358. }
  359. else
  360. {
  361. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: true);
  362. }
  363. }
  364. public static void Fcmlt_V(ILEmitterCtx context)
  365. {
  366. if (Optimizations.FastFP && Optimizations.UseSse2)
  367. {
  368. EmitCmpSseOrSse2OpF(context, nameof(Sse.CompareGreaterThan), scalar: false, isLeOrLt: true);
  369. }
  370. else
  371. {
  372. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: false);
  373. }
  374. }
  375. public static void Fcmp_S(ILEmitterCtx context)
  376. {
  377. EmitFcmpOrFcmpe(context, signalNaNs: false);
  378. }
  379. public static void Fcmpe_S(ILEmitterCtx context)
  380. {
  381. EmitFcmpOrFcmpe(context, signalNaNs: true);
  382. }
  383. private static void EmitFcmpOrFcmpe(ILEmitterCtx context, bool signalNaNs)
  384. {
  385. OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;
  386. bool cmpWithZero = !(op is OpCodeSimdFcond64) ? op.Bit3 : false;
  387. if (Optimizations.FastFP && Optimizations.UseSse2)
  388. {
  389. if (op.Size == 0)
  390. {
  391. Type[] typesCmp = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) };
  392. ILLabel lblNaN = new ILLabel();
  393. ILLabel lblEnd = new ILLabel();
  394. context.EmitLdvec(op.Rn);
  395. if (cmpWithZero)
  396. {
  397. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  398. }
  399. else
  400. {
  401. context.EmitLdvec(op.Rm);
  402. }
  403. context.EmitStvectmp();
  404. context.EmitLdvectmp();
  405. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), typesCmp));
  406. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  407. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp));
  408. context.Emit(OpCodes.Brtrue_S, lblNaN);
  409. context.Emit(OpCodes.Ldc_I4_0);
  410. context.EmitLdvec(op.Rn);
  411. context.EmitLdvectmp();
  412. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), typesCmp));
  413. context.EmitLdvec(op.Rn);
  414. context.EmitLdvectmp();
  415. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp));
  416. context.EmitLdvec(op.Rn);
  417. context.EmitLdvectmp();
  418. context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), typesCmp));
  419. context.EmitStflg((int)PState.NBit);
  420. context.EmitStflg((int)PState.ZBit);
  421. context.EmitStflg((int)PState.CBit);
  422. context.EmitStflg((int)PState.VBit);
  423. context.Emit(OpCodes.Br_S, lblEnd);
  424. context.MarkLabel(lblNaN);
  425. context.Emit(OpCodes.Ldc_I4_1);
  426. context.Emit(OpCodes.Ldc_I4_1);
  427. context.Emit(OpCodes.Ldc_I4_0);
  428. context.Emit(OpCodes.Ldc_I4_0);
  429. context.EmitStflg((int)PState.NBit);
  430. context.EmitStflg((int)PState.ZBit);
  431. context.EmitStflg((int)PState.CBit);
  432. context.EmitStflg((int)PState.VBit);
  433. context.MarkLabel(lblEnd);
  434. }
  435. else /* if (op.Size == 1) */
  436. {
  437. Type[] typesCmp = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) };
  438. ILLabel lblNaN = new ILLabel();
  439. ILLabel lblEnd = new ILLabel();
  440. context.EmitLdvec(op.Rn);
  441. if (cmpWithZero)
  442. {
  443. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  444. }
  445. else
  446. {
  447. context.EmitLdvec(op.Rm);
  448. }
  449. context.EmitStvectmp();
  450. context.EmitLdvectmp();
  451. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrderedScalar), typesCmp));
  452. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  453. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp));
  454. context.Emit(OpCodes.Brtrue_S, lblNaN);
  455. context.Emit(OpCodes.Ldc_I4_0);
  456. context.EmitLdvec(op.Rn);
  457. context.EmitLdvectmp();
  458. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqualOrderedScalar), typesCmp));
  459. context.EmitLdvec(op.Rn);
  460. context.EmitLdvectmp();
  461. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp));
  462. context.EmitLdvec(op.Rn);
  463. context.EmitLdvectmp();
  464. context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrderedScalar), typesCmp));
  465. context.EmitStflg((int)PState.NBit);
  466. context.EmitStflg((int)PState.ZBit);
  467. context.EmitStflg((int)PState.CBit);
  468. context.EmitStflg((int)PState.VBit);
  469. context.Emit(OpCodes.Br_S, lblEnd);
  470. context.MarkLabel(lblNaN);
  471. context.Emit(OpCodes.Ldc_I4_1);
  472. context.Emit(OpCodes.Ldc_I4_1);
  473. context.Emit(OpCodes.Ldc_I4_0);
  474. context.Emit(OpCodes.Ldc_I4_0);
  475. context.EmitStflg((int)PState.NBit);
  476. context.EmitStflg((int)PState.ZBit);
  477. context.EmitStflg((int)PState.CBit);
  478. context.EmitStflg((int)PState.VBit);
  479. context.MarkLabel(lblEnd);
  480. }
  481. }
  482. else
  483. {
  484. EmitVectorExtractF(context, op.Rn, 0, op.Size);
  485. if (cmpWithZero)
  486. {
  487. if (op.Size == 0)
  488. {
  489. context.EmitLdc_R4(0f);
  490. }
  491. else /* if (op.Size == 1) */
  492. {
  493. context.EmitLdc_R8(0d);
  494. }
  495. }
  496. else
  497. {
  498. EmitVectorExtractF(context, op.Rm, 0, op.Size);
  499. }
  500. context.EmitLdc_I4(!signalNaNs ? 0 : 1);
  501. EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare));
  502. EmitSetNzcv(context);
  503. }
  504. }
  505. private static void EmitCmpOp(ILEmitterCtx context, OpCode ilOp, bool scalar)
  506. {
  507. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  508. int bytes = op.GetBitsCount() >> 3;
  509. int elems = !scalar ? bytes >> op.Size : 1;
  510. ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
  511. for (int index = 0; index < elems; index++)
  512. {
  513. EmitVectorExtractSx(context, op.Rn, index, op.Size);
  514. if (op is OpCodeSimdReg64 binOp)
  515. {
  516. EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
  517. }
  518. else
  519. {
  520. context.EmitLdc_I8(0L);
  521. }
  522. ILLabel lblTrue = new ILLabel();
  523. ILLabel lblEnd = new ILLabel();
  524. context.Emit(ilOp, lblTrue);
  525. EmitVectorInsert(context, op.Rd, index, op.Size, 0);
  526. context.Emit(OpCodes.Br_S, lblEnd);
  527. context.MarkLabel(lblTrue);
  528. EmitVectorInsert(context, op.Rd, index, op.Size, (long)szMask);
  529. context.MarkLabel(lblEnd);
  530. }
  531. if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
  532. {
  533. EmitVectorZeroUpper(context, op.Rd);
  534. }
  535. }
  536. private static void EmitCmtstOp(ILEmitterCtx context, bool scalar)
  537. {
  538. OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp;
  539. int bytes = op.GetBitsCount() >> 3;
  540. int elems = !scalar ? bytes >> op.Size : 1;
  541. ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
  542. for (int index = 0; index < elems; index++)
  543. {
  544. EmitVectorExtractZx(context, op.Rn, index, op.Size);
  545. EmitVectorExtractZx(context, op.Rm, index, op.Size);
  546. ILLabel lblTrue = new ILLabel();
  547. ILLabel lblEnd = new ILLabel();
  548. context.Emit(OpCodes.And);
  549. context.EmitLdc_I8(0L);
  550. context.Emit(OpCodes.Bne_Un_S, lblTrue);
  551. EmitVectorInsert(context, op.Rd, index, op.Size, 0);
  552. context.Emit(OpCodes.Br_S, lblEnd);
  553. context.MarkLabel(lblTrue);
  554. EmitVectorInsert(context, op.Rd, index, op.Size, (long)szMask);
  555. context.MarkLabel(lblEnd);
  556. }
  557. if ((op.RegisterSize == RegisterSize.Simd64) || scalar)
  558. {
  559. EmitVectorZeroUpper(context, op.Rd);
  560. }
  561. }
  562. private static void EmitCmpOpF(ILEmitterCtx context, string name, bool scalar)
  563. {
  564. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  565. int sizeF = op.Size & 1;
  566. int bytes = op.GetBitsCount() >> 3;
  567. int elems = !scalar ? bytes >> sizeF + 2 : 1;
  568. for (int index = 0; index < elems; index++)
  569. {
  570. EmitVectorExtractF(context, op.Rn, index, sizeF);
  571. if (op is OpCodeSimdReg64 binOp)
  572. {
  573. EmitVectorExtractF(context, binOp.Rm, index, sizeF);
  574. }
  575. else
  576. {
  577. if (sizeF == 0)
  578. {
  579. context.EmitLdc_R4(0f);
  580. }
  581. else /* if (sizeF == 1) */
  582. {
  583. context.EmitLdc_R8(0d);
  584. }
  585. }
  586. EmitSoftFloatCall(context, name);
  587. EmitVectorInsertF(context, op.Rd, index, sizeF);
  588. }
  589. if (!scalar)
  590. {
  591. if (op.RegisterSize == RegisterSize.Simd64)
  592. {
  593. EmitVectorZeroUpper(context, op.Rd);
  594. }
  595. }
  596. else
  597. {
  598. if (sizeF == 0)
  599. {
  600. EmitVectorZero32_128(context, op.Rd);
  601. }
  602. else /* if (sizeF == 1) */
  603. {
  604. EmitVectorZeroUpper(context, op.Rd);
  605. }
  606. }
  607. }
  608. private static void EmitCmpSseOrSse2OpF(ILEmitterCtx context, string name, bool scalar, bool isLeOrLt = false)
  609. {
  610. OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp;
  611. int sizeF = op.Size & 1;
  612. if (sizeF == 0)
  613. {
  614. Type[] types = new Type[] { typeof(Vector128<float>), typeof(Vector128<float>) };
  615. if (!isLeOrLt)
  616. {
  617. context.EmitLdvec(op.Rn);
  618. }
  619. if (op is OpCodeSimdReg64 binOp)
  620. {
  621. context.EmitLdvec(binOp.Rm);
  622. }
  623. else
  624. {
  625. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  626. }
  627. if (isLeOrLt)
  628. {
  629. context.EmitLdvec(op.Rn);
  630. }
  631. context.EmitCall(typeof(Sse).GetMethod(name, types));
  632. context.EmitStvec(op.Rd);
  633. if (scalar)
  634. {
  635. EmitVectorZero32_128(context, op.Rd);
  636. }
  637. else if (op.RegisterSize == RegisterSize.Simd64)
  638. {
  639. EmitVectorZeroUpper(context, op.Rd);
  640. }
  641. }
  642. else /* if (sizeF == 1) */
  643. {
  644. Type[] types = new Type[] { typeof(Vector128<double>), typeof(Vector128<double>) };
  645. if (!isLeOrLt)
  646. {
  647. context.EmitLdvec(op.Rn);
  648. }
  649. if (op is OpCodeSimdReg64 binOp)
  650. {
  651. context.EmitLdvec(binOp.Rm);
  652. }
  653. else
  654. {
  655. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero));
  656. }
  657. if (isLeOrLt)
  658. {
  659. context.EmitLdvec(op.Rn);
  660. }
  661. context.EmitCall(typeof(Sse2).GetMethod(name, types));
  662. context.EmitStvec(op.Rd);
  663. if (scalar)
  664. {
  665. EmitVectorZeroUpper(context, op.Rd);
  666. }
  667. }
  668. }
  669. }
  670. }