AInstEmitSimdShift.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. using ChocolArm64.Decoder;
  2. using ChocolArm64.State;
  3. using ChocolArm64.Translation;
  4. using System;
  5. using System.Reflection.Emit;
  6. using static ChocolArm64.Instruction.AInstEmitSimdHelper;
  7. namespace ChocolArm64.Instruction
  8. {
  9. static partial class AInstEmit
  10. {
  11. public static void Shl_S(AILEmitterCtx Context)
  12. {
  13. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  14. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  15. Context.EmitLdc_I4(GetImmShl(Op));
  16. Context.Emit(OpCodes.Shl);
  17. EmitScalarSet(Context, Op.Rd, Op.Size);
  18. }
  19. public static void Shl_V(AILEmitterCtx Context)
  20. {
  21. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  22. int Shift = Op.Imm - (8 << Op.Size);
  23. EmitVectorShImmBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
  24. }
  25. public static void Shll_V(AILEmitterCtx Context)
  26. {
  27. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  28. int Shift = 8 << Op.Size;
  29. EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
  30. }
  31. public static void Shrn_V(AILEmitterCtx Context)
  32. {
  33. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  34. int Shift = (8 << (Op.Size + 1)) - Op.Imm;
  35. EmitVectorShImmNarrowBinaryZx(Context, () => Context.Emit(OpCodes.Shr_Un), Shift);
  36. }
  37. public static void Sli_V(AILEmitterCtx Context)
  38. {
  39. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  40. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  41. int Shift = Op.Imm - (8 << Op.Size);
  42. ulong Mask = Shift != 0 ? ulong.MaxValue >> (64 - Shift) : 0;
  43. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  44. {
  45. EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
  46. Context.EmitLdc_I4(Shift);
  47. Context.Emit(OpCodes.Shl);
  48. EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
  49. Context.EmitLdc_I8((long)Mask);
  50. Context.Emit(OpCodes.And);
  51. Context.Emit(OpCodes.Or);
  52. EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
  53. }
  54. if (Op.RegisterSize == ARegisterSize.SIMD64)
  55. {
  56. EmitVectorZeroUpper(Context, Op.Rd);
  57. }
  58. }
  59. public static void Sshl_V(AILEmitterCtx Context)
  60. {
  61. EmitVectorShl(Context, Signed: true);
  62. }
  63. public static void Sshll_V(AILEmitterCtx Context)
  64. {
  65. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  66. int Shift = Op.Imm - (8 << Op.Size);
  67. EmitVectorShImmWidenBinarySx(Context, () => Context.Emit(OpCodes.Shl), Shift);
  68. }
  69. public static void Sshr_S(AILEmitterCtx Context)
  70. {
  71. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  72. EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size);
  73. Context.EmitLdc_I4(GetImmShr(Op));
  74. Context.Emit(OpCodes.Shr);
  75. EmitScalarSet(Context, Op.Rd, Op.Size);
  76. }
  77. public static void Sshr_V(AILEmitterCtx Context)
  78. {
  79. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  80. int Shift = (8 << (Op.Size + 1)) - Op.Imm;
  81. EmitVectorShImmBinarySx(Context, () => Context.Emit(OpCodes.Shr), Shift);
  82. }
  83. public static void Ssra_V(AILEmitterCtx Context)
  84. {
  85. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  86. int Shift = (8 << (Op.Size + 1)) - Op.Imm;
  87. Action Emit = () =>
  88. {
  89. Context.Emit(OpCodes.Shr);
  90. Context.Emit(OpCodes.Add);
  91. };
  92. EmitVectorShImmTernarySx(Context, Emit, Shift);
  93. }
  94. public static void Ushl_V(AILEmitterCtx Context)
  95. {
  96. EmitVectorShl(Context, Signed: false);
  97. }
  98. public static void Ushll_V(AILEmitterCtx Context)
  99. {
  100. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  101. int Shift = Op.Imm - (8 << Op.Size);
  102. EmitVectorShImmWidenBinaryZx(Context, () => Context.Emit(OpCodes.Shl), Shift);
  103. }
  104. public static void Ushr_S(AILEmitterCtx Context)
  105. {
  106. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  107. EmitScalarUnaryOpZx(Context, () =>
  108. {
  109. Context.EmitLdc_I4(GetImmShr(Op));
  110. Context.Emit(OpCodes.Shr_Un);
  111. });
  112. }
  113. public static void Ushr_V(AILEmitterCtx Context)
  114. {
  115. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  116. EmitVectorUnaryOpZx(Context, () =>
  117. {
  118. Context.EmitLdc_I4(GetImmShr(Op));
  119. Context.Emit(OpCodes.Shr_Un);
  120. });
  121. }
  122. public static void Usra_V(AILEmitterCtx Context)
  123. {
  124. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  125. Action Emit = () =>
  126. {
  127. Context.EmitLdc_I4(GetImmShr(Op));
  128. Context.Emit(OpCodes.Shr_Un);
  129. Context.Emit(OpCodes.Add);
  130. };
  131. EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
  132. }
  133. private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
  134. {
  135. //This instruction shifts the value on vector A by the number of bits
  136. //specified on the signed, lower 8 bits of vector B. If the shift value
  137. //is greater or equal to the data size of each lane, then the result is zero.
  138. //Additionally, negative shifts produces right shifts by the negated shift value.
  139. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  140. int MaxShift = 8 << Op.Size;
  141. Action Emit = () =>
  142. {
  143. AILLabel LblShl = new AILLabel();
  144. AILLabel LblZero = new AILLabel();
  145. AILLabel LblEnd = new AILLabel();
  146. void EmitShift(OpCode ILOp)
  147. {
  148. Context.Emit(OpCodes.Dup);
  149. Context.EmitLdc_I4(MaxShift);
  150. Context.Emit(OpCodes.Bge_S, LblZero);
  151. Context.Emit(ILOp);
  152. Context.Emit(OpCodes.Br_S, LblEnd);
  153. }
  154. Context.Emit(OpCodes.Conv_I1);
  155. Context.Emit(OpCodes.Dup);
  156. Context.EmitLdc_I4(0);
  157. Context.Emit(OpCodes.Bge_S, LblShl);
  158. Context.Emit(OpCodes.Neg);
  159. EmitShift(Signed
  160. ? OpCodes.Shr
  161. : OpCodes.Shr_Un);
  162. Context.MarkLabel(LblShl);
  163. EmitShift(OpCodes.Shl);
  164. Context.MarkLabel(LblZero);
  165. Context.Emit(OpCodes.Pop);
  166. Context.Emit(OpCodes.Pop);
  167. Context.EmitLdc_I8(0);
  168. Context.MarkLabel(LblEnd);
  169. };
  170. if (Signed)
  171. {
  172. EmitVectorBinaryOpSx(Context, Emit);
  173. }
  174. else
  175. {
  176. EmitVectorBinaryOpZx(Context, Emit);
  177. }
  178. }
  179. private static void EmitVectorShImmBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
  180. {
  181. EmitVectorShImmOp(Context, Emit, Imm, false, true);
  182. }
  183. private static void EmitVectorShImmTernarySx(AILEmitterCtx Context, Action Emit, int Imm)
  184. {
  185. EmitVectorShImmOp(Context, Emit, Imm, true, true);
  186. }
  187. private static void EmitVectorShImmBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
  188. {
  189. EmitVectorShImmOp(Context, Emit, Imm, false, false);
  190. }
  191. private static void EmitVectorShImmOp(AILEmitterCtx Context, Action Emit, int Imm, bool Ternary, bool Signed)
  192. {
  193. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  194. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  195. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  196. {
  197. if (Ternary)
  198. {
  199. EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
  200. }
  201. EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
  202. Context.EmitLdc_I4(Imm);
  203. Emit();
  204. EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
  205. }
  206. if (Op.RegisterSize == ARegisterSize.SIMD64)
  207. {
  208. EmitVectorZeroUpper(Context, Op.Rd);
  209. }
  210. }
  211. private static void EmitVectorShImmNarrowBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
  212. {
  213. EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, true);
  214. }
  215. private static void EmitVectorShImmNarrowBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
  216. {
  217. EmitVectorShImmNarrowBinaryOp(Context, Emit, Imm, false);
  218. }
  219. private static void EmitVectorShImmNarrowBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
  220. {
  221. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  222. int Elems = 8 >> Op.Size;
  223. int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
  224. for (int Index = 0; Index < Elems; Index++)
  225. {
  226. EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);
  227. Context.EmitLdc_I4(Imm);
  228. Emit();
  229. EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
  230. }
  231. if (Part == 0)
  232. {
  233. EmitVectorZeroUpper(Context, Op.Rd);
  234. }
  235. }
  236. private static void EmitVectorShImmWidenBinarySx(AILEmitterCtx Context, Action Emit, int Imm)
  237. {
  238. EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, true);
  239. }
  240. private static void EmitVectorShImmWidenBinaryZx(AILEmitterCtx Context, Action Emit, int Imm)
  241. {
  242. EmitVectorShImmWidenBinaryOp(Context, Emit, Imm, false);
  243. }
  244. private static void EmitVectorShImmWidenBinaryOp(AILEmitterCtx Context, Action Emit, int Imm, bool Signed)
  245. {
  246. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  247. int Elems = 8 >> Op.Size;
  248. int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
  249. for (int Index = 0; Index < Elems; Index++)
  250. {
  251. EmitVectorExtract(Context, Op.Rn, Part + Index, Op.Size, Signed);
  252. Context.EmitLdc_I4(Imm);
  253. Emit();
  254. EmitVectorInsertTmp(Context, Index, Op.Size + 1);
  255. }
  256. Context.EmitLdvectmp();
  257. Context.EmitStvec(Op.Rd);
  258. }
  259. }
  260. }