AInstEmitSimdShift.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. using ChocolArm64.Decoder;
  2. using ChocolArm64.State;
  3. using ChocolArm64.Translation;
  4. using System;
  5. using System.Reflection.Emit;
  6. using System.Runtime.Intrinsics.X86;
  7. using static ChocolArm64.Instruction.AInstEmitSimdHelper;
  8. namespace ChocolArm64.Instruction
  9. {
  10. static partial class AInstEmit
  11. {
  12. public static void Rshrn_V(AILEmitterCtx Context)
  13. {
  14. EmitVectorShrImmNarrowOpZx(Context, Round: true);
  15. }
  16. public static void Shl_S(AILEmitterCtx Context)
  17. {
  18. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  19. EmitScalarUnaryOpZx(Context, () =>
  20. {
  21. Context.EmitLdc_I4(GetImmShl(Op));
  22. Context.Emit(OpCodes.Shl);
  23. });
  24. }
  25. public static void Shl_V(AILEmitterCtx Context)
  26. {
  27. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  28. if (AOptimizations.UseSse2 && Op.Size > 0)
  29. {
  30. Type[] Types = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) };
  31. EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
  32. Context.EmitLdc_I4(GetImmShl(Op));
  33. Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), Types));
  34. EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
  35. if (Op.RegisterSize == ARegisterSize.SIMD64)
  36. {
  37. EmitVectorZeroUpper(Context, Op.Rd);
  38. }
  39. }
  40. else
  41. {
  42. EmitVectorUnaryOpZx(Context, () =>
  43. {
  44. Context.EmitLdc_I4(GetImmShl(Op));
  45. Context.Emit(OpCodes.Shl);
  46. });
  47. }
  48. }
  49. public static void Shll_V(AILEmitterCtx Context)
  50. {
  51. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  52. int Shift = 8 << Op.Size;
  53. EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
  54. }
  55. public static void Shrn_V(AILEmitterCtx Context)
  56. {
  57. EmitVectorShrImmNarrowOpZx(Context, Round: false);
  58. }
  59. public static void Sli_V(AILEmitterCtx Context)
  60. {
  61. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  62. int Bytes = Op.GetBitsCount() >> 3;
  63. int Elems = Bytes >> Op.Size;
  64. int Shift = GetImmShl(Op);
  65. ulong Mask = Shift != 0 ? ulong.MaxValue >> (64 - Shift) : 0;
  66. for (int Index = 0; Index < Elems; Index++)
  67. {
  68. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  69. Context.EmitLdc_I4(Shift);
  70. Context.Emit(OpCodes.Shl);
  71. EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
  72. Context.EmitLdc_I8((long)Mask);
  73. Context.Emit(OpCodes.And);
  74. Context.Emit(OpCodes.Or);
  75. EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
  76. }
  77. if (Op.RegisterSize == ARegisterSize.SIMD64)
  78. {
  79. EmitVectorZeroUpper(Context, Op.Rd);
  80. }
  81. }
  82. public static void Sqrshrn_S(AILEmitterCtx Context)
  83. {
  84. EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
  85. }
  86. public static void Sqrshrn_V(AILEmitterCtx Context)
  87. {
  88. EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxSx);
  89. }
  90. public static void Sqrshrun_S(AILEmitterCtx Context)
  91. {
  92. EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
  93. }
  94. public static void Sqrshrun_V(AILEmitterCtx Context)
  95. {
  96. EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxZx);
  97. }
  98. public static void Sqshrn_S(AILEmitterCtx Context)
  99. {
  100. EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxSx);
  101. }
  102. public static void Sqshrn_V(AILEmitterCtx Context)
  103. {
  104. EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxSx);
  105. }
  106. public static void Sqshrun_S(AILEmitterCtx Context)
  107. {
  108. EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarSxZx);
  109. }
  110. public static void Sqshrun_V(AILEmitterCtx Context)
  111. {
  112. EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorSxZx);
  113. }
  114. public static void Srshr_S(AILEmitterCtx Context)
  115. {
  116. EmitScalarShrImmOpSx(Context, ShrImmFlags.Round);
  117. }
  118. public static void Srshr_V(AILEmitterCtx Context)
  119. {
  120. EmitVectorShrImmOpSx(Context, ShrImmFlags.Round);
  121. }
  122. public static void Srsra_S(AILEmitterCtx Context)
  123. {
  124. EmitScalarShrImmOpSx(Context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
  125. }
  126. public static void Srsra_V(AILEmitterCtx Context)
  127. {
  128. EmitVectorShrImmOpSx(Context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
  129. }
  130. public static void Sshl_V(AILEmitterCtx Context)
  131. {
  132. EmitVectorShl(Context, Signed: true);
  133. }
  134. public static void Sshll_V(AILEmitterCtx Context)
  135. {
  136. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  137. EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), GetImmShl(Op));
  138. }
  139. public static void Sshr_S(AILEmitterCtx Context)
  140. {
  141. EmitShrImmOp(Context, ShrImmFlags.ScalarSx);
  142. }
  143. public static void Sshr_V(AILEmitterCtx Context)
  144. {
  145. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  146. if (AOptimizations.UseSse2 && Op.Size > 0
  147. && Op.Size < 3)
  148. {
  149. Type[] Types = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], typeof(byte) };
  150. EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size);
  151. Context.EmitLdc_I4(GetImmShr(Op));
  152. Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), Types));
  153. EmitStvecWithSignedCast(Context, Op.Rd, Op.Size);
  154. if (Op.RegisterSize == ARegisterSize.SIMD64)
  155. {
  156. EmitVectorZeroUpper(Context, Op.Rd);
  157. }
  158. }
  159. else
  160. {
  161. EmitShrImmOp(Context, ShrImmFlags.VectorSx);
  162. }
  163. }
  164. public static void Ssra_S(AILEmitterCtx Context)
  165. {
  166. EmitScalarShrImmOpSx(Context, ShrImmFlags.Accumulate);
  167. }
  168. public static void Ssra_V(AILEmitterCtx Context)
  169. {
  170. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  171. if (AOptimizations.UseSse2 && Op.Size > 0
  172. && Op.Size < 3)
  173. {
  174. Type[] TypesSra = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], typeof(byte) };
  175. Type[] TypesAdd = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], VectorIntTypesPerSizeLog2[Op.Size] };
  176. EmitLdvecWithSignedCast(Context, Op.Rd, Op.Size);
  177. EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size);
  178. Context.EmitLdc_I4(GetImmShr(Op));
  179. Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), TypesSra));
  180. Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd));
  181. EmitStvecWithSignedCast(Context, Op.Rd, Op.Size);
  182. if (Op.RegisterSize == ARegisterSize.SIMD64)
  183. {
  184. EmitVectorZeroUpper(Context, Op.Rd);
  185. }
  186. }
  187. else
  188. {
  189. EmitVectorShrImmOpSx(Context, ShrImmFlags.Accumulate);
  190. }
  191. }
  192. public static void Uqrshrn_S(AILEmitterCtx Context)
  193. {
  194. EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
  195. }
  196. public static void Uqrshrn_V(AILEmitterCtx Context)
  197. {
  198. EmitRoundShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorZxZx);
  199. }
  200. public static void Uqshrn_S(AILEmitterCtx Context)
  201. {
  202. EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.ScalarZxZx);
  203. }
  204. public static void Uqshrn_V(AILEmitterCtx Context)
  205. {
  206. EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.VectorZxZx);
  207. }
  208. public static void Urshr_S(AILEmitterCtx Context)
  209. {
  210. EmitScalarShrImmOpZx(Context, ShrImmFlags.Round);
  211. }
  212. public static void Urshr_V(AILEmitterCtx Context)
  213. {
  214. EmitVectorShrImmOpZx(Context, ShrImmFlags.Round);
  215. }
  216. public static void Ursra_S(AILEmitterCtx Context)
  217. {
  218. EmitScalarShrImmOpZx(Context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
  219. }
  220. public static void Ursra_V(AILEmitterCtx Context)
  221. {
  222. EmitVectorShrImmOpZx(Context, ShrImmFlags.Round | ShrImmFlags.Accumulate);
  223. }
  224. public static void Ushl_V(AILEmitterCtx Context)
  225. {
  226. EmitVectorShl(Context, Signed: false);
  227. }
  228. public static void Ushll_V(AILEmitterCtx Context)
  229. {
  230. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  231. EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), GetImmShl(Op));
  232. }
  233. public static void Ushr_S(AILEmitterCtx Context)
  234. {
  235. EmitShrImmOp(Context, ShrImmFlags.ScalarZx);
  236. }
  237. public static void Ushr_V(AILEmitterCtx Context)
  238. {
  239. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  240. if (AOptimizations.UseSse2 && Op.Size > 0)
  241. {
  242. Type[] Types = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) };
  243. EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
  244. Context.EmitLdc_I4(GetImmShr(Op));
  245. Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), Types));
  246. EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
  247. if (Op.RegisterSize == ARegisterSize.SIMD64)
  248. {
  249. EmitVectorZeroUpper(Context, Op.Rd);
  250. }
  251. }
  252. else
  253. {
  254. EmitShrImmOp(Context, ShrImmFlags.VectorZx);
  255. }
  256. }
  257. public static void Usra_S(AILEmitterCtx Context)
  258. {
  259. EmitScalarShrImmOpZx(Context, ShrImmFlags.Accumulate);
  260. }
  261. public static void Usra_V(AILEmitterCtx Context)
  262. {
  263. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  264. if (AOptimizations.UseSse2 && Op.Size > 0)
  265. {
  266. Type[] TypesSrl = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) };
  267. Type[] TypesAdd = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], VectorUIntTypesPerSizeLog2[Op.Size] };
  268. EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
  269. EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
  270. Context.EmitLdc_I4(GetImmShr(Op));
  271. Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), TypesSrl));
  272. Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd));
  273. EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
  274. if (Op.RegisterSize == ARegisterSize.SIMD64)
  275. {
  276. EmitVectorZeroUpper(Context, Op.Rd);
  277. }
  278. }
  279. else
  280. {
  281. EmitVectorShrImmOpZx(Context, ShrImmFlags.Accumulate);
  282. }
  283. }
  284. private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
  285. {
  286. //This instruction shifts the value on vector A by the number of bits
  287. //specified on the signed, lower 8 bits of vector B. If the shift value
  288. //is greater or equal to the data size of each lane, then the result is zero.
  289. //Additionally, negative shifts produces right shifts by the negated shift value.
  290. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  291. int MaxShift = 8 << Op.Size;
  292. Action Emit = () =>
  293. {
  294. AILLabel LblShl = new AILLabel();
  295. AILLabel LblZero = new AILLabel();
  296. AILLabel LblEnd = new AILLabel();
  297. void EmitShift(OpCode ILOp)
  298. {
  299. Context.Emit(OpCodes.Dup);
  300. Context.EmitLdc_I4(MaxShift);
  301. Context.Emit(OpCodes.Bge_S, LblZero);
  302. Context.Emit(ILOp);
  303. Context.Emit(OpCodes.Br_S, LblEnd);
  304. }
  305. Context.Emit(OpCodes.Conv_I1);
  306. Context.Emit(OpCodes.Dup);
  307. Context.EmitLdc_I4(0);
  308. Context.Emit(OpCodes.Bge_S, LblShl);
  309. Context.Emit(OpCodes.Neg);
  310. EmitShift(Signed
  311. ? OpCodes.Shr
  312. : OpCodes.Shr_Un);
  313. Context.MarkLabel(LblShl);
  314. EmitShift(OpCodes.Shl);
  315. Context.MarkLabel(LblZero);
  316. Context.Emit(OpCodes.Pop);
  317. Context.Emit(OpCodes.Pop);
  318. Context.EmitLdc_I8(0);
  319. Context.MarkLabel(LblEnd);
  320. };
  321. if (Signed)
  322. {
  323. EmitVectorBinaryOpSx(Context, Emit);
  324. }
  325. else
  326. {
  327. EmitVectorBinaryOpZx(Context, Emit);
  328. }
  329. }
  330. [Flags]
  331. private enum ShrImmFlags
  332. {
  333. Scalar = 1 << 0,
  334. Signed = 1 << 1,
  335. Round = 1 << 2,
  336. Accumulate = 1 << 3,
  337. ScalarSx = Scalar | Signed,
  338. ScalarZx = Scalar,
  339. VectorSx = Signed,
  340. VectorZx = 0
  341. }
  342. private static void EmitScalarShrImmOpSx(AILEmitterCtx Context, ShrImmFlags Flags)
  343. {
  344. EmitShrImmOp(Context, ShrImmFlags.ScalarSx | Flags);
  345. }
  346. private static void EmitScalarShrImmOpZx(AILEmitterCtx Context, ShrImmFlags Flags)
  347. {
  348. EmitShrImmOp(Context, ShrImmFlags.ScalarZx | Flags);
  349. }
  350. private static void EmitVectorShrImmOpSx(AILEmitterCtx Context, ShrImmFlags Flags)
  351. {
  352. EmitShrImmOp(Context, ShrImmFlags.VectorSx | Flags);
  353. }
  354. private static void EmitVectorShrImmOpZx(AILEmitterCtx Context, ShrImmFlags Flags)
  355. {
  356. EmitShrImmOp(Context, ShrImmFlags.VectorZx | Flags);
  357. }
  358. private static void EmitShrImmOp(AILEmitterCtx Context, ShrImmFlags Flags)
  359. {
  360. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  361. bool Scalar = (Flags & ShrImmFlags.Scalar) != 0;
  362. bool Signed = (Flags & ShrImmFlags.Signed) != 0;
  363. bool Round = (Flags & ShrImmFlags.Round) != 0;
  364. bool Accumulate = (Flags & ShrImmFlags.Accumulate) != 0;
  365. int Shift = GetImmShr(Op);
  366. long RoundConst = 1L << (Shift - 1);
  367. int Bytes = Op.GetBitsCount() >> 3;
  368. int Elems = !Scalar ? Bytes >> Op.Size : 1;
  369. for (int Index = 0; Index < Elems; Index++)
  370. {
  371. EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
  372. if (Op.Size <= 2)
  373. {
  374. if (Round)
  375. {
  376. Context.EmitLdc_I8(RoundConst);
  377. Context.Emit(OpCodes.Add);
  378. }
  379. Context.EmitLdc_I4(Shift);
  380. Context.Emit(Signed ? OpCodes.Shr : OpCodes.Shr_Un);
  381. }
  382. else /* if (Op.Size == 3) */
  383. {
  384. EmitShrImm_64(Context, Signed, Round ? RoundConst : 0L, Shift);
  385. }
  386. if (Accumulate)
  387. {
  388. EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
  389. Context.Emit(OpCodes.Add);
  390. }
  391. EmitVectorInsertTmp(Context, Index, Op.Size);
  392. }
  393. Context.EmitLdvectmp();
  394. Context.EmitStvec(Op.Rd);
  395. if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
  396. {
  397. EmitVectorZeroUpper(Context, Op.Rd);
  398. }
  399. }
  400. private static void EmitVectorShrImmNarrowOpZx(AILEmitterCtx Context, bool Round)
  401. {
  402. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  403. int Shift = GetImmShr(Op);
  404. long RoundConst = 1L << (Shift - 1);
  405. int Elems = 8 >> Op.Size;
  406. int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
  407. if (Part != 0)
  408. {
  409. Context.EmitLdvec(Op.Rd);
  410. Context.EmitStvectmp();
  411. }
  412. for (int Index = 0; Index < Elems; Index++)
  413. {
  414. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
  415. if (Round)
  416. {
  417. Context.EmitLdc_I8(RoundConst);
  418. Context.Emit(OpCodes.Add);
  419. }
  420. Context.EmitLdc_I4(Shift);
  421. Context.Emit(OpCodes.Shr_Un);
  422. EmitVectorInsertTmp(Context, Part + Index, Op.Size);
  423. }
  424. Context.EmitLdvectmp();
  425. Context.EmitStvec(Op.Rd);
  426. if (Part == 0)
  427. {
  428. EmitVectorZeroUpper(Context, Op.Rd);
  429. }
  430. }
  431. [Flags]
  432. private enum ShrImmSaturatingNarrowFlags
  433. {
  434. Scalar = 1 << 0,
  435. SignedSrc = 1 << 1,
  436. SignedDst = 1 << 2,
  437. Round = 1 << 3,
  438. ScalarSxSx = Scalar | SignedSrc | SignedDst,
  439. ScalarSxZx = Scalar | SignedSrc,
  440. ScalarZxZx = Scalar,
  441. VectorSxSx = SignedSrc | SignedDst,
  442. VectorSxZx = SignedSrc,
  443. VectorZxZx = 0
  444. }
  445. private static void EmitRoundShrImmSaturatingNarrowOp(AILEmitterCtx Context, ShrImmSaturatingNarrowFlags Flags)
  446. {
  447. EmitShrImmSaturatingNarrowOp(Context, ShrImmSaturatingNarrowFlags.Round | Flags);
  448. }
  449. private static void EmitShrImmSaturatingNarrowOp(AILEmitterCtx Context, ShrImmSaturatingNarrowFlags Flags)
  450. {
  451. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  452. bool Scalar = (Flags & ShrImmSaturatingNarrowFlags.Scalar) != 0;
  453. bool SignedSrc = (Flags & ShrImmSaturatingNarrowFlags.SignedSrc) != 0;
  454. bool SignedDst = (Flags & ShrImmSaturatingNarrowFlags.SignedDst) != 0;
  455. bool Round = (Flags & ShrImmSaturatingNarrowFlags.Round) != 0;
  456. int Shift = GetImmShr(Op);
  457. long RoundConst = 1L << (Shift - 1);
  458. int Elems = !Scalar ? 8 >> Op.Size : 1;
  459. int Part = !Scalar && (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0;
  460. if (Scalar)
  461. {
  462. EmitVectorZeroLowerTmp(Context);
  463. }
  464. if (Part != 0)
  465. {
  466. Context.EmitLdvec(Op.Rd);
  467. Context.EmitStvectmp();
  468. }
  469. for (int Index = 0; Index < Elems; Index++)
  470. {
  471. EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, SignedSrc);
  472. if (Op.Size <= 1 || !Round)
  473. {
  474. if (Round)
  475. {
  476. Context.EmitLdc_I8(RoundConst);
  477. Context.Emit(OpCodes.Add);
  478. }
  479. Context.EmitLdc_I4(Shift);
  480. Context.Emit(SignedSrc ? OpCodes.Shr : OpCodes.Shr_Un);
  481. }
  482. else /* if (Op.Size == 2 && Round) */
  483. {
  484. EmitShrImm_64(Context, SignedSrc, RoundConst, Shift); // Shift <= 32
  485. }
  486. EmitSatQ(Context, Op.Size, SignedSrc, SignedDst);
  487. EmitVectorInsertTmp(Context, Part + Index, Op.Size);
  488. }
  489. Context.EmitLdvectmp();
  490. Context.EmitStvec(Op.Rd);
  491. if (Part == 0)
  492. {
  493. EmitVectorZeroUpper(Context, Op.Rd);
  494. }
  495. }
  496. // Dst_64 = (Int(Src_64, Signed) + RoundConst) >> Shift;
  497. private static void EmitShrImm_64(
  498. AILEmitterCtx Context,
  499. bool Signed,
  500. long RoundConst,
  501. int Shift)
  502. {
  503. Context.EmitLdc_I8(RoundConst);
  504. Context.EmitLdc_I4(Shift);
  505. ASoftFallback.EmitCall(Context, Signed
  506. ? nameof(ASoftFallback.SignedShrImm_64)
  507. : nameof(ASoftFallback.UnsignedShrImm_64));
  508. }
  509. private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
  510. {
  511. EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true);
  512. }
  513. private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
  514. {
  515. EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false);
  516. }
  517. private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
  518. {
  519. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  520. int Elems = 8 >> Op.Size;
  521. int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
  522. for (int Index = 0; Index < Elems; Index++)
  523. {
  524. EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed);
  525. Context.EmitLdc_I4(Imm);
  526. Emit();
  527. EmitVectorInsertTmp(Context, Index, Op.Size + 1);
  528. }
  529. Context.EmitLdvectmp();
  530. Context.EmitStvec(Op.Rd);
  531. }
  532. }
  533. }