InstEmitSimdCmp.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  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.Operand.Factory;
  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 Facge_S(ArmEmitterContext context)
  223. {
  224. if (Optimizations.FastFP && Optimizations.UseAvx)
  225. {
  226. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true, absolute: true);
  227. }
  228. else
  229. {
  230. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true, absolute: true);
  231. }
  232. }
  233. public static void Facge_V(ArmEmitterContext context)
  234. {
  235. if (Optimizations.FastFP && Optimizations.UseAvx)
  236. {
  237. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false, absolute: true);
  238. }
  239. else
  240. {
  241. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false, absolute: true);
  242. }
  243. }
  244. public static void Facgt_S(ArmEmitterContext context)
  245. {
  246. if (Optimizations.FastFP && Optimizations.UseAvx)
  247. {
  248. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: true, absolute: true);
  249. }
  250. else
  251. {
  252. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true, absolute: true);
  253. }
  254. }
  255. public static void Facgt_V(ArmEmitterContext context)
  256. {
  257. if (Optimizations.FastFP && Optimizations.UseAvx)
  258. {
  259. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: false, absolute: true);
  260. }
  261. else
  262. {
  263. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false, absolute: true);
  264. }
  265. }
  266. public static void Fccmp_S(ArmEmitterContext context)
  267. {
  268. EmitFccmpOrFccmpe(context, signalNaNs: false);
  269. }
  270. public static void Fccmpe_S(ArmEmitterContext context)
  271. {
  272. EmitFccmpOrFccmpe(context, signalNaNs: true);
  273. }
  274. public static void Fcmeq_S(ArmEmitterContext context)
  275. {
  276. if (Optimizations.FastFP && Optimizations.UseSse2)
  277. {
  278. EmitSse2OrAvxCmpOpF(context, CmpCondition.Equal, scalar: true);
  279. }
  280. else
  281. {
  282. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: true);
  283. }
  284. }
  285. public static void Fcmeq_V(ArmEmitterContext context)
  286. {
  287. if (Optimizations.FastFP && Optimizations.UseSse2)
  288. {
  289. EmitSse2OrAvxCmpOpF(context, CmpCondition.Equal, scalar: false);
  290. }
  291. else
  292. {
  293. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: false);
  294. }
  295. }
  296. public static void Fcmge_S(ArmEmitterContext context)
  297. {
  298. if (Optimizations.FastFP && Optimizations.UseAvx)
  299. {
  300. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true);
  301. }
  302. else
  303. {
  304. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true);
  305. }
  306. }
  307. public static void Fcmge_V(ArmEmitterContext context)
  308. {
  309. if (Optimizations.FastFP && Optimizations.UseAvx)
  310. {
  311. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false);
  312. }
  313. else
  314. {
  315. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false);
  316. }
  317. }
  318. public static void Fcmgt_S(ArmEmitterContext context)
  319. {
  320. if (Optimizations.FastFP && Optimizations.UseAvx)
  321. {
  322. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: true);
  323. }
  324. else
  325. {
  326. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true);
  327. }
  328. }
  329. public static void Fcmgt_V(ArmEmitterContext context)
  330. {
  331. if (Optimizations.FastFP && Optimizations.UseAvx)
  332. {
  333. EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: false);
  334. }
  335. else
  336. {
  337. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false);
  338. }
  339. }
  340. public static void Fcmle_S(ArmEmitterContext context)
  341. {
  342. if (Optimizations.FastFP && Optimizations.UseSse2)
  343. {
  344. EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThanOrEqual, scalar: true);
  345. }
  346. else
  347. {
  348. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: true);
  349. }
  350. }
  351. public static void Fcmle_V(ArmEmitterContext context)
  352. {
  353. if (Optimizations.FastFP && Optimizations.UseSse2)
  354. {
  355. EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThanOrEqual, scalar: false);
  356. }
  357. else
  358. {
  359. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: false);
  360. }
  361. }
  362. public static void Fcmlt_S(ArmEmitterContext context)
  363. {
  364. if (Optimizations.FastFP && Optimizations.UseSse2)
  365. {
  366. EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThan, scalar: true);
  367. }
  368. else
  369. {
  370. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: true);
  371. }
  372. }
  373. public static void Fcmlt_V(ArmEmitterContext context)
  374. {
  375. if (Optimizations.FastFP && Optimizations.UseSse2)
  376. {
  377. EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThan, scalar: false);
  378. }
  379. else
  380. {
  381. EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: false);
  382. }
  383. }
  384. public static void Fcmp_S(ArmEmitterContext context)
  385. {
  386. EmitFcmpOrFcmpe(context, signalNaNs: false);
  387. }
  388. public static void Fcmpe_S(ArmEmitterContext context)
  389. {
  390. EmitFcmpOrFcmpe(context, signalNaNs: true);
  391. }
  392. private static void EmitFccmpOrFccmpe(ArmEmitterContext context, bool signalNaNs)
  393. {
  394. OpCodeSimdFcond op = (OpCodeSimdFcond)context.CurrOp;
  395. Operand lblTrue = Label();
  396. Operand lblEnd = Label();
  397. context.BranchIfTrue(lblTrue, InstEmitFlowHelper.GetCondTrue(context, op.Cond));
  398. EmitSetNzcv(context, op.Nzcv);
  399. context.Branch(lblEnd);
  400. context.MarkLabel(lblTrue);
  401. EmitFcmpOrFcmpe(context, signalNaNs);
  402. context.MarkLabel(lblEnd);
  403. }
  404. private static void EmitSetNzcv(ArmEmitterContext context, int nzcv)
  405. {
  406. Operand Extract(int value, int bit)
  407. {
  408. if (bit != 0)
  409. {
  410. value >>= bit;
  411. }
  412. value &= 1;
  413. return Const(value);
  414. }
  415. SetFlag(context, PState.VFlag, Extract(nzcv, 0));
  416. SetFlag(context, PState.CFlag, Extract(nzcv, 1));
  417. SetFlag(context, PState.ZFlag, Extract(nzcv, 2));
  418. SetFlag(context, PState.NFlag, Extract(nzcv, 3));
  419. }
  420. private static void EmitFcmpOrFcmpe(ArmEmitterContext context, bool signalNaNs)
  421. {
  422. OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
  423. bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;
  424. if (Optimizations.FastFP && (signalNaNs ? Optimizations.UseAvx : Optimizations.UseSse2))
  425. {
  426. Operand n = GetVec(op.Rn);
  427. Operand m = cmpWithZero ? context.VectorZero() : GetVec(op.Rm);
  428. CmpCondition cmpOrdered = signalNaNs ? CmpCondition.OrderedS : CmpCondition.OrderedQ;
  429. Operand lblNaN = Label();
  430. Operand lblEnd = Label();
  431. if (op.Size == 0)
  432. {
  433. Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpss, n, m, Const((int)cmpOrdered));
  434. Operand isOrdered = context.AddIntrinsicInt(Intrinsic.X86Cvtsi2si, ordMask);
  435. context.BranchIfFalse(lblNaN, isOrdered);
  436. Operand nCopy = context.Copy(n);
  437. Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m);
  438. Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comissge, nCopy, mCopy);
  439. Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisseq, nCopy, mCopy);
  440. Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisslt, nCopy, mCopy);
  441. SetFlag(context, PState.VFlag, Const(0));
  442. SetFlag(context, PState.CFlag, cf);
  443. SetFlag(context, PState.ZFlag, zf);
  444. SetFlag(context, PState.NFlag, nf);
  445. }
  446. else /* if (op.Size == 1) */
  447. {
  448. Operand ordMask = context.AddIntrinsic(Intrinsic.X86Cmpsd, n, m, Const((int)cmpOrdered));
  449. Operand isOrdered = context.AddIntrinsicLong(Intrinsic.X86Cvtsi2si, ordMask);
  450. context.BranchIfFalse(lblNaN, isOrdered);
  451. Operand nCopy = context.Copy(n);
  452. Operand mCopy = cmpWithZero ? context.VectorZero() : context.Copy(m);
  453. Operand cf = context.AddIntrinsicInt(Intrinsic.X86Comisdge, nCopy, mCopy);
  454. Operand zf = context.AddIntrinsicInt(Intrinsic.X86Comisdeq, nCopy, mCopy);
  455. Operand nf = context.AddIntrinsicInt(Intrinsic.X86Comisdlt, nCopy, mCopy);
  456. SetFlag(context, PState.VFlag, Const(0));
  457. SetFlag(context, PState.CFlag, cf);
  458. SetFlag(context, PState.ZFlag, zf);
  459. SetFlag(context, PState.NFlag, nf);
  460. }
  461. context.Branch(lblEnd);
  462. context.MarkLabel(lblNaN);
  463. SetFlag(context, PState.VFlag, Const(1));
  464. SetFlag(context, PState.CFlag, Const(1));
  465. SetFlag(context, PState.ZFlag, Const(0));
  466. SetFlag(context, PState.NFlag, Const(0));
  467. context.MarkLabel(lblEnd);
  468. }
  469. else
  470. {
  471. OperandType type = op.Size != 0 ? OperandType.FP64 : OperandType.FP32;
  472. Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0);
  473. Operand me;
  474. if (cmpWithZero)
  475. {
  476. me = op.Size == 0 ? ConstF(0f) : ConstF(0d);
  477. }
  478. else
  479. {
  480. me = context.VectorExtract(type, GetVec(op.Rm), 0);
  481. }
  482. Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));
  483. EmitSetNzcv(context, nzcv);
  484. }
  485. }
  486. private static void EmitSetNzcv(ArmEmitterContext context, Operand nzcv)
  487. {
  488. Operand Extract(Operand value, int bit)
  489. {
  490. if (bit != 0)
  491. {
  492. value = context.ShiftRightUI(value, Const(bit));
  493. }
  494. value = context.BitwiseAnd(value, Const(1));
  495. return value;
  496. }
  497. SetFlag(context, PState.VFlag, Extract(nzcv, 0));
  498. SetFlag(context, PState.CFlag, Extract(nzcv, 1));
  499. SetFlag(context, PState.ZFlag, Extract(nzcv, 2));
  500. SetFlag(context, PState.NFlag, Extract(nzcv, 3));
  501. }
  502. private static void EmitCmpOp(ArmEmitterContext context, Func2I emitCmp, bool scalar)
  503. {
  504. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  505. Operand res = context.VectorZero();
  506. int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
  507. ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
  508. for (int index = 0; index < elems; index++)
  509. {
  510. Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
  511. Operand me;
  512. if (op is OpCodeSimdReg binOp)
  513. {
  514. me = EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
  515. }
  516. else
  517. {
  518. me = Const(0L);
  519. }
  520. Operand isTrue = emitCmp(ne, me);
  521. Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
  522. res = EmitVectorInsert(context, res, mask, index, op.Size);
  523. }
  524. context.Copy(GetVec(op.Rd), res);
  525. }
  526. private static void EmitCmtstOp(ArmEmitterContext context, bool scalar)
  527. {
  528. OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
  529. Operand res = context.VectorZero();
  530. int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
  531. ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
  532. for (int index = 0; index < elems; index++)
  533. {
  534. Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
  535. Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
  536. Operand test = context.BitwiseAnd(ne, me);
  537. Operand isTrue = context.ICompareNotEqual(test, Const(0L));
  538. Operand mask = context.ConditionalSelect(isTrue, Const(szMask), Const(0L));
  539. res = EmitVectorInsert(context, res, mask, index, op.Size);
  540. }
  541. context.Copy(GetVec(op.Rd), res);
  542. }
  543. private static void EmitCmpOpF(ArmEmitterContext context, string name, bool scalar, bool absolute = false)
  544. {
  545. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  546. Operand res = context.VectorZero();
  547. int sizeF = op.Size & 1;
  548. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  549. int elems = !scalar ? op.GetBytesCount() >> sizeF + 2 : 1;
  550. for (int index = 0; index < elems; index++)
  551. {
  552. Operand ne = context.VectorExtract(type, GetVec(op.Rn), index);
  553. Operand me;
  554. if (op is OpCodeSimdReg binOp)
  555. {
  556. me = context.VectorExtract(type, GetVec(binOp.Rm), index);
  557. }
  558. else
  559. {
  560. me = sizeF == 0 ? ConstF(0f) : ConstF(0d);
  561. }
  562. if (absolute)
  563. {
  564. ne = EmitUnaryMathCall(context, nameof(Math.Abs), ne);
  565. me = EmitUnaryMathCall(context, nameof(Math.Abs), me);
  566. }
  567. Operand e = EmitSoftFloatCall(context, name, ne, me);
  568. res = context.VectorInsert(res, e, index);
  569. }
  570. context.Copy(GetVec(op.Rd), res);
  571. }
  572. private static void EmitSse2OrAvxCmpOpF(ArmEmitterContext context, CmpCondition cond, bool scalar, bool absolute = false)
  573. {
  574. OpCodeSimd op = (OpCodeSimd)context.CurrOp;
  575. Operand n = GetVec(op.Rn);
  576. Operand m = op is OpCodeSimdReg binOp ? GetVec(binOp.Rm) : context.VectorZero();
  577. int sizeF = op.Size & 1;
  578. if (sizeF == 0)
  579. {
  580. if (absolute)
  581. {
  582. Operand mask = scalar ? X86GetScalar(context, int.MaxValue) : X86GetAllElements(context, int.MaxValue);
  583. n = context.AddIntrinsic(Intrinsic.X86Andps, n, mask);
  584. m = context.AddIntrinsic(Intrinsic.X86Andps, m, mask);
  585. }
  586. Intrinsic inst = scalar ? Intrinsic.X86Cmpss : Intrinsic.X86Cmpps;
  587. Operand res = context.AddIntrinsic(inst, n, m, Const((int)cond));
  588. if (scalar)
  589. {
  590. res = context.VectorZeroUpper96(res);
  591. }
  592. else if (op.RegisterSize == RegisterSize.Simd64)
  593. {
  594. res = context.VectorZeroUpper64(res);
  595. }
  596. context.Copy(GetVec(op.Rd), res);
  597. }
  598. else /* if (sizeF == 1) */
  599. {
  600. if (absolute)
  601. {
  602. Operand mask = scalar ? X86GetScalar(context, long.MaxValue) : X86GetAllElements(context, long.MaxValue);
  603. n = context.AddIntrinsic(Intrinsic.X86Andpd, n, mask);
  604. m = context.AddIntrinsic(Intrinsic.X86Andpd, m, mask);
  605. }
  606. Intrinsic inst = scalar ? Intrinsic.X86Cmpsd : Intrinsic.X86Cmppd;
  607. Operand res = context.AddIntrinsic(inst, n, m, Const((int)cond));
  608. if (scalar)
  609. {
  610. res = context.VectorZeroUpper64(res);
  611. }
  612. context.Copy(GetVec(op.Rd), res);
  613. }
  614. }
  615. }
  616. }