InstEmitSimdCmp.cs 21 KB

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