InstEmitMul32.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.State; 4 using ARMeilleure.Translation; 5 using System; 6 using static ARMeilleure.Instructions.InstEmitAluHelper; 7 using static ARMeilleure.Instructions.InstEmitHelper; 8 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 9 10 namespace ARMeilleure.Instructions 11 { 12 static partial class InstEmit32 13 { 14 [Flags] 15 private enum MullFlags 16 { 17 Subtract = 1, 18 Add = 1 << 1, 19 Signed = 1 << 2, 20 21 SignedAdd = Signed | Add, 22 SignedSubtract = Signed | Subtract, 23 } 24 25 public static void Mla(ArmEmitterContext context) 26 { 27 IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp; 28 29 Operand n = GetAluN(context); 30 Operand m = GetAluM(context); 31 Operand a = GetIntA32(context, op.Ra); 32 33 Operand res = context.Add(a, context.Multiply(n, m)); 34 35 if (ShouldSetFlags(context)) 36 { 37 EmitNZFlagsCheck(context, res); 38 } 39 40 EmitAluStore(context, res); 41 } 42 43 public static void Mls(ArmEmitterContext context) 44 { 45 IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp; 46 47 Operand n = GetAluN(context); 48 Operand m = GetAluM(context); 49 Operand a = GetIntA32(context, op.Ra); 50 51 Operand res = context.Subtract(a, context.Multiply(n, m)); 52 53 EmitAluStore(context, res); 54 } 55 56 public static void Smmla(ArmEmitterContext context) 57 { 58 EmitSmmul(context, MullFlags.SignedAdd); 59 } 60 61 public static void Smmls(ArmEmitterContext context) 62 { 63 EmitSmmul(context, MullFlags.SignedSubtract); 64 } 65 66 public static void Smmul(ArmEmitterContext context) 67 { 68 EmitSmmul(context, MullFlags.Signed); 69 } 70 71 private static void EmitSmmul(ArmEmitterContext context, MullFlags flags) 72 { 73 IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp; 74 75 Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn)); 76 Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm)); 77 78 Operand res = context.Multiply(n, m); 79 80 if (flags.HasFlag(MullFlags.Add) && op.Ra != 0xf) 81 { 82 res = context.Add(context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Ra)), Const(32)), res); 83 } 84 else if (flags.HasFlag(MullFlags.Subtract)) 85 { 86 res = context.Subtract(context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Ra)), Const(32)), res); 87 } 88 89 if (op.R) 90 { 91 res = context.Add(res, Const(0x80000000L)); 92 } 93 94 Operand hi = context.ConvertI64ToI32(context.ShiftRightSI(res, Const(32))); 95 96 EmitGenericAluStoreA32(context, op.Rd, false, hi); 97 } 98 99 public static void Smla__(ArmEmitterContext context) 100 { 101 IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp; 102 103 Operand n = GetIntA32(context, op.Rn); 104 Operand m = GetIntA32(context, op.Rm); 105 Operand a = GetIntA32(context, op.Ra); 106 107 if (op.NHigh) 108 { 109 n = context.SignExtend16(OperandType.I64, context.ShiftRightUI(n, Const(16))); 110 } 111 else 112 { 113 n = context.SignExtend16(OperandType.I64, n); 114 } 115 116 if (op.MHigh) 117 { 118 m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16))); 119 } 120 else 121 { 122 m = context.SignExtend16(OperandType.I64, m); 123 } 124 125 Operand res = context.Multiply(n, m); 126 127 Operand toAdd = context.SignExtend32(OperandType.I64, a); 128 res = context.Add(res, toAdd); 129 Operand q = context.ICompareNotEqual(res, context.SignExtend32(OperandType.I64, res)); 130 res = context.ConvertI64ToI32(res); 131 132 UpdateQFlag(context, q); 133 134 EmitGenericAluStoreA32(context, op.Rd, false, res); 135 } 136 137 public static void Smlal(ArmEmitterContext context) 138 { 139 EmitMlal(context, true); 140 } 141 142 public static void Smlal__(ArmEmitterContext context) 143 { 144 IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp; 145 146 Operand n = GetIntA32(context, op.Rn); 147 Operand m = GetIntA32(context, op.Rm); 148 149 if (op.NHigh) 150 { 151 n = context.SignExtend16(OperandType.I64, context.ShiftRightUI(n, Const(16))); 152 } 153 else 154 { 155 n = context.SignExtend16(OperandType.I64, n); 156 } 157 158 if (op.MHigh) 159 { 160 m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16))); 161 } 162 else 163 { 164 m = context.SignExtend16(OperandType.I64, m); 165 } 166 167 Operand res = context.Multiply(n, m); 168 169 Operand toAdd = context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi)), Const(32)); 170 toAdd = context.BitwiseOr(toAdd, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo))); 171 res = context.Add(res, toAdd); 172 173 Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); 174 Operand lo = context.ConvertI64ToI32(res); 175 176 EmitGenericAluStoreA32(context, op.RdHi, false, hi); 177 EmitGenericAluStoreA32(context, op.RdLo, false, lo); 178 } 179 180 public static void Smlaw_(ArmEmitterContext context) 181 { 182 IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp; 183 184 Operand n = GetIntA32(context, op.Rn); 185 Operand m = GetIntA32(context, op.Rm); 186 Operand a = GetIntA32(context, op.Ra); 187 188 if (op.MHigh) 189 { 190 m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16))); 191 } 192 else 193 { 194 m = context.SignExtend16(OperandType.I64, m); 195 } 196 197 Operand res = context.Multiply(context.SignExtend32(OperandType.I64, n), m); 198 199 Operand toAdd = context.ShiftLeft(context.SignExtend32(OperandType.I64, a), Const(16)); 200 res = context.Add(res, toAdd); 201 res = context.ShiftRightSI(res, Const(16)); 202 Operand q = context.ICompareNotEqual(res, context.SignExtend32(OperandType.I64, res)); 203 res = context.ConvertI64ToI32(res); 204 205 UpdateQFlag(context, q); 206 207 EmitGenericAluStoreA32(context, op.Rd, false, res); 208 } 209 210 public static void Smul__(ArmEmitterContext context) 211 { 212 IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp; 213 214 Operand n = GetIntA32(context, op.Rn); 215 Operand m = GetIntA32(context, op.Rm); 216 217 if (op.NHigh) 218 { 219 n = context.ShiftRightSI(n, Const(16)); 220 } 221 else 222 { 223 n = context.SignExtend16(OperandType.I32, n); 224 } 225 226 if (op.MHigh) 227 { 228 m = context.ShiftRightSI(m, Const(16)); 229 } 230 else 231 { 232 m = context.SignExtend16(OperandType.I32, m); 233 } 234 235 Operand res = context.Multiply(n, m); 236 237 EmitGenericAluStoreA32(context, op.Rd, false, res); 238 } 239 240 public static void Smull(ArmEmitterContext context) 241 { 242 IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp; 243 244 Operand n = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rn)); 245 Operand m = context.SignExtend32(OperandType.I64, GetIntA32(context, op.Rm)); 246 247 Operand res = context.Multiply(n, m); 248 249 Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); 250 Operand lo = context.ConvertI64ToI32(res); 251 252 if (ShouldSetFlags(context)) 253 { 254 EmitNZFlagsCheck(context, res); 255 } 256 257 EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi); 258 EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo); 259 } 260 261 public static void Smulw_(ArmEmitterContext context) 262 { 263 IOpCode32AluMla op = (IOpCode32AluMla)context.CurrOp; 264 265 Operand n = GetIntA32(context, op.Rn); 266 Operand m = GetIntA32(context, op.Rm); 267 268 if (op.MHigh) 269 { 270 m = context.SignExtend16(OperandType.I64, context.ShiftRightUI(m, Const(16))); 271 } 272 else 273 { 274 m = context.SignExtend16(OperandType.I64, m); 275 } 276 277 Operand res = context.Multiply(context.SignExtend32(OperandType.I64, n), m); 278 279 res = context.ShiftRightUI(res, Const(16)); 280 res = context.ConvertI64ToI32(res); 281 282 EmitGenericAluStoreA32(context, op.Rd, false, res); 283 } 284 285 public static void Umaal(ArmEmitterContext context) 286 { 287 IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp; 288 289 Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn)); 290 Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm)); 291 Operand dHi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi)); 292 Operand dLo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo)); 293 294 Operand res = context.Multiply(n, m); 295 res = context.Add(res, dHi); 296 res = context.Add(res, dLo); 297 298 Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); 299 Operand lo = context.ConvertI64ToI32(res); 300 301 EmitGenericAluStoreA32(context, op.RdHi, false, hi); 302 EmitGenericAluStoreA32(context, op.RdLo, false, lo); 303 } 304 305 public static void Umlal(ArmEmitterContext context) 306 { 307 EmitMlal(context, false); 308 } 309 310 public static void Umull(ArmEmitterContext context) 311 { 312 IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp; 313 314 Operand n = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rn)); 315 Operand m = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rm)); 316 317 Operand res = context.Multiply(n, m); 318 319 Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); 320 Operand lo = context.ConvertI64ToI32(res); 321 322 if (ShouldSetFlags(context)) 323 { 324 EmitNZFlagsCheck(context, res); 325 } 326 327 EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi); 328 EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo); 329 } 330 331 private static void EmitMlal(ArmEmitterContext context, bool signed) 332 { 333 IOpCode32AluUmull op = (IOpCode32AluUmull)context.CurrOp; 334 335 Operand n = GetIntA32(context, op.Rn); 336 Operand m = GetIntA32(context, op.Rm); 337 338 if (signed) 339 { 340 n = context.SignExtend32(OperandType.I64, n); 341 m = context.SignExtend32(OperandType.I64, m); 342 } 343 else 344 { 345 n = context.ZeroExtend32(OperandType.I64, n); 346 m = context.ZeroExtend32(OperandType.I64, m); 347 } 348 349 Operand res = context.Multiply(n, m); 350 351 Operand toAdd = context.ShiftLeft(context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdHi)), Const(32)); 352 toAdd = context.BitwiseOr(toAdd, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.RdLo))); 353 res = context.Add(res, toAdd); 354 355 Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32))); 356 Operand lo = context.ConvertI64ToI32(res); 357 358 if (ShouldSetFlags(context)) 359 { 360 EmitNZFlagsCheck(context, res); 361 } 362 363 EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi); 364 EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo); 365 } 366 367 private static void UpdateQFlag(ArmEmitterContext context, Operand q) 368 { 369 Operand lblSkipSetQ = Label(); 370 371 context.BranchIfFalse(lblSkipSetQ, q); 372 373 SetFlag(context, PState.QFlag, Const(1)); 374 375 context.MarkLabel(lblSkipSetQ); 376 } 377 } 378 }