InstEmitSimdCmp.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.State;
  4. using ARMeilleure.Translation;
  5. using System;
  6. using static ARMeilleure.Instructions.InstEmitHelper;
  7. using static ARMeilleure.Instructions.InstEmitSimdHelper;
  8. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  9. namespace ARMeilleure.Instructions
  10. {
  11. using Func2I = Func<Operand, Operand, Operand>;
  12. static partial class InstEmit
  13. {
  14. public static void Cmeq_S(ArmEmitterContext context)
  15. {
  16. EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: true);
  17. }
  18. public static void Cmeq_V(ArmEmitterContext context)
  19. {
  20. if (Optimizations.UseSse41)
  21. {
  22. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  23. Operand n = GetVec(op.Rn);
  24. Operand m;
  25. if (op is OpCodeSimdReg binOp)
  26. {
  27. m = GetVec(binOp.Rm);
  28. }
  29. else
  30. {
  31. m = context.VectorZero();
  32. }
  33. Intrinsic cmpInst = X86PcmpeqInstruction[op.Size];
  34. Operand res = context.AddIntrinsic(cmpInst, n, m);
  35. if (op.RegisterSize == RegisterSize.Simd64)
  36. {
  37. res = context.VectorZeroUpper64(res);
  38. }
  39. context.Copy(GetVec(op.Rd), res);
  40. }
  41. else
  42. {
  43. EmitCmpOp(context, (op1, op2) => context.ICompareEqual(op1, op2), scalar: false);
  44. }
  45. }
  46. public static void Cmge_S(ArmEmitterContext context)
  47. {
  48. EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: true);
  49. }
  50. public static void Cmge_V(ArmEmitterContext context)
  51. {
  52. if (Optimizations.UseSse42)
  53. {
  54. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  55. Operand n = GetVec(op.Rn);
  56. Operand m;
  57. if (op is OpCodeSimdReg binOp)
  58. {
  59. m = GetVec(binOp.Rm);
  60. }
  61. else
  62. {
  63. m = context.VectorZero();
  64. }
  65. Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
  66. Operand res = context.AddIntrinsic(cmpInst, m, n);
  67. Operand mask = X86GetAllElements(context, -1L);
  68. res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask);
  69. if (op.RegisterSize == RegisterSize.Simd64)
  70. {
  71. res = context.VectorZeroUpper64(res);
  72. }
  73. context.Copy(GetVec(op.Rd), res);
  74. }
  75. else
  76. {
  77. EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqual(op1, op2), scalar: false);
  78. }
  79. }
  80. public static void Cmgt_S(ArmEmitterContext context)
  81. {
  82. EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: true);
  83. }
  84. public static void Cmgt_V(ArmEmitterContext context)
  85. {
  86. if (Optimizations.UseSse42)
  87. {
  88. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  89. Operand n = GetVec(op.Rn);
  90. Operand m;
  91. if (op is OpCodeSimdReg binOp)
  92. {
  93. m = GetVec(binOp.Rm);
  94. }
  95. else
  96. {
  97. m = context.VectorZero();
  98. }
  99. Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
  100. Operand res = context.AddIntrinsic(cmpInst, n, m);
  101. if (op.RegisterSize == RegisterSize.Simd64)
  102. {
  103. res = context.VectorZeroUpper64(res);
  104. }
  105. context.Copy(GetVec(op.Rd), res);
  106. }
  107. else
  108. {
  109. EmitCmpOp(context, (op1, op2) => context.ICompareGreater(op1, op2), scalar: false);
  110. }
  111. }
  112. public static void Cmhi_S(ArmEmitterContext context)
  113. {
  114. EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: true);
  115. }
  116. public static void Cmhi_V(ArmEmitterContext context)
  117. {
  118. OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
  119. if (Optimizations.UseSse41 && op.Size < 3)
  120. {
  121. Operand n = GetVec(op.Rn);
  122. Operand m = GetVec(op.Rm);
  123. Intrinsic maxInst = X86PmaxuInstruction[op.Size];
  124. Operand res = context.AddIntrinsic(maxInst, m, n);
  125. Intrinsic cmpInst = X86PcmpeqInstruction[op.Size];
  126. res = context.AddIntrinsic(cmpInst, res, m);
  127. Operand mask = X86GetAllElements(context, -1L);
  128. res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask);
  129. if (op.RegisterSize == RegisterSize.Simd64)
  130. {
  131. res = context.VectorZeroUpper64(res);
  132. }
  133. context.Copy(GetVec(op.Rd), res);
  134. }
  135. else
  136. {
  137. EmitCmpOp(context, (op1, op2) => context.ICompareGreaterUI(op1, op2), scalar: false);
  138. }
  139. }
  140. public static void Cmhs_S(ArmEmitterContext context)
  141. {
  142. EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: true);
  143. }
  144. public static void Cmhs_V(ArmEmitterContext context)
  145. {
  146. OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
  147. if (Optimizations.UseSse41 && op.Size < 3)
  148. {
  149. Operand n = GetVec(op.Rn);
  150. Operand m = GetVec(op.Rm);
  151. Intrinsic maxInst = X86PmaxuInstruction[op.Size];
  152. Operand res = context.AddIntrinsic(maxInst, n, m);
  153. Intrinsic cmpInst = X86PcmpeqInstruction[op.Size];
  154. res = context.AddIntrinsic(cmpInst, res, n);
  155. if (op.RegisterSize == RegisterSize.Simd64)
  156. {
  157. res = context.VectorZeroUpper64(res);
  158. }
  159. context.Copy(GetVec(op.Rd), res);
  160. }
  161. else
  162. {
  163. EmitCmpOp(context, (op1, op2) => context.ICompareGreaterOrEqualUI(op1, op2), scalar: false);
  164. }
  165. }
  166. public static void Cmle_S(ArmEmitterContext context)
  167. {
  168. EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: true);
  169. }
  170. public static void Cmle_V(ArmEmitterContext context)
  171. {
  172. if (Optimizations.UseSse42)
  173. {
  174. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  175. Operand n = GetVec(op.Rn);
  176. Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
  177. Operand res = context.AddIntrinsic(cmpInst, n, context.VectorZero());
  178. Operand mask = X86GetAllElements(context, -1L);
  179. res = context.AddIntrinsic(Intrinsic.X86Pandn, res, mask);
  180. if (op.RegisterSize == RegisterSize.Simd64)
  181. {
  182. res = context.VectorZeroUpper64(res);
  183. }
  184. context.Copy(GetVec(op.Rd), res);
  185. }
  186. else
  187. {
  188. EmitCmpOp(context, (op1, op2) => context.ICompareLessOrEqual(op1, op2), scalar: false);
  189. }
  190. }
  191. public static void Cmlt_S(ArmEmitterContext context)
  192. {
  193. EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: true);
  194. }
  195. public static void Cmlt_V(ArmEmitterContext context)
  196. {
  197. if (Optimizations.UseSse42)
  198. {
  199. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  200. Operand n = GetVec(op.Rn);
  201. Intrinsic cmpInst = X86PcmpgtInstruction[op.Size];
  202. Operand res = context.AddIntrinsic(cmpInst, context.VectorZero(), n);
  203. if (op.RegisterSize == RegisterSize.Simd64)
  204. {
  205. res = context.VectorZeroUpper64(res);
  206. }
  207. context.Copy(GetVec(op.Rd), res);
  208. }
  209. else
  210. {
  211. EmitCmpOp(context, (op1, op2) => context.ICompareLess(op1, op2), scalar: false);
  212. }
  213. }
  214. public static void Cmtst_S(ArmEmitterContext context)
  215. {
  216. EmitCmtstOp(context, scalar: true);
  217. }
  218. public static void Cmtst_V(ArmEmitterContext context)
  219. {
  220. EmitCmtstOp(context, scalar: false);
  221. }
  222. public static void Fccmp_S(ArmEmitterContext context)
  223. {
  224. EmitFccmpOrFccmpe(context, signalNaNs: false);
  225. }
  226. public static void Fccmpe_S(ArmEmitterContext context)
  227. {
  228. EmitFccmpOrFccmpe(context, signalNaNs: true);
  229. }
  230. public static void Fcmeq_S(ArmEmitterContext context)
  231. {
  232. if (Optimizations.FastFP && Optimizations.UseSse2)
  233. {
  234. EmitCmpSseOrSse2OpF(context, CmpCondition.Equal, scalar: true);
  235. }
  236. else
  237. {
  238. EmitCmpOpF(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, scalar: true);
  239. }
  240. }
  241. public static void Fcmeq_V(ArmEmitterContext context)
  242. {
  243. if (Optimizations.FastFP && Optimizations.UseSse2)
  244. {
  245. EmitCmpSseOrSse2OpF(context, CmpCondition.Equal, scalar: false);
  246. }
  247. else
  248. {
  249. EmitCmpOpF(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, scalar: false);
  250. }
  251. }
  252. public static void Fcmge_S(ArmEmitterContext context)
  253. {
  254. if (Optimizations.FastFP && Optimizations.UseSse2)
  255. {
  256. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: true);
  257. }
  258. else
  259. {
  260. EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: true);
  261. }
  262. }
  263. public static void Fcmge_V(ArmEmitterContext context)
  264. {
  265. if (Optimizations.FastFP && Optimizations.UseSse2)
  266. {
  267. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: false);
  268. }
  269. else
  270. {
  271. EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: false);
  272. }
  273. }
  274. public static void Fcmgt_S(ArmEmitterContext context)
  275. {
  276. if (Optimizations.FastFP && Optimizations.UseSse2)
  277. {
  278. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: true);
  279. }
  280. else
  281. {
  282. EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: true);
  283. }
  284. }
  285. public static void Fcmgt_V(ArmEmitterContext context)
  286. {
  287. if (Optimizations.FastFP && Optimizations.UseSse2)
  288. {
  289. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: false);
  290. }
  291. else
  292. {
  293. EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: false);
  294. }
  295. }
  296. public static void Fcmle_S(ArmEmitterContext context)
  297. {
  298. if (Optimizations.FastFP && Optimizations.UseSse2)
  299. {
  300. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: true, isLeOrLt: true);
  301. }
  302. else
  303. {
  304. EmitCmpOpF(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, scalar: true);
  305. }
  306. }
  307. public static void Fcmle_V(ArmEmitterContext context)
  308. {
  309. if (Optimizations.FastFP && Optimizations.UseSse2)
  310. {
  311. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThanOrEqual, scalar: false, isLeOrLt: true);
  312. }
  313. else
  314. {
  315. EmitCmpOpF(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, scalar: false);
  316. }
  317. }
  318. public static void Fcmlt_S(ArmEmitterContext context)
  319. {
  320. if (Optimizations.FastFP && Optimizations.UseSse2)
  321. {
  322. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: true, isLeOrLt: true);
  323. }
  324. else
  325. {
  326. EmitCmpOpF(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, scalar: true);
  327. }
  328. }
  329. public static void Fcmlt_V(ArmEmitterContext context)
  330. {
  331. if (Optimizations.FastFP && Optimizations.UseSse2)
  332. {
  333. EmitCmpSseOrSse2OpF(context, CmpCondition.GreaterThan, scalar: false, isLeOrLt: true);
  334. }
  335. else
  336. {
  337. EmitCmpOpF(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, scalar: false);
  338. }
  339. }
  340. public static void Fcmp_S(ArmEmitterContext context)
  341. {
  342. EmitFcmpOrFcmpe(context, signalNaNs: false);
  343. }
  344. public static void Fcmpe_S(ArmEmitterContext context)
  345. {
  346. EmitFcmpOrFcmpe(context, signalNaNs: true);
  347. }
  348. public static void EmitFccmpOrFccmpe(ArmEmitterContext context, bool signalNaNs)
  349. {
  350. OpCodeSimdFcond op = (OpCodeSimdFcond)context.CurrOp;
  351. Operand lblTrue = Label();
  352. Operand lblEnd = Label();
  353. context.BranchIfTrue(lblTrue, InstEmitFlowHelper.GetCondTrue(context, op.Cond));
  354. EmitSetNzcv(context, Const(op.Nzcv));
  355. context.Branch(lblEnd);
  356. context.MarkLabel(lblTrue);
  357. EmitFcmpOrFcmpe(context, signalNaNs);
  358. context.MarkLabel(lblEnd);
  359. }
  360. private static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs)
  361. {
  362. OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
  363. const int cmpOrdered = 7;
  364. bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;
  365. if (Optimizations.FastFP && Optimizations.UseSse2)
  366. {
  367. Operand n = GetVec(op.Rn);
  368. Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm);
  369. Operand lblNaN = Label();
  370. Operand lblEnd = Label();
  371. if (op.Size == 0)
  372. {
  373. Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const(cmpOrdered));
  374. Operand isOrdered = context.VectorExtract16(ordMask, 0);
  375. context.BranchIfFalse(lblNaN, isOrdered);
  376. Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, n, m);
  377. Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, n, m);
  378. Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, n, m);
  379. SetFlag(context, PState.VFlag, Const(0));
  380. SetFlag(context, PState.CFlag, cf);
  381. SetFlag(context, PState.ZFlag, zf);
  382. SetFlag(context, PState.NFlag, nf);
  383. }
  384. else /* if (op.Size == 1) */
  385. {
  386. Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const(cmpOrdered));
  387. Operand isOrdered = context.VectorExtract16(ordMask, 0);
  388. context.BranchIfFalse(lblNaN, isOrdered);
  389. Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, n, m);
  390. Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, n, m);
  391. Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, n, m);
  392. SetFlag(context, PState.VFlag, Const(0));
  393. SetFlag(context, PState.CFlag, cf);
  394. SetFlag(context, PState.ZFlag, zf);
  395. SetFlag(context, PState.NFlag, nf);
  396. }
  397. context.Branch(lblEnd);
  398. context.MarkLabel(lblNaN);
  399. SetFlag(context, PState.VFlag, Const(1));
  400. SetFlag(context, PState.CFlag, Const(1));
  401. SetFlag(context, PState.ZFlag, Const(0));
  402. SetFlag(context, PState.NFlag, Const(0));
  403. context.MarkLabel(lblEnd);
  404. }
  405. else
  406. {
  407. OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32;
  408. Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0);
  409. Operand me;
  410. if (cmpWithZero)
  411. {
  412. me = op.Size == 0 ? ConstF(0f) : ConstF(0d);
  413. }
  414. else
  415. {
  416. me = context.VectorExtract(type, GetVec(op.Rm), 0);
  417. }
  418. Delegate dlg = op.Size != 0
  419. ? (Delegate)new _S32_F64_F64_Bool(SoftFloat64.FPCompare)
  420. : (Delegate)new _S32_F32_F32_Bool(SoftFloat32.FPCompare);
  421. Operand nzcv = context.Call(dlg, ne, me, Const(signalNaNs));
  422. EmitSetNzcv(context, nzcv);
  423. }
  424. }
  425. private static void EmitSetNzcv(ArmEmitterContext context, Operand nzcv)
  426. {
  427. Operand Extract(Operand value, int bit)
  428. {
  429. if (bit != 0)
  430. {
  431. value = context.ShiftRightUI(value, Const(bit));
  432. }
  433. value = context.BitwiseAnd(value, Const(1));
  434. return value;
  435. }
  436. SetFlag(context, PState.VFlag, Extract(nzcv, 0));
  437. SetFlag(context, PState.CFlag, Extract(nzcv, 1));
  438. SetFlag(context, PState.ZFlag, Extract(nzcv, 2));
  439. SetFlag(context, PState.NFlag, Extract(nzcv, 3));
  440. }
  441. private static void EmitCmpOp(ArmEmitterContext context, Func2I emitCmp, bool scalar)
  442. {
  443. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  444. Operand res = context.VectorZero();
  445. int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
  446. ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
  447. for (int index = 0; index < elems; index++)
  448. {
  449. Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
  450. Operand me;
  451. if (op is OpCodeSimdReg binOp)
  452. {
  453. me = EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
  454. }
  455. else
  456. {
  457. me = Const(0L);
  458. }
  459. Operand isTrue = emitCmp(ne, me);
  460. Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
  461. res = EmitVectorInsert(context, res, mask, index, op.Size);
  462. }
  463. context.Copy(GetVec(op.Rd), res);
  464. }
  465. private static void EmitCmtstOp(ArmEmitterContext context, bool scalar)
  466. {
  467. OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
  468. Operand res = context.VectorZero();
  469. int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
  470. ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
  471. for (int index = 0; index < elems; index++)
  472. {
  473. Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
  474. Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
  475. Operand test = context.BitwiseAnd(ne, me);
  476. Operand isTrue = context.ICompareNotEqual(test, Const(0L));
  477. Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
  478. res = EmitVectorInsert(context, res, mask, index, op.Size);
  479. }
  480. context.Copy(GetVec(op.Rd), res);
  481. }
  482. private static void EmitCmpOpF(
  483. ArmEmitterContext context,
  484. _F32_F32_F32 f32,
  485. _F64_F64_F64 f64,
  486. bool scalar)
  487. {
  488. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  489. Operand res = context.VectorZero();
  490. int sizeF = op.Size & 1;
  491. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  492. int elems = !scalar ? op.GetBytesCount() >> sizeF + 2 : 1;
  493. for (int index = 0; index < elems; index++)
  494. {
  495. Operand ne = context.VectorExtract(type, GetVec(op.Rn), index);
  496. Operand me;
  497. if (op is OpCodeSimdReg binOp)
  498. {
  499. me = context.VectorExtract(type, GetVec(binOp.Rm), index);
  500. }
  501. else
  502. {
  503. me = sizeF == 0 ? ConstF(0f) : ConstF(0d);
  504. }
  505. Operand e = EmitSoftFloatCall(context, f32, f64, ne, me);
  506. res = context.VectorInsert(res, e, index);
  507. }
  508. context.Copy(GetVec(op.Rd), res);
  509. }
  510. private enum CmpCondition
  511. {
  512. Equal = 0,
  513. GreaterThanOrEqual = 5,
  514. GreaterThan = 6
  515. }
  516. private static void EmitCmpSseOrSse2OpF(
  517. ArmEmitterContext context,
  518. CmpCondition cond,
  519. bool scalar,
  520. bool isLeOrLt = false)
  521. {
  522. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  523. Operand n = GetVec(op.Rn);
  524. Operand m = op is OpCodeSimdReg binOp ? GetVec(binOp.Rm) : context.VectorZero();
  525. int sizeF = op.Size & 1;
  526. if (sizeF == 0)
  527. {
  528. Intrinsic inst = scalar ? Intrinsic.X86Cmpss : Intrinsic.X86Cmpps;
  529. Operand res = isLeOrLt
  530. ? context.AddIntrinsic(inst, m, n, Const((int)cond))
  531. : context.AddIntrinsic(inst, n, m, Const((int)cond));
  532. if (scalar)
  533. {
  534. res = context.VectorZeroUpper96(res);
  535. }
  536. else if (op.RegisterSize == RegisterSize.Simd64)
  537. {
  538. res = context.VectorZeroUpper64(res);
  539. }
  540. context.Copy(GetVec(op.Rd), res);
  541. }
  542. else /* if (sizeF == 1) */
  543. {
  544. Intrinsic inst = scalar ? Intrinsic.X86Cmpsd : Intrinsic.X86Cmppd;
  545. Operand res = isLeOrLt
  546. ? context.AddIntrinsic(inst, m, n, Const((int)cond))
  547. : context.AddIntrinsic(inst, n, m, Const((int)cond));
  548. if (scalar)
  549. {
  550. res = context.VectorZeroUpper64(res);
  551. }
  552. context.Copy(GetVec(op.Rd), res);
  553. }
  554. }
  555. }
  556. }