InstEmitSimdCmp.cs 28 KB

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