InstEmitSimdCmp.cs 25 KB

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