InstEmitSimdArithmetic32.cs 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.Translation;
  4. using System;
  5. using System.Diagnostics;
  6. using static ARMeilleure.Instructions.InstEmitFlowHelper;
  7. using static ARMeilleure.Instructions.InstEmitHelper;
  8. using static ARMeilleure.Instructions.InstEmitSimdHelper;
  9. using static ARMeilleure.Instructions.InstEmitSimdHelper32;
  10. using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  11. namespace ARMeilleure.Instructions
  12. {
  13. static partial class InstEmit32
  14. {
  15. public static void Vabd_I(ArmEmitterContext context)
  16. {
  17. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  18. EmitVectorBinaryOpI32(context, (op1, op2) => EmitAbs(context, context.Subtract(op1, op2)), !op.U);
  19. }
  20. public static void Vabdl_I(ArmEmitterContext context)
  21. {
  22. OpCode32SimdRegLong op = (OpCode32SimdRegLong)context.CurrOp;
  23. EmitVectorBinaryLongOpI32(context, (op1, op2) => EmitAbs(context, context.Subtract(op1, op2)), !op.U);
  24. }
  25. public static void Vabs_S(ArmEmitterContext context)
  26. {
  27. OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
  28. if (Optimizations.FastFP && Optimizations.UseSse2)
  29. {
  30. EmitScalarUnaryOpSimd32(context, (m) =>
  31. {
  32. return EmitFloatAbs(context, m, (op.Size & 1) == 0, false);
  33. });
  34. }
  35. else
  36. {
  37. EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
  38. }
  39. }
  40. public static void Vabs_V(ArmEmitterContext context)
  41. {
  42. OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
  43. if (op.F)
  44. {
  45. if (Optimizations.FastFP && Optimizations.UseSse2)
  46. {
  47. EmitVectorUnaryOpSimd32(context, (m) =>
  48. {
  49. return EmitFloatAbs(context, m, (op.Size & 1) == 0, true);
  50. });
  51. }
  52. else
  53. {
  54. EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
  55. }
  56. }
  57. else
  58. {
  59. EmitVectorUnaryOpSx32(context, (op1) => EmitAbs(context, op1));
  60. }
  61. }
  62. private static Operand EmitAbs(ArmEmitterContext context, Operand value)
  63. {
  64. Operand isPositive = context.ICompareGreaterOrEqual(value, Const(value.Type, 0));
  65. return context.ConditionalSelect(isPositive, value, context.Negate(value));
  66. }
  67. public static void Vadd_S(ArmEmitterContext context)
  68. {
  69. if (Optimizations.FastFP && Optimizations.UseSse2)
  70. {
  71. EmitScalarBinaryOpF32(context, Intrinsic.X86Addss, Intrinsic.X86Addsd);
  72. }
  73. else if (Optimizations.FastFP)
  74. {
  75. EmitScalarBinaryOpF32(context, (op1, op2) => context.Add(op1, op2));
  76. }
  77. else
  78. {
  79. EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2));
  80. }
  81. }
  82. public static void Vadd_V(ArmEmitterContext context)
  83. {
  84. if (Optimizations.FastFP && Optimizations.UseSse2)
  85. {
  86. EmitVectorBinaryOpF32(context, Intrinsic.X86Addps, Intrinsic.X86Addpd);
  87. }
  88. else if (Optimizations.FastFP)
  89. {
  90. EmitVectorBinaryOpF32(context, (op1, op2) => context.Add(op1, op2));
  91. }
  92. else
  93. {
  94. EmitVectorBinaryOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPAddFpscr), op1, op2));
  95. }
  96. }
  97. public static void Vadd_I(ArmEmitterContext context)
  98. {
  99. if (Optimizations.UseSse2)
  100. {
  101. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  102. EmitVectorBinaryOpSimd32(context, (op1, op2) => context.AddIntrinsic(X86PaddInstruction[op.Size], op1, op2));
  103. }
  104. else
  105. {
  106. EmitVectorBinaryOpZx32(context, (op1, op2) => context.Add(op1, op2));
  107. }
  108. }
  109. public static void Vaddl_I(ArmEmitterContext context)
  110. {
  111. OpCode32SimdRegLong op = (OpCode32SimdRegLong)context.CurrOp;
  112. EmitVectorBinaryLongOpI32(context, (op1, op2) => context.Add(op1, op2), !op.U);
  113. }
  114. public static void Vaddw_I(ArmEmitterContext context)
  115. {
  116. OpCode32SimdRegWide op = (OpCode32SimdRegWide)context.CurrOp;
  117. EmitVectorBinaryWideOpI32(context, (op1, op2) => context.Add(op1, op2), !op.U);
  118. }
  119. public static void Vcnt(ArmEmitterContext context)
  120. {
  121. OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
  122. Operand res = GetVecA32(op.Qd);
  123. int elems = op.GetBytesCount();
  124. for (int index = 0; index < elems; index++)
  125. {
  126. Operand de;
  127. Operand me = EmitVectorExtractZx32(context, op.Qm, op.Im + index, op.Size);
  128. if (Optimizations.UsePopCnt)
  129. {
  130. de = context.AddIntrinsicInt(Intrinsic.X86Popcnt, me);
  131. }
  132. else
  133. {
  134. de = EmitCountSetBits8(context, me);
  135. }
  136. res = EmitVectorInsert(context, res, de, op.Id + index, op.Size);
  137. }
  138. context.Copy(GetVecA32(op.Qd), res);
  139. }
  140. public static void Vdup(ArmEmitterContext context)
  141. {
  142. OpCode32SimdDupGP op = (OpCode32SimdDupGP)context.CurrOp;
  143. Operand insert = GetIntA32(context, op.Rt);
  144. // Zero extend into an I64, then replicate. Saves the most time over elementwise inserts.
  145. insert = op.Size switch
  146. {
  147. 2 => context.Multiply(context.ZeroExtend32(OperandType.I64, insert), Const(0x0000000100000001u)),
  148. 1 => context.Multiply(context.ZeroExtend16(OperandType.I64, insert), Const(0x0001000100010001u)),
  149. 0 => context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u)),
  150. _ => throw new InvalidOperationException($"Invalid Vdup size \"{op.Size}\".")
  151. };
  152. InsertScalar(context, op.Vd, insert);
  153. if (op.Q)
  154. {
  155. InsertScalar(context, op.Vd + 1, insert);
  156. }
  157. }
  158. public static void Vdup_1(ArmEmitterContext context)
  159. {
  160. OpCode32SimdDupElem op = (OpCode32SimdDupElem)context.CurrOp;
  161. Operand insert = EmitVectorExtractZx32(context, op.Vm >> 1, ((op.Vm & 1) << (3 - op.Size)) + op.Index, op.Size);
  162. // Zero extend into an I64, then replicate. Saves the most time over elementwise inserts.
  163. insert = op.Size switch
  164. {
  165. 2 => context.Multiply(context.ZeroExtend32(OperandType.I64, insert), Const(0x0000000100000001u)),
  166. 1 => context.Multiply(context.ZeroExtend16(OperandType.I64, insert), Const(0x0001000100010001u)),
  167. 0 => context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u)),
  168. _ => throw new InvalidOperationException($"Invalid Vdup size \"{op.Size}\".")
  169. };
  170. InsertScalar(context, op.Vd, insert);
  171. if (op.Q)
  172. {
  173. InsertScalar(context, op.Vd | 1, insert);
  174. }
  175. }
  176. private static (long, long) MaskHelperByteSequence(int start, int length, int startByte)
  177. {
  178. int end = start + length;
  179. int b = startByte;
  180. long result = 0;
  181. long result2 = 0;
  182. for (int i = 0; i < 8; i++)
  183. {
  184. result |= (long)((i >= end || i < start) ? 0x80 : b++) << (i * 8);
  185. }
  186. for (int i = 8; i < 16; i++)
  187. {
  188. result2 |= (long)((i >= end || i < start) ? 0x80 : b++) << ((i - 8) * 8);
  189. }
  190. return (result2, result);
  191. }
  192. public static void Vext(ArmEmitterContext context)
  193. {
  194. OpCode32SimdExt op = (OpCode32SimdExt)context.CurrOp;
  195. int elems = op.GetBytesCount();
  196. int byteOff = op.Immediate;
  197. if (Optimizations.UseSsse3)
  198. {
  199. EmitVectorBinaryOpSimd32(context, (n, m) =>
  200. {
  201. // Writing low to high of d: start <imm> into n, overlap into m.
  202. // Then rotate n down by <imm>, m up by (elems)-imm.
  203. // Then OR them together for the result.
  204. (long nMaskHigh, long nMaskLow) = MaskHelperByteSequence(0, elems - byteOff, byteOff);
  205. (long mMaskHigh, long mMaskLow) = MaskHelperByteSequence(elems - byteOff, byteOff, 0);
  206. Operand nMask, mMask;
  207. if (!op.Q)
  208. {
  209. // Do the same operation to the bytes in the top doubleword too, as our target could be in either.
  210. nMaskHigh = nMaskLow + 0x0808080808080808L;
  211. mMaskHigh = mMaskLow + 0x0808080808080808L;
  212. }
  213. nMask = X86GetElements(context, nMaskHigh, nMaskLow);
  214. mMask = X86GetElements(context, mMaskHigh, mMaskLow);
  215. Operand nPart = context.AddIntrinsic(Intrinsic.X86Pshufb, n, nMask);
  216. Operand mPart = context.AddIntrinsic(Intrinsic.X86Pshufb, m, mMask);
  217. return context.AddIntrinsic(Intrinsic.X86Por, nPart, mPart);
  218. });
  219. }
  220. else
  221. {
  222. Operand res = GetVecA32(op.Qd);
  223. for (int index = 0; index < elems; index++)
  224. {
  225. Operand extract;
  226. if (byteOff >= elems)
  227. {
  228. extract = EmitVectorExtractZx32(context, op.Qm, op.Im + (byteOff - elems), op.Size);
  229. }
  230. else
  231. {
  232. extract = EmitVectorExtractZx32(context, op.Qn, op.In + byteOff, op.Size);
  233. }
  234. byteOff++;
  235. res = EmitVectorInsert(context, res, extract, op.Id + index, op.Size);
  236. }
  237. context.Copy(GetVecA32(op.Qd), res);
  238. }
  239. }
  240. public static void Vfma_S(ArmEmitterContext context) // Fused.
  241. {
  242. if (Optimizations.FastFP && Optimizations.UseFma)
  243. {
  244. EmitScalarTernaryOpF32(context, Intrinsic.X86Vfmadd231ss, Intrinsic.X86Vfmadd231sd);
  245. }
  246. else if (Optimizations.FastFP && Optimizations.UseSse2)
  247. {
  248. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Addss, Intrinsic.X86Addsd);
  249. }
  250. else
  251. {
  252. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  253. {
  254. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3);
  255. });
  256. }
  257. }
  258. public static void Vfma_V(ArmEmitterContext context) // Fused.
  259. {
  260. if (Optimizations.FastFP && Optimizations.UseFma)
  261. {
  262. EmitVectorTernaryOpF32(context, Intrinsic.X86Vfmadd231ps);
  263. }
  264. else
  265. {
  266. EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
  267. {
  268. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulAddFpscr), op1, op2, op3);
  269. });
  270. }
  271. }
  272. public static void Vfms_S(ArmEmitterContext context) // Fused.
  273. {
  274. if (Optimizations.FastFP && Optimizations.UseFma)
  275. {
  276. EmitScalarTernaryOpF32(context, Intrinsic.X86Vfnmadd231ss, Intrinsic.X86Vfnmadd231sd);
  277. }
  278. else if (Optimizations.FastFP && Optimizations.UseSse2)
  279. {
  280. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Subss, Intrinsic.X86Subsd);
  281. }
  282. else
  283. {
  284. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  285. {
  286. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3);
  287. });
  288. }
  289. }
  290. public static void Vfms_V(ArmEmitterContext context) // Fused.
  291. {
  292. if (Optimizations.FastFP && Optimizations.UseFma)
  293. {
  294. EmitVectorTernaryOpF32(context, Intrinsic.X86Vfnmadd231ps);
  295. }
  296. else
  297. {
  298. EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
  299. {
  300. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulSubFpscr), op1, op2, op3);
  301. });
  302. }
  303. }
  304. public static void Vfnma_S(ArmEmitterContext context) // Fused.
  305. {
  306. if (Optimizations.FastFP && Optimizations.UseFma)
  307. {
  308. EmitScalarTernaryOpF32(context, Intrinsic.X86Vfnmsub231ss, Intrinsic.X86Vfnmsub231sd);
  309. }
  310. else if (Optimizations.FastFP && Optimizations.UseSse2)
  311. {
  312. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Subss, Intrinsic.X86Subsd, isNegD: true);
  313. }
  314. else
  315. {
  316. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  317. {
  318. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulAdd), op1, op2, op3);
  319. });
  320. }
  321. }
  322. public static void Vfnms_S(ArmEmitterContext context) // Fused.
  323. {
  324. if (Optimizations.FastFP && Optimizations.UseFma)
  325. {
  326. EmitScalarTernaryOpF32(context, Intrinsic.X86Vfmsub231ss, Intrinsic.X86Vfmsub231sd);
  327. }
  328. else if (Optimizations.FastFP && Optimizations.UseSse2)
  329. {
  330. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Addss, Intrinsic.X86Addsd, isNegD: true);
  331. }
  332. else
  333. {
  334. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  335. {
  336. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulSub), op1, op2, op3);
  337. });
  338. }
  339. }
  340. public static void Vhadd(ArmEmitterContext context)
  341. {
  342. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  343. if (op.U)
  344. {
  345. EmitVectorBinaryOpZx32(context, (op1, op2) => context.ShiftRightUI(context.Add(op1, op2), Const(1)));
  346. }
  347. else
  348. {
  349. EmitVectorBinaryOpSx32(context, (op1, op2) => context.ShiftRightSI(context.Add(op1, op2), Const(1)));
  350. }
  351. }
  352. public static void Vmov_S(ArmEmitterContext context)
  353. {
  354. if (Optimizations.FastFP && Optimizations.UseSse2)
  355. {
  356. EmitScalarUnaryOpF32(context, 0, 0);
  357. }
  358. else
  359. {
  360. EmitScalarUnaryOpF32(context, (op1) => op1);
  361. }
  362. }
  363. public static void Vmovn(ArmEmitterContext context)
  364. {
  365. EmitVectorUnaryNarrowOp32(context, (op1) => op1);
  366. }
  367. public static void Vneg_S(ArmEmitterContext context)
  368. {
  369. OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
  370. if (Optimizations.UseSse2)
  371. {
  372. EmitScalarUnaryOpSimd32(context, (m) =>
  373. {
  374. if ((op.Size & 1) == 0)
  375. {
  376. Operand mask = X86GetScalar(context, -0f);
  377. return context.AddIntrinsic(Intrinsic.X86Xorps, mask, m);
  378. }
  379. else
  380. {
  381. Operand mask = X86GetScalar(context, -0d);
  382. return context.AddIntrinsic(Intrinsic.X86Xorpd, mask, m);
  383. }
  384. });
  385. }
  386. else
  387. {
  388. EmitScalarUnaryOpF32(context, (op1) => context.Negate(op1));
  389. }
  390. }
  391. public static void Vnmul_S(ArmEmitterContext context)
  392. {
  393. OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
  394. if (Optimizations.UseSse2)
  395. {
  396. EmitScalarBinaryOpSimd32(context, (n, m) =>
  397. {
  398. if ((op.Size & 1) == 0)
  399. {
  400. Operand res = context.AddIntrinsic(Intrinsic.X86Mulss, n, m);
  401. Operand mask = X86GetScalar(context, -0f);
  402. return context.AddIntrinsic(Intrinsic.X86Xorps, mask, res);
  403. }
  404. else
  405. {
  406. Operand res = context.AddIntrinsic(Intrinsic.X86Mulsd, n, m);
  407. Operand mask = X86GetScalar(context, -0d);
  408. return context.AddIntrinsic(Intrinsic.X86Xorpd, mask, res);
  409. }
  410. });
  411. }
  412. else
  413. {
  414. EmitScalarBinaryOpF32(context, (op1, op2) => context.Negate(context.Multiply(op1, op2)));
  415. }
  416. }
  417. public static void Vnmla_S(ArmEmitterContext context)
  418. {
  419. OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
  420. if (Optimizations.FastFP && Optimizations.UseSse2)
  421. {
  422. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Subss, Intrinsic.X86Subsd, isNegD: true);
  423. }
  424. else if (Optimizations.FastFP)
  425. {
  426. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  427. {
  428. return context.Subtract(context.Negate(op1), context.Multiply(op2, op3));
  429. });
  430. }
  431. else
  432. {
  433. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  434. {
  435. Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op2, op3);
  436. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), context.Negate(op1), res);
  437. });
  438. }
  439. }
  440. public static void Vnmls_S(ArmEmitterContext context)
  441. {
  442. OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
  443. if (Optimizations.FastFP && Optimizations.UseSse2)
  444. {
  445. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Addss, Intrinsic.X86Addsd, isNegD: true);
  446. }
  447. else if (Optimizations.FastFP)
  448. {
  449. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  450. {
  451. return context.Add(context.Negate(op1), context.Multiply(op2, op3));
  452. });
  453. }
  454. else
  455. {
  456. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  457. {
  458. Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op2, op3);
  459. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), context.Negate(op1), res);
  460. });
  461. }
  462. }
  463. public static void Vneg_V(ArmEmitterContext context)
  464. {
  465. OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
  466. if (op.F)
  467. {
  468. if (Optimizations.FastFP && Optimizations.UseSse2)
  469. {
  470. EmitVectorUnaryOpSimd32(context, (m) =>
  471. {
  472. if ((op.Size & 1) == 0)
  473. {
  474. Operand mask = X86GetAllElements(context, -0f);
  475. return context.AddIntrinsic(Intrinsic.X86Xorps, mask, m);
  476. }
  477. else
  478. {
  479. Operand mask = X86GetAllElements(context, -0d);
  480. return context.AddIntrinsic(Intrinsic.X86Xorpd, mask, m);
  481. }
  482. });
  483. }
  484. else
  485. {
  486. EmitVectorUnaryOpF32(context, (op1) => context.Negate(op1));
  487. }
  488. }
  489. else
  490. {
  491. EmitVectorUnaryOpSx32(context, (op1) => context.Negate(op1));
  492. }
  493. }
  494. public static void Vdiv_S(ArmEmitterContext context)
  495. {
  496. if (Optimizations.FastFP && Optimizations.UseSse2)
  497. {
  498. EmitScalarBinaryOpF32(context, Intrinsic.X86Divss, Intrinsic.X86Divsd);
  499. }
  500. else if (Optimizations.FastFP)
  501. {
  502. EmitScalarBinaryOpF32(context, (op1, op2) => context.Divide(op1, op2));
  503. }
  504. else
  505. {
  506. EmitScalarBinaryOpF32(context, (op1, op2) =>
  507. {
  508. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv), op1, op2);
  509. });
  510. }
  511. }
  512. public static void Vmaxnm_S(ArmEmitterContext context)
  513. {
  514. if (Optimizations.FastFP && Optimizations.UseSse41)
  515. {
  516. EmitSse41MaxMinNumOpF32(context, true, true);
  517. }
  518. else
  519. {
  520. EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2));
  521. }
  522. }
  523. public static void Vmaxnm_V(ArmEmitterContext context)
  524. {
  525. if (Optimizations.FastFP && Optimizations.UseSse41)
  526. {
  527. EmitSse41MaxMinNumOpF32(context, true, false);
  528. }
  529. else
  530. {
  531. EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMaxNumFpscr), op1, op2));
  532. }
  533. }
  534. public static void Vminnm_S(ArmEmitterContext context)
  535. {
  536. if (Optimizations.FastFP && Optimizations.UseSse41)
  537. {
  538. EmitSse41MaxMinNumOpF32(context, false, true);
  539. }
  540. else
  541. {
  542. EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2));
  543. }
  544. }
  545. public static void Vminnm_V(ArmEmitterContext context)
  546. {
  547. if (Optimizations.FastFP && Optimizations.UseSse41)
  548. {
  549. EmitSse41MaxMinNumOpF32(context, false, false);
  550. }
  551. else
  552. {
  553. EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMinNumFpscr), op1, op2));
  554. }
  555. }
  556. public static void Vmax_V(ArmEmitterContext context)
  557. {
  558. if (Optimizations.FastFP && Optimizations.UseSse2)
  559. {
  560. EmitVectorBinaryOpF32(context, Intrinsic.X86Maxps, Intrinsic.X86Maxpd);
  561. }
  562. else
  563. {
  564. EmitVectorBinaryOpF32(context, (op1, op2) =>
  565. {
  566. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMaxFpscr), op1, op2);
  567. });
  568. }
  569. }
  570. public static void Vmax_I(ArmEmitterContext context)
  571. {
  572. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  573. if (op.U)
  574. {
  575. if (Optimizations.UseSse2)
  576. {
  577. EmitVectorBinaryOpSimd32(context, (op1, op2) => context.AddIntrinsic(X86PmaxuInstruction[op.Size], op1, op2));
  578. }
  579. else
  580. {
  581. EmitVectorBinaryOpZx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareGreaterUI(op1, op2), op1, op2));
  582. }
  583. }
  584. else
  585. {
  586. if (Optimizations.UseSse2)
  587. {
  588. EmitVectorBinaryOpSimd32(context, (op1, op2) => context.AddIntrinsic(X86PmaxsInstruction[op.Size], op1, op2));
  589. }
  590. else
  591. {
  592. EmitVectorBinaryOpSx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareGreater(op1, op2), op1, op2));
  593. }
  594. }
  595. }
  596. public static void Vmin_V(ArmEmitterContext context)
  597. {
  598. if (Optimizations.FastFP && Optimizations.UseSse2)
  599. {
  600. EmitVectorBinaryOpF32(context, Intrinsic.X86Minps, Intrinsic.X86Minpd);
  601. }
  602. else
  603. {
  604. EmitVectorBinaryOpF32(context, (op1, op2) =>
  605. {
  606. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMinFpscr), op1, op2);
  607. });
  608. }
  609. }
  610. public static void Vmin_I(ArmEmitterContext context)
  611. {
  612. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  613. if (op.U)
  614. {
  615. if (Optimizations.UseSse2)
  616. {
  617. EmitVectorBinaryOpSimd32(context, (op1, op2) => context.AddIntrinsic(X86PminuInstruction[op.Size], op1, op2));
  618. }
  619. else
  620. {
  621. EmitVectorBinaryOpZx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareLessUI(op1, op2), op1, op2));
  622. }
  623. }
  624. else
  625. {
  626. if (Optimizations.UseSse2)
  627. {
  628. EmitVectorBinaryOpSimd32(context, (op1, op2) => context.AddIntrinsic(X86PminsInstruction[op.Size], op1, op2));
  629. }
  630. else
  631. {
  632. EmitVectorBinaryOpSx32(context, (op1, op2) => context.ConditionalSelect(context.ICompareLess(op1, op2), op1, op2));
  633. }
  634. }
  635. }
  636. public static void Vmla_S(ArmEmitterContext context)
  637. {
  638. if (Optimizations.FastFP && Optimizations.UseSse2)
  639. {
  640. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Addss, Intrinsic.X86Addsd);
  641. }
  642. else if (Optimizations.FastFP)
  643. {
  644. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  645. {
  646. return context.Add(op1, context.Multiply(op2, op3));
  647. });
  648. }
  649. else
  650. {
  651. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  652. {
  653. Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op2, op3);
  654. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, res);
  655. });
  656. }
  657. }
  658. public static void Vmla_V(ArmEmitterContext context)
  659. {
  660. if (Optimizations.FastFP && Optimizations.UseSse2)
  661. {
  662. EmitVectorTernaryOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd, Intrinsic.X86Addps, Intrinsic.X86Addpd);
  663. }
  664. else if (Optimizations.FastFP)
  665. {
  666. EmitVectorTernaryOpF32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)));
  667. }
  668. else
  669. {
  670. EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
  671. {
  672. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulAddFpscr), op1, op2, op3);
  673. });
  674. }
  675. }
  676. public static void Vmla_I(ArmEmitterContext context)
  677. {
  678. EmitVectorTernaryOpZx32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)));
  679. }
  680. public static void Vmla_1(ArmEmitterContext context)
  681. {
  682. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  683. if (op.F)
  684. {
  685. if (Optimizations.FastFP && Optimizations.UseSse2)
  686. {
  687. EmitVectorsByScalarOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd, Intrinsic.X86Addps, Intrinsic.X86Addpd);
  688. }
  689. else if (Optimizations.FastFP)
  690. {
  691. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)));
  692. }
  693. else
  694. {
  695. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulAddFpscr), op1, op2, op3));
  696. }
  697. }
  698. else
  699. {
  700. EmitVectorsByScalarOpI32(context, (op1, op2, op3) => context.Add(op1, context.Multiply(op2, op3)), false);
  701. }
  702. }
  703. public static void Vmls_S(ArmEmitterContext context)
  704. {
  705. if (Optimizations.FastFP && Optimizations.UseSse2)
  706. {
  707. EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Subss, Intrinsic.X86Subsd);
  708. }
  709. else if (Optimizations.FastFP)
  710. {
  711. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  712. {
  713. return context.Subtract(op1, context.Multiply(op2, op3));
  714. });
  715. }
  716. else
  717. {
  718. EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
  719. {
  720. Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op2, op3);
  721. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, res);
  722. });
  723. }
  724. }
  725. public static void Vmls_V(ArmEmitterContext context)
  726. {
  727. if (Optimizations.FastFP && Optimizations.UseSse2)
  728. {
  729. EmitVectorTernaryOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd, Intrinsic.X86Subps, Intrinsic.X86Subpd);
  730. }
  731. else if (Optimizations.FastFP)
  732. {
  733. EmitVectorTernaryOpF32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)));
  734. }
  735. else
  736. {
  737. EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
  738. {
  739. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulSubFpscr), op1, op2, op3);
  740. });
  741. }
  742. }
  743. public static void Vmls_I(ArmEmitterContext context)
  744. {
  745. EmitVectorTernaryOpZx32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)));
  746. }
  747. public static void Vmls_1(ArmEmitterContext context)
  748. {
  749. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  750. if (op.F)
  751. {
  752. if (Optimizations.FastFP && Optimizations.UseSse2)
  753. {
  754. EmitVectorsByScalarOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd, Intrinsic.X86Subps, Intrinsic.X86Subpd);
  755. }
  756. else if (Optimizations.FastFP)
  757. {
  758. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)));
  759. }
  760. else
  761. {
  762. EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulSubFpscr), op1, op2, op3));
  763. }
  764. }
  765. else
  766. {
  767. EmitVectorsByScalarOpI32(context, (op1, op2, op3) => context.Subtract(op1, context.Multiply(op2, op3)), false);
  768. }
  769. }
  770. public static void Vmlsl_I(ArmEmitterContext context)
  771. {
  772. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  773. EmitVectorTernaryLongOpI32(context, (opD, op1, op2) => context.Subtract(opD, context.Multiply(op1, op2)), !op.U);
  774. }
  775. public static void Vmul_S(ArmEmitterContext context)
  776. {
  777. if (Optimizations.FastFP && Optimizations.UseSse2)
  778. {
  779. EmitScalarBinaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd);
  780. }
  781. else if (Optimizations.FastFP)
  782. {
  783. EmitScalarBinaryOpF32(context, (op1, op2) => context.Multiply(op1, op2));
  784. }
  785. else
  786. {
  787. EmitScalarBinaryOpF32(context, (op1, op2) =>
  788. {
  789. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2);
  790. });
  791. }
  792. }
  793. public static void Vmul_V(ArmEmitterContext context)
  794. {
  795. if (Optimizations.FastFP && Optimizations.UseSse2)
  796. {
  797. EmitVectorBinaryOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd);
  798. }
  799. else if (Optimizations.FastFP)
  800. {
  801. EmitVectorBinaryOpF32(context, (op1, op2) => context.Multiply(op1, op2));
  802. }
  803. else
  804. {
  805. EmitVectorBinaryOpF32(context, (op1, op2) =>
  806. {
  807. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulFpscr), op1, op2);
  808. });
  809. }
  810. }
  811. public static void Vmul_I(ArmEmitterContext context)
  812. {
  813. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  814. if (op.U) // This instruction is always signed, U indicates polynomial mode.
  815. {
  816. EmitVectorBinaryOpZx32(context, (op1, op2) => EmitPolynomialMultiply(context, op1, op2, 8 << op.Size));
  817. }
  818. else
  819. {
  820. EmitVectorBinaryOpSx32(context, (op1, op2) => context.Multiply(op1, op2));
  821. }
  822. }
  823. public static void Vmul_1(ArmEmitterContext context)
  824. {
  825. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  826. if (op.F)
  827. {
  828. if (Optimizations.FastFP && Optimizations.UseSse2)
  829. {
  830. EmitVectorByScalarOpF32(context, Intrinsic.X86Mulps, Intrinsic.X86Mulpd);
  831. }
  832. else if (Optimizations.FastFP)
  833. {
  834. EmitVectorByScalarOpF32(context, (op1, op2) => context.Multiply(op1, op2));
  835. }
  836. else
  837. {
  838. EmitVectorByScalarOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulFpscr), op1, op2));
  839. }
  840. }
  841. else
  842. {
  843. EmitVectorByScalarOpI32(context, (op1, op2) => context.Multiply(op1, op2), false);
  844. }
  845. }
  846. public static void Vmull_1(ArmEmitterContext context)
  847. {
  848. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  849. EmitVectorByScalarLongOpI32(context, (op1, op2) => context.Multiply(op1, op2), !op.U);
  850. }
  851. public static void Vmull_I(ArmEmitterContext context)
  852. {
  853. OpCode32SimdRegLong op = (OpCode32SimdRegLong)context.CurrOp;
  854. if (op.Polynomial)
  855. {
  856. if (op.Size == 0) // P8
  857. {
  858. EmitVectorBinaryLongOpI32(context, (op1, op2) => EmitPolynomialMultiply(context, op1, op2, 8 << op.Size), false);
  859. }
  860. else /* if (op.Size == 2) // P64 */
  861. {
  862. Operand ne = context.VectorExtract(OperandType.I64, GetVec(op.Qn), op.Vn & 1);
  863. Operand me = context.VectorExtract(OperandType.I64, GetVec(op.Qm), op.Vm & 1);
  864. Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)), ne, me);
  865. context.Copy(GetVecA32(op.Qd), res);
  866. }
  867. }
  868. else
  869. {
  870. EmitVectorBinaryLongOpI32(context, (op1, op2) => context.Multiply(op1, op2), !op.U);
  871. }
  872. }
  873. public static void Vpadd_V(ArmEmitterContext context)
  874. {
  875. if (Optimizations.FastFP && Optimizations.UseSse2)
  876. {
  877. EmitSse2VectorPairwiseOpF32(context, Intrinsic.X86Addps);
  878. }
  879. else
  880. {
  881. EmitVectorPairwiseOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPAddFpscr), op1, op2));
  882. }
  883. }
  884. public static void Vpadd_I(ArmEmitterContext context)
  885. {
  886. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  887. if (Optimizations.UseSsse3)
  888. {
  889. EmitSsse3VectorPairwiseOp32(context, X86PaddInstruction);
  890. }
  891. else
  892. {
  893. EmitVectorPairwiseOpI32(context, (op1, op2) => context.Add(op1, op2), !op.U);
  894. }
  895. }
  896. public static void Vpmax_V(ArmEmitterContext context)
  897. {
  898. if (Optimizations.FastFP && Optimizations.UseSse2)
  899. {
  900. EmitSse2VectorPairwiseOpF32(context, Intrinsic.X86Maxps);
  901. }
  902. else
  903. {
  904. EmitVectorPairwiseOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat64.FPMaxFpscr), op1, op2));
  905. }
  906. }
  907. public static void Vpmax_I(ArmEmitterContext context)
  908. {
  909. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  910. if (Optimizations.UseSsse3)
  911. {
  912. EmitSsse3VectorPairwiseOp32(context, op.U ? X86PmaxuInstruction : X86PmaxsInstruction);
  913. }
  914. else
  915. {
  916. EmitVectorPairwiseOpI32(context, (op1, op2) =>
  917. {
  918. Operand greater = op.U ? context.ICompareGreaterUI(op1, op2) : context.ICompareGreater(op1, op2);
  919. return context.ConditionalSelect(greater, op1, op2);
  920. }, !op.U);
  921. }
  922. }
  923. public static void Vpmin_V(ArmEmitterContext context)
  924. {
  925. if (Optimizations.FastFP && Optimizations.UseSse2)
  926. {
  927. EmitSse2VectorPairwiseOpF32(context, Intrinsic.X86Minps);
  928. }
  929. else
  930. {
  931. EmitVectorPairwiseOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMinFpscr), op1, op2));
  932. }
  933. }
  934. public static void Vpmin_I(ArmEmitterContext context)
  935. {
  936. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  937. if (Optimizations.UseSsse3)
  938. {
  939. EmitSsse3VectorPairwiseOp32(context, op.U ? X86PminuInstruction : X86PminsInstruction);
  940. }
  941. else
  942. {
  943. EmitVectorPairwiseOpI32(context, (op1, op2) =>
  944. {
  945. Operand greater = op.U ? context.ICompareLessUI(op1, op2) : context.ICompareLess(op1, op2);
  946. return context.ConditionalSelect(greater, op1, op2);
  947. }, !op.U);
  948. }
  949. }
  950. public static void Vrev(ArmEmitterContext context)
  951. {
  952. OpCode32SimdRev op = (OpCode32SimdRev)context.CurrOp;
  953. if (Optimizations.UseSsse3)
  954. {
  955. EmitVectorUnaryOpSimd32(context, (op1) =>
  956. {
  957. Operand mask;
  958. switch (op.Size)
  959. {
  960. case 3:
  961. // Rev64
  962. switch (op.Opc)
  963. {
  964. case 0:
  965. mask = X86GetElements(context, 0x08090a0b0c0d0e0fL, 0x0001020304050607L);
  966. return context.AddIntrinsic(Intrinsic.X86Pshufb, op1, mask);
  967. case 1:
  968. mask = X86GetElements(context, 0x09080b0a0d0c0f0eL, 0x0100030205040706L);
  969. return context.AddIntrinsic(Intrinsic.X86Pshufb, op1, mask);
  970. case 2:
  971. return context.AddIntrinsic(Intrinsic.X86Shufps, op1, op1, Const(1 | (0 << 2) | (3 << 4) | (2 << 6)));
  972. }
  973. break;
  974. case 2:
  975. // Rev32
  976. switch (op.Opc)
  977. {
  978. case 0:
  979. mask = X86GetElements(context, 0x0c0d0e0f_08090a0bL, 0x04050607_00010203L);
  980. return context.AddIntrinsic(Intrinsic.X86Pshufb, op1, mask);
  981. case 1:
  982. mask = X86GetElements(context, 0x0d0c0f0e_09080b0aL, 0x05040706_01000302L);
  983. return context.AddIntrinsic(Intrinsic.X86Pshufb, op1, mask);
  984. }
  985. break;
  986. case 1:
  987. // Rev16
  988. mask = X86GetElements(context, 0x0e0f_0c0d_0a0b_0809L, 0x_0607_0405_0203_0001L);
  989. return context.AddIntrinsic(Intrinsic.X86Pshufb, op1, mask);
  990. }
  991. throw new InvalidOperationException("Invalid VREV Opcode + Size combo."); // Should be unreachable.
  992. });
  993. }
  994. else
  995. {
  996. EmitVectorUnaryOpZx32(context, (op1) =>
  997. {
  998. switch (op.Opc)
  999. {
  1000. case 0:
  1001. switch (op.Size) // Swap bytes.
  1002. {
  1003. case 1:
  1004. return InstEmitAluHelper.EmitReverseBytes16_32Op(context, op1);
  1005. case 2:
  1006. case 3:
  1007. return context.ByteSwap(op1);
  1008. }
  1009. break;
  1010. case 1:
  1011. switch (op.Size)
  1012. {
  1013. case 2:
  1014. return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff0000)), Const(16)),
  1015. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x0000ffff)), Const(16)));
  1016. case 3:
  1017. return context.BitwiseOr(
  1018. context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff000000000000ul)), Const(48)),
  1019. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x000000000000fffful)), Const(48))),
  1020. context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0x0000ffff00000000ul)), Const(16)),
  1021. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000ffff0000ul)), Const(16))));
  1022. }
  1023. break;
  1024. case 2:
  1025. // Swap upper and lower halves.
  1026. return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffffffff00000000ul)), Const(32)),
  1027. context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000fffffffful)), Const(32)));
  1028. }
  1029. throw new InvalidOperationException("Invalid VREV Opcode + Size combo."); // Should be unreachable.
  1030. });
  1031. }
  1032. }
  1033. public static void Vrecpe(ArmEmitterContext context)
  1034. {
  1035. OpCode32SimdSqrte op = (OpCode32SimdSqrte)context.CurrOp;
  1036. if (op.F)
  1037. {
  1038. int sizeF = op.Size & 1;
  1039. if (Optimizations.FastFP && Optimizations.UseSse2 && sizeF == 0)
  1040. {
  1041. EmitVectorUnaryOpF32(context, Intrinsic.X86Rcpps, 0);
  1042. }
  1043. else
  1044. {
  1045. EmitVectorUnaryOpF32(context, (op1) =>
  1046. {
  1047. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPRecipEstimateFpscr), op1);
  1048. });
  1049. }
  1050. }
  1051. else
  1052. {
  1053. throw new NotImplementedException("Integer Vrecpe not currently implemented.");
  1054. }
  1055. }
  1056. public static void Vrecps(ArmEmitterContext context)
  1057. {
  1058. if (Optimizations.FastFP && Optimizations.UseSse2)
  1059. {
  1060. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  1061. bool single = (op.Size & 1) == 0;
  1062. // (2 - (n*m))
  1063. EmitVectorBinaryOpSimd32(context, (n, m) =>
  1064. {
  1065. if (single)
  1066. {
  1067. Operand maskTwo = X86GetAllElements(context, 2f);
  1068. Operand res = context.AddIntrinsic(Intrinsic.X86Mulps, n, m);
  1069. return context.AddIntrinsic(Intrinsic.X86Subps, maskTwo, res);
  1070. }
  1071. else
  1072. {
  1073. Operand maskTwo = X86GetAllElements(context, 2d);
  1074. Operand res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, m);
  1075. return context.AddIntrinsic(Intrinsic.X86Subpd, maskTwo, res);
  1076. }
  1077. });
  1078. }
  1079. else
  1080. {
  1081. EmitVectorBinaryOpF32(context, (op1, op2) =>
  1082. {
  1083. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStep), op1, op2);
  1084. });
  1085. }
  1086. }
  1087. public static void Vrsqrte(ArmEmitterContext context)
  1088. {
  1089. OpCode32SimdSqrte op = (OpCode32SimdSqrte)context.CurrOp;
  1090. if (op.F)
  1091. {
  1092. int sizeF = op.Size & 1;
  1093. if (Optimizations.FastFP && Optimizations.UseSse2 && sizeF == 0)
  1094. {
  1095. EmitVectorUnaryOpF32(context, Intrinsic.X86Rsqrtps, 0);
  1096. }
  1097. else
  1098. {
  1099. EmitVectorUnaryOpF32(context, (op1) =>
  1100. {
  1101. return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPRSqrtEstimateFpscr), op1);
  1102. });
  1103. }
  1104. }
  1105. else
  1106. {
  1107. throw new NotImplementedException("Integer Vrsqrte not currently implemented.");
  1108. }
  1109. }
  1110. public static void Vrsqrts(ArmEmitterContext context)
  1111. {
  1112. if (Optimizations.FastFP && Optimizations.UseSse2)
  1113. {
  1114. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  1115. bool single = (op.Size & 1) == 0;
  1116. // (3 - (n*m)) / 2
  1117. EmitVectorBinaryOpSimd32(context, (n, m) =>
  1118. {
  1119. if (single)
  1120. {
  1121. Operand maskHalf = X86GetAllElements(context, 0.5f);
  1122. Operand maskThree = X86GetAllElements(context, 3f);
  1123. Operand res = context.AddIntrinsic(Intrinsic.X86Mulps, n, m);
  1124. res = context.AddIntrinsic(Intrinsic.X86Subps, maskThree, res);
  1125. return context.AddIntrinsic(Intrinsic.X86Mulps, maskHalf, res);
  1126. }
  1127. else
  1128. {
  1129. Operand maskHalf = X86GetAllElements(context, 0.5d);
  1130. Operand maskThree = X86GetAllElements(context, 3d);
  1131. Operand res = context.AddIntrinsic(Intrinsic.X86Mulpd, n, m);
  1132. res = context.AddIntrinsic(Intrinsic.X86Subpd, maskThree, res);
  1133. return context.AddIntrinsic(Intrinsic.X86Mulpd, maskHalf, res);
  1134. }
  1135. });
  1136. }
  1137. else
  1138. {
  1139. EmitVectorBinaryOpF32(context, (op1, op2) =>
  1140. {
  1141. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStep), op1, op2);
  1142. });
  1143. }
  1144. }
  1145. public static void Vsel(ArmEmitterContext context)
  1146. {
  1147. OpCode32SimdSel op = (OpCode32SimdSel)context.CurrOp;
  1148. Operand condition = default;
  1149. switch (op.Cc)
  1150. {
  1151. case OpCode32SimdSelMode.Eq:
  1152. condition = GetCondTrue(context, Condition.Eq);
  1153. break;
  1154. case OpCode32SimdSelMode.Ge:
  1155. condition = GetCondTrue(context, Condition.Ge);
  1156. break;
  1157. case OpCode32SimdSelMode.Gt:
  1158. condition = GetCondTrue(context, Condition.Gt);
  1159. break;
  1160. case OpCode32SimdSelMode.Vs:
  1161. condition = GetCondTrue(context, Condition.Vs);
  1162. break;
  1163. }
  1164. EmitScalarBinaryOpI32(context, (op1, op2) =>
  1165. {
  1166. return context.ConditionalSelect(condition, op1, op2);
  1167. });
  1168. }
  1169. public static void Vsqrt_S(ArmEmitterContext context)
  1170. {
  1171. if (Optimizations.FastFP && Optimizations.UseSse2)
  1172. {
  1173. EmitScalarUnaryOpF32(context, Intrinsic.X86Sqrtss, Intrinsic.X86Sqrtsd);
  1174. }
  1175. else
  1176. {
  1177. EmitScalarUnaryOpF32(context, (op1) =>
  1178. {
  1179. return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt), op1);
  1180. });
  1181. }
  1182. }
  1183. public static void Vsub_S(ArmEmitterContext context)
  1184. {
  1185. if (Optimizations.FastFP && Optimizations.UseSse2)
  1186. {
  1187. EmitScalarBinaryOpF32(context, Intrinsic.X86Subss, Intrinsic.X86Subsd);
  1188. }
  1189. else
  1190. {
  1191. EmitScalarBinaryOpF32(context, (op1, op2) => context.Subtract(op1, op2));
  1192. }
  1193. }
  1194. public static void Vsub_V(ArmEmitterContext context)
  1195. {
  1196. if (Optimizations.FastFP && Optimizations.UseSse2)
  1197. {
  1198. EmitVectorBinaryOpF32(context, Intrinsic.X86Subps, Intrinsic.X86Subpd);
  1199. }
  1200. else
  1201. {
  1202. EmitVectorBinaryOpF32(context, (op1, op2) => context.Subtract(op1, op2));
  1203. }
  1204. }
  1205. public static void Vsub_I(ArmEmitterContext context)
  1206. {
  1207. if (Optimizations.UseSse2)
  1208. {
  1209. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  1210. EmitVectorBinaryOpSimd32(context, (op1, op2) => context.AddIntrinsic(X86PsubInstruction[op.Size], op1, op2));
  1211. }
  1212. else
  1213. {
  1214. EmitVectorBinaryOpZx32(context, (op1, op2) => context.Subtract(op1, op2));
  1215. }
  1216. }
  1217. public static void Vsubw_I(ArmEmitterContext context)
  1218. {
  1219. OpCode32SimdRegWide op = (OpCode32SimdRegWide)context.CurrOp;
  1220. EmitVectorBinaryWideOpI32(context, (op1, op2) => context.Subtract(op1, op2), !op.U);
  1221. }
  1222. private static void EmitSse41MaxMinNumOpF32(ArmEmitterContext context, bool isMaxNum, bool scalar)
  1223. {
  1224. IOpCode32Simd op = (IOpCode32Simd)context.CurrOp;
  1225. Func<Operand, Operand, Operand> genericEmit = (n, m) =>
  1226. {
  1227. Operand nNum = context.Copy(n);
  1228. Operand mNum = context.Copy(m);
  1229. InstEmit.EmitSse2VectorIsNaNOpF(context, nNum, out Operand nQNaNMask, out _, isQNaN: true);
  1230. InstEmit.EmitSse2VectorIsNaNOpF(context, mNum, out Operand mQNaNMask, out _, isQNaN: true);
  1231. int sizeF = op.Size & 1;
  1232. if (sizeF == 0)
  1233. {
  1234. Operand negInfMask = X86GetAllElements(context, isMaxNum ? float.NegativeInfinity : float.PositiveInfinity);
  1235. Operand nMask = context.AddIntrinsic(Intrinsic.X86Andnps, mQNaNMask, nQNaNMask);
  1236. Operand mMask = context.AddIntrinsic(Intrinsic.X86Andnps, nQNaNMask, mQNaNMask);
  1237. nNum = context.AddIntrinsic(Intrinsic.X86Blendvps, nNum, negInfMask, nMask);
  1238. mNum = context.AddIntrinsic(Intrinsic.X86Blendvps, mNum, negInfMask, mMask);
  1239. return context.AddIntrinsic(isMaxNum ? Intrinsic.X86Maxps : Intrinsic.X86Minps, nNum, mNum);
  1240. }
  1241. else /* if (sizeF == 1) */
  1242. {
  1243. Operand negInfMask = X86GetAllElements(context, isMaxNum ? double.NegativeInfinity : double.PositiveInfinity);
  1244. Operand nMask = context.AddIntrinsic(Intrinsic.X86Andnpd, mQNaNMask, nQNaNMask);
  1245. Operand mMask = context.AddIntrinsic(Intrinsic.X86Andnpd, nQNaNMask, mQNaNMask);
  1246. nNum = context.AddIntrinsic(Intrinsic.X86Blendvpd, nNum, negInfMask, nMask);
  1247. mNum = context.AddIntrinsic(Intrinsic.X86Blendvpd, mNum, negInfMask, mMask);
  1248. return context.AddIntrinsic(isMaxNum ? Intrinsic.X86Maxpd : Intrinsic.X86Minpd, nNum, mNum);
  1249. }
  1250. };
  1251. if (scalar)
  1252. {
  1253. EmitScalarBinaryOpSimd32(context, genericEmit);
  1254. }
  1255. else
  1256. {
  1257. EmitVectorBinaryOpSimd32(context, genericEmit);
  1258. }
  1259. }
  1260. }
  1261. }