InstEmitAluHelper.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.State;
  4. using ARMeilleure.Translation;
  5. using System;
  6. using static ARMeilleure.Instructions.InstEmitHelper;
  7. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  8. namespace ARMeilleure.Instructions
  9. {
  10. static class InstEmitAluHelper
  11. {
  12. public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
  13. {
  14. SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
  15. SetFlag(context, PState.ZFlag, context.ICompareEqual(d, Const(d.Type, 0)));
  16. }
  17. public static void EmitAdcsCCheck(ArmEmitterContext context, Operand n, Operand d)
  18. {
  19. // C = (Rd == Rn && CIn) || Rd < Rn
  20. Operand cIn = GetFlag(PState.CFlag);
  21. Operand cOut = context.BitwiseAnd(context.ICompareEqual(d, n), cIn);
  22. cOut = context.BitwiseOr(cOut, context.ICompareLessUI(d, n));
  23. SetFlag(context, PState.CFlag, cOut);
  24. }
  25. public static void EmitAddsCCheck(ArmEmitterContext context, Operand n, Operand d)
  26. {
  27. // C = Rd < Rn
  28. SetFlag(context, PState.CFlag, context.ICompareLessUI(d, n));
  29. }
  30. public static void EmitAddsVCheck(ArmEmitterContext context, Operand n, Operand m, Operand d)
  31. {
  32. // V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
  33. Operand vOut = context.BitwiseExclusiveOr(d, n);
  34. vOut = context.BitwiseAnd(vOut, context.BitwiseNot(context.BitwiseExclusiveOr(n, m)));
  35. vOut = context.ICompareLess(vOut, Const(vOut.Type, 0));
  36. SetFlag(context, PState.VFlag, vOut);
  37. }
  38. public static void EmitSbcsCCheck(ArmEmitterContext context, Operand n, Operand m)
  39. {
  40. // C = (Rn == Rm && CIn) || Rn > Rm
  41. Operand cIn = GetFlag(PState.CFlag);
  42. Operand cOut = context.BitwiseAnd(context.ICompareEqual(n, m), cIn);
  43. cOut = context.BitwiseOr(cOut, context.ICompareGreaterUI(n, m));
  44. SetFlag(context, PState.CFlag, cOut);
  45. }
  46. public static void EmitSubsCCheck(ArmEmitterContext context, Operand n, Operand m)
  47. {
  48. // C = Rn >= Rm
  49. SetFlag(context, PState.CFlag, context.ICompareGreaterOrEqualUI(n, m));
  50. }
  51. public static void EmitSubsVCheck(ArmEmitterContext context, Operand n, Operand m, Operand d)
  52. {
  53. // V = (Rd ^ Rn) & (Rn ^ Rm) < 0
  54. Operand vOut = context.BitwiseExclusiveOr(d, n);
  55. vOut = context.BitwiseAnd(vOut, context.BitwiseExclusiveOr(n, m));
  56. vOut = context.ICompareLess(vOut, Const(vOut.Type, 0));
  57. SetFlag(context, PState.VFlag, vOut);
  58. }
  59. public static Operand GetAluN(ArmEmitterContext context)
  60. {
  61. if (context.CurrOp is IOpCodeAlu op)
  62. {
  63. if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs)
  64. {
  65. return GetIntOrZR(context, op.Rn);
  66. }
  67. else
  68. {
  69. return GetIntOrSP(context, op.Rn);
  70. }
  71. }
  72. else if (context.CurrOp is IOpCode32Alu op32)
  73. {
  74. return GetIntA32(context, op32.Rn);
  75. }
  76. else
  77. {
  78. throw InvalidOpCodeType(context.CurrOp);
  79. }
  80. }
  81. public static Operand GetAluM(ArmEmitterContext context, bool setCarry = true)
  82. {
  83. switch (context.CurrOp)
  84. {
  85. // ARM32.
  86. case OpCode32AluImm op:
  87. {
  88. if (op.SetFlags && op.IsRotated)
  89. {
  90. SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
  91. }
  92. return Const(op.Immediate);
  93. }
  94. case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
  95. case OpCodeT16AluImm8 op: return Const(op.Immediate);
  96. // ARM64.
  97. case IOpCodeAluImm op:
  98. {
  99. if (op.GetOperandType() == OperandType.I32)
  100. {
  101. return Const((int)op.Immediate);
  102. }
  103. else
  104. {
  105. return Const(op.Immediate);
  106. }
  107. }
  108. case IOpCodeAluRs op:
  109. {
  110. Operand value = GetIntOrZR(context, op.Rm);
  111. switch (op.ShiftType)
  112. {
  113. case ShiftType.Lsl: value = context.ShiftLeft (value, Const(op.Shift)); break;
  114. case ShiftType.Lsr: value = context.ShiftRightUI(value, Const(op.Shift)); break;
  115. case ShiftType.Asr: value = context.ShiftRightSI(value, Const(op.Shift)); break;
  116. case ShiftType.Ror: value = context.RotateRight (value, Const(op.Shift)); break;
  117. }
  118. return value;
  119. }
  120. case IOpCodeAluRx op:
  121. {
  122. Operand value = GetExtendedM(context, op.Rm, op.IntType);
  123. value = context.ShiftLeft(value, Const(op.Shift));
  124. return value;
  125. }
  126. default: throw InvalidOpCodeType(context.CurrOp);
  127. }
  128. }
  129. private static Exception InvalidOpCodeType(OpCode opCode)
  130. {
  131. return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\".");
  132. }
  133. // ARM32 helpers.
  134. private static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry)
  135. {
  136. Operand m = GetIntA32(context, op.Rm);
  137. int shift = op.Imm;
  138. if (shift == 0)
  139. {
  140. switch (op.ShiftType)
  141. {
  142. case ShiftType.Lsr: shift = 32; break;
  143. case ShiftType.Asr: shift = 32; break;
  144. case ShiftType.Ror: shift = 1; break;
  145. }
  146. }
  147. if (shift != 0)
  148. {
  149. setCarry &= op.SetFlags;
  150. switch (op.ShiftType)
  151. {
  152. case ShiftType.Lsl: m = GetLslC(context, m, setCarry, shift); break;
  153. case ShiftType.Lsr: m = GetLsrC(context, m, setCarry, shift); break;
  154. case ShiftType.Asr: m = GetAsrC(context, m, setCarry, shift); break;
  155. case ShiftType.Ror:
  156. if (op.Imm != 0)
  157. {
  158. m = GetRorC(context, m, setCarry, shift);
  159. }
  160. else
  161. {
  162. m = GetRrxC(context, m, setCarry);
  163. }
  164. break;
  165. }
  166. }
  167. return m;
  168. }
  169. private static Operand GetLslC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
  170. {
  171. if ((uint)shift > 32)
  172. {
  173. return GetShiftByMoreThan32(context, setCarry);
  174. }
  175. else if (shift == 32)
  176. {
  177. if (setCarry)
  178. {
  179. SetCarryMLsb(context, m);
  180. }
  181. return Const(0);
  182. }
  183. else
  184. {
  185. if (setCarry)
  186. {
  187. Operand cOut = context.ShiftRightUI(m, Const(32 - shift));
  188. cOut = context.BitwiseAnd(cOut, Const(1));
  189. SetFlag(context, PState.CFlag, cOut);
  190. }
  191. return context.ShiftLeft(m, Const(shift));
  192. }
  193. }
  194. private static Operand GetLsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
  195. {
  196. if ((uint)shift > 32)
  197. {
  198. return GetShiftByMoreThan32(context, setCarry);
  199. }
  200. else if (shift == 32)
  201. {
  202. if (setCarry)
  203. {
  204. SetCarryMMsb(context, m);
  205. }
  206. return Const(0);
  207. }
  208. else
  209. {
  210. if (setCarry)
  211. {
  212. SetCarryMShrOut(context, m, shift);
  213. }
  214. return context.ShiftRightUI(m, Const(shift));
  215. }
  216. }
  217. private static Operand GetShiftByMoreThan32(ArmEmitterContext context, bool setCarry)
  218. {
  219. if (setCarry)
  220. {
  221. SetFlag(context, PState.CFlag, Const(0));
  222. }
  223. return Const(0);
  224. }
  225. private static Operand GetAsrC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
  226. {
  227. if ((uint)shift >= 32)
  228. {
  229. m = context.ShiftRightSI(m, Const(31));
  230. if (setCarry)
  231. {
  232. SetCarryMLsb(context, m);
  233. }
  234. return m;
  235. }
  236. else
  237. {
  238. if (setCarry)
  239. {
  240. SetCarryMShrOut(context, m, shift);
  241. }
  242. return context.ShiftRightSI(m, Const(shift));
  243. }
  244. }
  245. private static Operand GetRorC(ArmEmitterContext context, Operand m, bool setCarry, int shift)
  246. {
  247. shift &= 0x1f;
  248. m = context.RotateRight(m, Const(shift));
  249. if (setCarry)
  250. {
  251. SetCarryMMsb(context, m);
  252. }
  253. return m;
  254. }
  255. private static Operand GetRrxC(ArmEmitterContext context, Operand m, bool setCarry)
  256. {
  257. // Rotate right by 1 with carry.
  258. Operand cIn = context.Copy(GetFlag(PState.CFlag));
  259. if (setCarry)
  260. {
  261. SetCarryMLsb(context, m);
  262. }
  263. m = context.ShiftRightUI(m, Const(1));
  264. m = context.BitwiseOr(m, context.ShiftLeft(cIn, Const(31)));
  265. return m;
  266. }
  267. private static void SetCarryMLsb(ArmEmitterContext context, Operand m)
  268. {
  269. SetFlag(context, PState.CFlag, context.BitwiseAnd(m, Const(1)));
  270. }
  271. private static void SetCarryMMsb(ArmEmitterContext context, Operand m)
  272. {
  273. SetFlag(context, PState.CFlag, context.ShiftRightUI(m, Const(31)));
  274. }
  275. private static void SetCarryMShrOut(ArmEmitterContext context, Operand m, int shift)
  276. {
  277. Operand cOut = context.ShiftRightUI(m, Const(shift - 1));
  278. cOut = context.BitwiseAnd(cOut, Const(1));
  279. SetFlag(context, PState.CFlag, cOut);
  280. }
  281. }
  282. }