InstEmitHelper.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.State;
  4. using ARMeilleure.Translation;
  5. using System;
  6. using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  7. namespace ARMeilleure.Instructions
  8. {
  9. static class InstEmitHelper
  10. {
  11. public static Operand GetExtendedM(ArmEmitterContext context, int rm, IntType type)
  12. {
  13. Operand value = GetIntOrZR(context, rm);
  14. switch (type)
  15. {
  16. case IntType.UInt8: value = context.ZeroExtend8 (value.Type, value); break;
  17. case IntType.UInt16: value = context.ZeroExtend16(value.Type, value); break;
  18. case IntType.UInt32: value = context.ZeroExtend32(value.Type, value); break;
  19. case IntType.Int8: value = context.SignExtend8 (value.Type, value); break;
  20. case IntType.Int16: value = context.SignExtend16(value.Type, value); break;
  21. case IntType.Int32: value = context.SignExtend32(value.Type, value); break;
  22. }
  23. return value;
  24. }
  25. public static Operand GetIntA32(ArmEmitterContext context, int regIndex)
  26. {
  27. if (regIndex == RegisterAlias.Aarch32Pc)
  28. {
  29. OpCode32 op = (OpCode32)context.CurrOp;
  30. return Const((int)op.GetPc());
  31. }
  32. else
  33. {
  34. return Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32);
  35. }
  36. }
  37. public static Operand GetIntA32AlignedPC(ArmEmitterContext context, int regIndex)
  38. {
  39. if (regIndex == RegisterAlias.Aarch32Pc)
  40. {
  41. OpCode32 op = (OpCode32)context.CurrOp;
  42. return Const((int)(op.GetPc() & 0xfffffffc));
  43. }
  44. else
  45. {
  46. return Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32);
  47. }
  48. }
  49. public static Operand GetVecA32(int regIndex)
  50. {
  51. return Register(regIndex, RegisterType.Vector, OperandType.V128);
  52. }
  53. public static void SetIntA32(ArmEmitterContext context, int regIndex, Operand value)
  54. {
  55. if (regIndex == RegisterAlias.Aarch32Pc)
  56. {
  57. if (!IsA32Return(context))
  58. {
  59. context.StoreToContext();
  60. }
  61. EmitBxWritePc(context, value);
  62. }
  63. else
  64. {
  65. if (value.Type == OperandType.I64)
  66. {
  67. value = context.ConvertI64ToI32(value);
  68. }
  69. Operand reg = Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32);
  70. context.Copy(reg, value);
  71. }
  72. }
  73. public static int GetRegisterAlias(Aarch32Mode mode, int regIndex)
  74. {
  75. // Only registers >= 8 are banked,
  76. // with registers in the range [8, 12] being
  77. // banked for the FIQ mode, and registers
  78. // 13 and 14 being banked for all modes.
  79. if ((uint)regIndex < 8)
  80. {
  81. return regIndex;
  82. }
  83. return GetBankedRegisterAlias(mode, regIndex);
  84. }
  85. public static int GetBankedRegisterAlias(Aarch32Mode mode, int regIndex)
  86. {
  87. switch (regIndex)
  88. {
  89. case 8: return mode == Aarch32Mode.Fiq
  90. ? RegisterAlias.R8Fiq
  91. : RegisterAlias.R8Usr;
  92. case 9: return mode == Aarch32Mode.Fiq
  93. ? RegisterAlias.R9Fiq
  94. : RegisterAlias.R9Usr;
  95. case 10: return mode == Aarch32Mode.Fiq
  96. ? RegisterAlias.R10Fiq
  97. : RegisterAlias.R10Usr;
  98. case 11: return mode == Aarch32Mode.Fiq
  99. ? RegisterAlias.R11Fiq
  100. : RegisterAlias.R11Usr;
  101. case 12: return mode == Aarch32Mode.Fiq
  102. ? RegisterAlias.R12Fiq
  103. : RegisterAlias.R12Usr;
  104. case 13:
  105. switch (mode)
  106. {
  107. case Aarch32Mode.User:
  108. case Aarch32Mode.System: return RegisterAlias.SpUsr;
  109. case Aarch32Mode.Fiq: return RegisterAlias.SpFiq;
  110. case Aarch32Mode.Irq: return RegisterAlias.SpIrq;
  111. case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc;
  112. case Aarch32Mode.Abort: return RegisterAlias.SpAbt;
  113. case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp;
  114. case Aarch32Mode.Undefined: return RegisterAlias.SpUnd;
  115. default: throw new ArgumentException(nameof(mode));
  116. }
  117. case 14:
  118. switch (mode)
  119. {
  120. case Aarch32Mode.User:
  121. case Aarch32Mode.Hypervisor:
  122. case Aarch32Mode.System: return RegisterAlias.LrUsr;
  123. case Aarch32Mode.Fiq: return RegisterAlias.LrFiq;
  124. case Aarch32Mode.Irq: return RegisterAlias.LrIrq;
  125. case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc;
  126. case Aarch32Mode.Abort: return RegisterAlias.LrAbt;
  127. case Aarch32Mode.Undefined: return RegisterAlias.LrUnd;
  128. default: throw new ArgumentException(nameof(mode));
  129. }
  130. default: throw new ArgumentOutOfRangeException(nameof(regIndex));
  131. }
  132. }
  133. public static bool IsA32Return(ArmEmitterContext context)
  134. {
  135. switch (context.CurrOp)
  136. {
  137. case IOpCode32MemMult op:
  138. return true; // Setting PC using LDM is nearly always a return.
  139. case OpCode32AluRsImm op:
  140. return op.Rm == RegisterAlias.Aarch32Lr;
  141. case OpCode32AluRsReg op:
  142. return op.Rm == RegisterAlias.Aarch32Lr;
  143. case OpCode32AluReg op:
  144. return op.Rm == RegisterAlias.Aarch32Lr;
  145. case OpCode32Mem op:
  146. return op.Rn == RegisterAlias.Aarch32Sp && op.WBack && !op.Index; // Setting PC to an address stored on the stack is nearly always a return.
  147. }
  148. return false;
  149. }
  150. public static void EmitBxWritePc(ArmEmitterContext context, Operand pc, int sourceRegister = 0)
  151. {
  152. bool isReturn = sourceRegister == RegisterAlias.Aarch32Lr || IsA32Return(context);
  153. Operand mode = context.BitwiseAnd(pc, Const(1));
  154. SetFlag(context, PState.TFlag, mode);
  155. Operand addr = context.ConditionalSelect(mode, context.BitwiseAnd(pc, Const(~1)), context.BitwiseAnd(pc, Const(~3)));
  156. InstEmitFlowHelper.EmitVirtualJump(context, addr, isReturn);
  157. }
  158. public static Operand GetIntOrZR(ArmEmitterContext context, int regIndex)
  159. {
  160. if (regIndex == RegisterConsts.ZeroIndex)
  161. {
  162. OperandType type = context.CurrOp.GetOperandType();
  163. return type == OperandType.I32 ? Const(0) : Const(0L);
  164. }
  165. else
  166. {
  167. return GetIntOrSP(context, regIndex);
  168. }
  169. }
  170. public static void SetIntOrZR(ArmEmitterContext context, int regIndex, Operand value)
  171. {
  172. if (regIndex == RegisterConsts.ZeroIndex)
  173. {
  174. return;
  175. }
  176. SetIntOrSP(context, regIndex, value);
  177. }
  178. public static Operand GetIntOrSP(ArmEmitterContext context, int regIndex)
  179. {
  180. Operand value = Register(regIndex, RegisterType.Integer, OperandType.I64);
  181. if (context.CurrOp.RegisterSize == RegisterSize.Int32)
  182. {
  183. value = context.ConvertI64ToI32(value);
  184. }
  185. return value;
  186. }
  187. public static void SetIntOrSP(ArmEmitterContext context, int regIndex, Operand value)
  188. {
  189. Operand reg = Register(regIndex, RegisterType.Integer, OperandType.I64);
  190. if (value.Type == OperandType.I32)
  191. {
  192. value = context.ZeroExtend32(OperandType.I64, value);
  193. }
  194. context.Copy(reg, value);
  195. }
  196. public static Operand GetVec(int regIndex)
  197. {
  198. return Register(regIndex, RegisterType.Vector, OperandType.V128);
  199. }
  200. public static Operand GetFlag(PState stateFlag)
  201. {
  202. return Register((int)stateFlag, RegisterType.Flag, OperandType.I32);
  203. }
  204. public static Operand GetFpFlag(FPState stateFlag)
  205. {
  206. return Register((int)stateFlag, RegisterType.FpFlag, OperandType.I32);
  207. }
  208. public static void SetFlag(ArmEmitterContext context, PState stateFlag, Operand value)
  209. {
  210. context.Copy(GetFlag(stateFlag), value);
  211. context.MarkFlagSet(stateFlag);
  212. }
  213. public static void SetFpFlag(ArmEmitterContext context, FPState stateFlag, Operand value)
  214. {
  215. context.Copy(GetFpFlag(stateFlag), value);
  216. }
  217. }
  218. }