InstEmitSimdCmp.cs 24 KB

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