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