InstEmitMul32.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.Translation;
  4. using System;
  5. using static ARMeilleure.Instructions.InstEmitAluHelper;
  6. using static ARMeilleure.Instructions.InstEmitHelper;
  7. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  8. namespace ARMeilleure.Instructions
  9. {
  10. static partial class InstEmit32
  11. {
  12. [Flags]
  13. private enum MullFlags
  14. {
  15. Subtract = 1,
  16. Add = 1 << 1,
  17. Signed = 1 << 2,
  18. SignedAdd = Signed | Add,
  19. SignedSubtract = Signed | Subtract
  20. }
  21. public static void Mla(ArmEmitterContext context)
  22. {
  23. OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
  24. Operand n = GetAluN(context);
  25. Operand m = GetAluM(context);
  26. Operand a = GetIntA32(context, op.Ra);
  27. Operand res = context.Add(a, context.Multiply(n, m));
  28. if (op.SetFlags)
  29. {
  30. EmitNZFlagsCheck(context, res);
  31. }
  32. EmitAluStore(context, res);
  33. }
  34. public static void Mls(ArmEmitterContext context)
  35. {
  36. OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
  37. Operand n = GetAluN(context);
  38. Operand m = GetAluM(context);
  39. Operand a = GetIntA32(context, op.Ra);
  40. Operand res = context.Subtract(a, context.Multiply(n, m));
  41. EmitAluStore(context, res);
  42. }
  43. public static void Smull(ArmEmitterContext context)
  44. {
  45. OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
  46. Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn));
  47. Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm));
  48. Operand res = context.Multiply(n, m);
  49. Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
  50. Operand lo = context.ConvertI64ToI32(res);
  51. if (op.SetFlags)
  52. {
  53. EmitNZFlagsCheck(context, res);
  54. }
  55. EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
  56. EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
  57. }
  58. public static void Smmla(ArmEmitterContext context)
  59. {
  60. EmitSmmul(context, MullFlags.SignedAdd);
  61. }
  62. public static void Smmls(ArmEmitterContext context)
  63. {
  64. EmitSmmul(context, MullFlags.SignedSubtract);
  65. }
  66. public static void Smmul(ArmEmitterContext context)
  67. {
  68. EmitSmmul(context, MullFlags.Signed);
  69. }
  70. private static void EmitSmmul(ArmEmitterContext context, MullFlags flags)
  71. {
  72. OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
  73. Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn));
  74. Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm));
  75. Operand res = context.Multiply(n, m);
  76. if (flags.HasFlag(MullFlags.Add) && op.Ra != 0xf)
  77. {
  78. res = context.Add(context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Ra)), Const(32)), res);
  79. }
  80. else if (flags.HasFlag(MullFlags.Subtract))
  81. {
  82. res = context.Subtract(context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Ra)), Const(32)), res);
  83. }
  84. if (op.R)
  85. {
  86. res = context.Add(res, Const(0x80000000L));
  87. }
  88. Operand hi = context.ConvertI64ToI32(context.ShiftRightSI(res, Const(32)));
  89. EmitGenericAluStoreA32(context, op.Rd, false, hi);
  90. }
  91. public static void Smlab(ArmEmitterContext context)
  92. {
  93. OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
  94. Operand n = GetIntA32(context, op.Rn);
  95. Operand m = GetIntA32(context, op.Rm);
  96. if (op.NHigh)
  97. {
  98. n = context.SignExtend16(OperandType.I32, context.ShiftRightUI(n, Const(16)));
  99. }
  100. else
  101. {
  102. n = context.SignExtend16(OperandType.I32, n);
  103. }
  104. if (op.MHigh)
  105. {
  106. m = context.SignExtend16(OperandType.I32, context.ShiftRightUI(m, Const(16)));
  107. }
  108. else
  109. {
  110. m = context.SignExtend16(OperandType.I32, m);
  111. }
  112. Operand res = context.Multiply(n, m);
  113. Operand a = GetIntA32(context, op.Ra);
  114. res = context.Add(res, a);
  115. // TODO: set Q flag when last addition overflows (saturation)?
  116. EmitGenericAluStoreA32(context, op.Rd, false, res);
  117. }
  118. public static void Smlal(ArmEmitterContext context)
  119. {
  120. EmitMlal(context, true);
  121. }
  122. public static void Smlalh(ArmEmitterContext context)
  123. {
  124. OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
  125. Operand n = GetIntA32(context, op.Rn);
  126. Operand m = GetIntA32(context, op.Rm);
  127. if (op.NHigh)
  128. {
  129. n = context.SignExtend16(OperandType.I64, context.ShiftRightUI(n, Const(16)));
  130. }
  131. else
  132. {
  133. n = context.SignExtend16(OperandType.I64, n);
  134. }
  135. if (op.MHigh)
  136. {
  137. m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16)));
  138. }
  139. else
  140. {
  141. m = context.SignExtend16(OperandType.I64, m);
  142. }
  143. Operand res = context.Multiply(n, m);
  144. Operand toAdd = context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi)), Const(32));
  145. toAdd = context.BitwiseOr(toAdd, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo)));
  146. res = context.Add(res, toAdd);
  147. Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
  148. Operand lo = context.ConvertI64ToI32(res);
  149. EmitGenericAluStoreA32(context, op.RdHi, false, hi);
  150. EmitGenericAluStoreA32(context, op.RdLo, false, lo);
  151. }
  152. public static void Smulh(ArmEmitterContext context)
  153. {
  154. OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
  155. Operand n = GetIntA32(context, op.Rn);
  156. Operand m = GetIntA32(context, op.Rm);
  157. if (op.NHigh)
  158. {
  159. n = context.ShiftRightSI(n, Const(16));
  160. }
  161. else
  162. {
  163. n = context.SignExtend16(OperandType.I32, n);
  164. }
  165. if (op.MHigh)
  166. {
  167. m = context.ShiftRightSI(m, Const(16));
  168. }
  169. else
  170. {
  171. m = context.SignExtend16(OperandType.I32, m);
  172. }
  173. Operand res = context.Multiply(n, m);
  174. EmitGenericAluStoreA32(context, op.Rd, false, res);
  175. }
  176. public static void Umlal(ArmEmitterContext context)
  177. {
  178. EmitMlal(context, false);
  179. }
  180. public static void Umull(ArmEmitterContext context)
  181. {
  182. OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
  183. Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn));
  184. Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm));
  185. Operand res = context.Multiply(n, m);
  186. Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
  187. Operand lo = context.ConvertI64ToI32(res);
  188. if (op.SetFlags)
  189. {
  190. EmitNZFlagsCheck(context, res);
  191. }
  192. EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
  193. EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
  194. }
  195. public static void EmitMlal(ArmEmitterContext context, bool signed)
  196. {
  197. OpCode32AluUmull op = (OpCode32AluUmull)context.CurrOp;
  198. Operand n = GetIntA32(context, op.Rn);
  199. Operand m = GetIntA32(context, op.Rm);
  200. if (signed)
  201. {
  202. n = context.SignExtend32(OperandType.I64, n);
  203. m = context.SignExtend32(OperandType.I64, m);
  204. }
  205. else
  206. {
  207. n = context.ZeroExtend32(OperandType.I64, n);
  208. m = context.ZeroExtend32(OperandType.I64, m);
  209. }
  210. Operand res = context.Multiply(n, m);
  211. Operand toAdd = context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi)), Const(32));
  212. toAdd = context.BitwiseOr(toAdd, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo)));
  213. res = context.Add(res, toAdd);
  214. Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
  215. Operand lo = context.ConvertI64ToI32(res);
  216. if (op.SetFlags)
  217. {
  218. EmitNZFlagsCheck(context, res);
  219. }
  220. EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
  221. EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
  222. }
  223. }
  224. }