InstEmitAlu.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. using ChocolArm64.Decoders;
  2. using ChocolArm64.State;
  3. using ChocolArm64.Translation;
  4. using System;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using System.Runtime.Intrinsics.X86;
  8. using static ChocolArm64.Instructions.InstEmitAluHelper;
  9. namespace ChocolArm64.Instructions
  10. {
  11. static partial class InstEmit
  12. {
  13. public static void Adc(ILEmitterCtx context) => EmitAdc(context, false);
  14. public static void Adcs(ILEmitterCtx context) => EmitAdc(context, true);
  15. private static void EmitAdc(ILEmitterCtx context, bool setFlags)
  16. {
  17. EmitDataLoadOpers(context);
  18. context.Emit(OpCodes.Add);
  19. context.EmitLdflg((int)PState.CBit);
  20. Type[] mthdTypes = new Type[] { typeof(bool) };
  21. MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes);
  22. context.EmitCall(mthdInfo);
  23. if (context.CurrOp.RegisterSize != RegisterSize.Int32)
  24. {
  25. context.Emit(OpCodes.Conv_U8);
  26. }
  27. context.Emit(OpCodes.Add);
  28. if (setFlags)
  29. {
  30. context.EmitZnFlagCheck();
  31. EmitAdcsCCheck(context);
  32. EmitAddsVCheck(context);
  33. }
  34. EmitDataStore(context);
  35. }
  36. public static void Add(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Add);
  37. public static void Adds(ILEmitterCtx context)
  38. {
  39. EmitDataLoadOpers(context);
  40. context.Emit(OpCodes.Add);
  41. context.EmitZnFlagCheck();
  42. EmitAddsCCheck(context);
  43. EmitAddsVCheck(context);
  44. EmitDataStoreS(context);
  45. }
  46. public static void And(ILEmitterCtx context) => EmitDataOp(context, OpCodes.And);
  47. public static void Ands(ILEmitterCtx context)
  48. {
  49. EmitDataLoadOpers(context);
  50. context.Emit(OpCodes.And);
  51. EmitZeroCvFlags(context);
  52. context.EmitZnFlagCheck();
  53. EmitDataStoreS(context);
  54. }
  55. public static void Asrv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shr);
  56. public static void Bic(ILEmitterCtx context) => EmitBic(context, false);
  57. public static void Bics(ILEmitterCtx context) => EmitBic(context, true);
  58. private static void EmitBic(ILEmitterCtx context, bool setFlags)
  59. {
  60. EmitDataLoadOpers(context);
  61. context.Emit(OpCodes.Not);
  62. context.Emit(OpCodes.And);
  63. if (setFlags)
  64. {
  65. EmitZeroCvFlags(context);
  66. context.EmitZnFlagCheck();
  67. }
  68. EmitDataStore(context, setFlags);
  69. }
  70. public static void Cls(ILEmitterCtx context)
  71. {
  72. OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
  73. context.EmitLdintzr(op.Rn);
  74. context.EmitLdc_I4(op.RegisterSize == RegisterSize.Int32 ? 32 : 64);
  75. SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingSigns));
  76. context.EmitStintzr(op.Rd);
  77. }
  78. public static void Clz(ILEmitterCtx context)
  79. {
  80. OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
  81. context.EmitLdintzr(op.Rn);
  82. if (Lzcnt.IsSupported)
  83. {
  84. Type tValue = op.RegisterSize == RegisterSize.Int32 ? typeof(uint) : typeof(ulong);
  85. context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { tValue }));
  86. }
  87. else
  88. {
  89. context.EmitLdc_I4(op.RegisterSize == RegisterSize.Int32 ? 32 : 64);
  90. SoftFallback.EmitCall(context, nameof(SoftFallback.CountLeadingZeros));
  91. }
  92. context.EmitStintzr(op.Rd);
  93. }
  94. public static void Eon(ILEmitterCtx context)
  95. {
  96. EmitDataLoadOpers(context);
  97. context.Emit(OpCodes.Not);
  98. context.Emit(OpCodes.Xor);
  99. EmitDataStore(context);
  100. }
  101. public static void Eor(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Xor);
  102. public static void Extr(ILEmitterCtx context)
  103. {
  104. //TODO: Ensure that the Shift is valid for the Is64Bits.
  105. OpCodeAluRs64 op = (OpCodeAluRs64)context.CurrOp;
  106. context.EmitLdintzr(op.Rm);
  107. if (op.Shift > 0)
  108. {
  109. context.EmitLdc_I4(op.Shift);
  110. context.Emit(OpCodes.Shr_Un);
  111. context.EmitLdintzr(op.Rn);
  112. context.EmitLdc_I4(op.GetBitsCount() - op.Shift);
  113. context.Emit(OpCodes.Shl);
  114. context.Emit(OpCodes.Or);
  115. }
  116. EmitDataStore(context);
  117. }
  118. public static void Lslv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shl);
  119. public static void Lsrv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shr_Un);
  120. public static void Sbc(ILEmitterCtx context) => EmitSbc(context, false);
  121. public static void Sbcs(ILEmitterCtx context) => EmitSbc(context, true);
  122. private static void EmitSbc(ILEmitterCtx context, bool setFlags)
  123. {
  124. EmitDataLoadOpers(context);
  125. context.Emit(OpCodes.Sub);
  126. context.EmitLdflg((int)PState.CBit);
  127. Type[] mthdTypes = new Type[] { typeof(bool) };
  128. MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes);
  129. context.EmitCall(mthdInfo);
  130. context.EmitLdc_I4(1);
  131. context.Emit(OpCodes.Xor);
  132. if (context.CurrOp.RegisterSize != RegisterSize.Int32)
  133. {
  134. context.Emit(OpCodes.Conv_U8);
  135. }
  136. context.Emit(OpCodes.Sub);
  137. if (setFlags)
  138. {
  139. context.EmitZnFlagCheck();
  140. EmitSbcsCCheck(context);
  141. EmitSubsVCheck(context);
  142. }
  143. EmitDataStore(context);
  144. }
  145. public static void Sub(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Sub);
  146. public static void Subs(ILEmitterCtx context)
  147. {
  148. context.TryOptMarkCondWithoutCmp();
  149. EmitDataLoadOpers(context);
  150. context.Emit(OpCodes.Sub);
  151. context.EmitZnFlagCheck();
  152. EmitSubsCCheck(context);
  153. EmitSubsVCheck(context);
  154. EmitDataStoreS(context);
  155. }
  156. public static void Orn(ILEmitterCtx context)
  157. {
  158. EmitDataLoadOpers(context);
  159. context.Emit(OpCodes.Not);
  160. context.Emit(OpCodes.Or);
  161. EmitDataStore(context);
  162. }
  163. public static void Orr(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Or);
  164. public static void Rbit(ILEmitterCtx context) => EmitFallback32_64(context,
  165. nameof(SoftFallback.ReverseBits32),
  166. nameof(SoftFallback.ReverseBits64));
  167. public static void Rev16(ILEmitterCtx context) => EmitFallback32_64(context,
  168. nameof(SoftFallback.ReverseBytes16_32),
  169. nameof(SoftFallback.ReverseBytes16_64));
  170. public static void Rev32(ILEmitterCtx context) => EmitFallback32_64(context,
  171. nameof(SoftFallback.ReverseBytes32_32),
  172. nameof(SoftFallback.ReverseBytes32_64));
  173. private static void EmitFallback32_64(ILEmitterCtx context, string name32, string name64)
  174. {
  175. OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
  176. context.EmitLdintzr(op.Rn);
  177. if (op.RegisterSize == RegisterSize.Int32)
  178. {
  179. SoftFallback.EmitCall(context, name32);
  180. }
  181. else
  182. {
  183. SoftFallback.EmitCall(context, name64);
  184. }
  185. context.EmitStintzr(op.Rd);
  186. }
  187. public static void Rev64(ILEmitterCtx context)
  188. {
  189. OpCodeAlu64 op = (OpCodeAlu64)context.CurrOp;
  190. context.EmitLdintzr(op.Rn);
  191. SoftFallback.EmitCall(context, nameof(SoftFallback.ReverseBytes64));
  192. context.EmitStintzr(op.Rd);
  193. }
  194. public static void Rorv(ILEmitterCtx context)
  195. {
  196. EmitDataLoadRn(context);
  197. EmitDataLoadShift(context);
  198. context.Emit(OpCodes.Shr_Un);
  199. EmitDataLoadRn(context);
  200. context.EmitLdc_I4(context.CurrOp.GetBitsCount());
  201. EmitDataLoadShift(context);
  202. context.Emit(OpCodes.Sub);
  203. context.Emit(OpCodes.Shl);
  204. context.Emit(OpCodes.Or);
  205. EmitDataStore(context);
  206. }
  207. public static void Sdiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div);
  208. public static void Udiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div_Un);
  209. private static void EmitDiv(ILEmitterCtx context, OpCode ilOp)
  210. {
  211. //If Rm == 0, Rd = 0 (division by zero).
  212. context.EmitLdc_I(0);
  213. EmitDataLoadRm(context);
  214. context.EmitLdc_I(0);
  215. ILLabel badDiv = new ILLabel();
  216. context.Emit(OpCodes.Beq_S, badDiv);
  217. context.Emit(OpCodes.Pop);
  218. if (ilOp == OpCodes.Div)
  219. {
  220. //If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow).
  221. long intMin = 1L << (context.CurrOp.GetBitsCount() - 1);
  222. context.EmitLdc_I(intMin);
  223. EmitDataLoadRn(context);
  224. context.EmitLdc_I(intMin);
  225. context.Emit(OpCodes.Ceq);
  226. EmitDataLoadRm(context);
  227. context.EmitLdc_I(-1);
  228. context.Emit(OpCodes.Ceq);
  229. context.Emit(OpCodes.And);
  230. context.Emit(OpCodes.Brtrue_S, badDiv);
  231. context.Emit(OpCodes.Pop);
  232. }
  233. EmitDataLoadRn(context);
  234. EmitDataLoadRm(context);
  235. context.Emit(ilOp);
  236. context.MarkLabel(badDiv);
  237. EmitDataStore(context);
  238. }
  239. private static void EmitDataOp(ILEmitterCtx context, OpCode ilOp)
  240. {
  241. EmitDataLoadOpers(context);
  242. context.Emit(ilOp);
  243. EmitDataStore(context);
  244. }
  245. private static void EmitDataOpShift(ILEmitterCtx context, OpCode ilOp)
  246. {
  247. EmitDataLoadRn(context);
  248. EmitDataLoadShift(context);
  249. context.Emit(ilOp);
  250. EmitDataStore(context);
  251. }
  252. private static void EmitDataLoadShift(ILEmitterCtx context)
  253. {
  254. EmitDataLoadRm(context);
  255. context.EmitLdc_I(context.CurrOp.GetBitsCount() - 1);
  256. context.Emit(OpCodes.And);
  257. //Note: Only 32-bits shift values are valid, so when the value is 64-bits
  258. //we need to cast it to a 32-bits integer. This is fine because we
  259. //AND the value and only keep the lower 5 or 6 bits anyway -- it
  260. //could very well fit on a byte.
  261. if (context.CurrOp.RegisterSize != RegisterSize.Int32)
  262. {
  263. context.Emit(OpCodes.Conv_I4);
  264. }
  265. }
  266. private static void EmitZeroCvFlags(ILEmitterCtx context)
  267. {
  268. context.EmitLdc_I4(0);
  269. context.EmitStflg((int)PState.VBit);
  270. context.EmitLdc_I4(0);
  271. context.EmitStflg((int)PState.CBit);
  272. }
  273. }
  274. }