InstEmitSimdArithmetic32.cs 53 KB

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