InstEmitAlu.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.State; 4 using ARMeilleure.Translation; 5 using System.Diagnostics; 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 InstEmit 13 { 14 public static void Adc(ArmEmitterContext context) => EmitAdc(context, setFlags: false); 15 public static void Adcs(ArmEmitterContext context) => EmitAdc(context, setFlags: true); 16 17 private static void EmitAdc(ArmEmitterContext context, bool setFlags) 18 { 19 Operand n = GetAluN(context); 20 Operand m = GetAluM(context); 21 22 Operand d = context.Add(n, m); 23 24 Operand carry = GetFlag(PState.CFlag); 25 26 if (context.CurrOp.RegisterSize == RegisterSize.Int64) 27 { 28 carry = context.ZeroExtend32(OperandType.I64, carry); 29 } 30 31 d = context.Add(d, carry); 32 33 if (setFlags) 34 { 35 EmitNZFlagsCheck(context, d); 36 37 EmitAdcsCCheck(context, n, d); 38 EmitAddsVCheck(context, n, m, d); 39 } 40 41 SetAluDOrZR(context, d); 42 } 43 44 public static void Add(ArmEmitterContext context) 45 { 46 SetAluD(context, context.Add(GetAluN(context), GetAluM(context))); 47 } 48 49 public static void Adds(ArmEmitterContext context) 50 { 51 Operand n = GetAluN(context); 52 Operand m = GetAluM(context); 53 54 context.MarkComparison(n, m); 55 56 Operand d = context.Add(n, m); 57 58 EmitNZFlagsCheck(context, d); 59 60 EmitAddsCCheck(context, n, d); 61 EmitAddsVCheck(context, n, m, d); 62 63 SetAluDOrZR(context, d); 64 } 65 66 public static void And(ArmEmitterContext context) 67 { 68 SetAluD(context, context.BitwiseAnd(GetAluN(context), GetAluM(context))); 69 } 70 71 public static void Ands(ArmEmitterContext context) 72 { 73 Operand n = GetAluN(context); 74 Operand m = GetAluM(context); 75 76 Operand d = context.BitwiseAnd(n, m); 77 78 EmitNZFlagsCheck(context, d); 79 EmitCVFlagsClear(context); 80 81 SetAluDOrZR(context, d); 82 } 83 84 public static void Asrv(ArmEmitterContext context) 85 { 86 SetAluDOrZR(context, context.ShiftRightSI(GetAluN(context), GetAluMShift(context))); 87 } 88 89 public static void Bic(ArmEmitterContext context) => EmitBic(context, setFlags: false); 90 public static void Bics(ArmEmitterContext context) => EmitBic(context, setFlags: true); 91 92 private static void EmitBic(ArmEmitterContext context, bool setFlags) 93 { 94 Operand n = GetAluN(context); 95 Operand m = GetAluM(context); 96 97 Operand d = context.BitwiseAnd(n, context.BitwiseNot(m)); 98 99 if (setFlags) 100 { 101 EmitNZFlagsCheck(context, d); 102 EmitCVFlagsClear(context); 103 } 104 105 SetAluD(context, d, setFlags); 106 } 107 108 public static void Cls(ArmEmitterContext context) 109 { 110 OpCodeAlu op = (OpCodeAlu)context.CurrOp; 111 112 Operand n = GetIntOrZR(context, op.Rn); 113 114 Operand nHigh = context.ShiftRightUI(n, Const(1)); 115 116 bool is32Bits = op.RegisterSize == RegisterSize.Int32; 117 118 Operand mask = is32Bits ? Const(int.MaxValue) : Const(long.MaxValue); 119 120 Operand nLow = context.BitwiseAnd(n, mask); 121 122 Operand res = context.CountLeadingZeros(context.BitwiseExclusiveOr(nHigh, nLow)); 123 124 res = context.Subtract(res, Const(res.Type, 1)); 125 126 SetAluDOrZR(context, res); 127 } 128 129 public static void Clz(ArmEmitterContext context) 130 { 131 OpCodeAlu op = (OpCodeAlu)context.CurrOp; 132 133 Operand n = GetIntOrZR(context, op.Rn); 134 135 Operand d = context.CountLeadingZeros(n); 136 137 SetAluDOrZR(context, d); 138 } 139 140 public static void Eon(ArmEmitterContext context) 141 { 142 Operand n = GetAluN(context); 143 Operand m = GetAluM(context); 144 145 Operand d = context.BitwiseExclusiveOr(n, context.BitwiseNot(m)); 146 147 SetAluD(context, d); 148 } 149 150 public static void Eor(ArmEmitterContext context) 151 { 152 SetAluD(context, context.BitwiseExclusiveOr(GetAluN(context), GetAluM(context))); 153 } 154 155 public static void Extr(ArmEmitterContext context) 156 { 157 OpCodeAluRs op = (OpCodeAluRs)context.CurrOp; 158 159 Operand res = GetIntOrZR(context, op.Rm); 160 161 if (op.Shift != 0) 162 { 163 if (op.Rn == op.Rm) 164 { 165 res = context.RotateRight(res, Const(op.Shift)); 166 } 167 else 168 { 169 res = context.ShiftRightUI(res, Const(op.Shift)); 170 171 Operand n = GetIntOrZR(context, op.Rn); 172 173 int invShift = op.GetBitsCount() - op.Shift; 174 175 res = context.BitwiseOr(res, context.ShiftLeft(n, Const(invShift))); 176 } 177 } 178 179 SetAluDOrZR(context, res); 180 } 181 182 public static void Lslv(ArmEmitterContext context) 183 { 184 SetAluDOrZR(context, context.ShiftLeft(GetAluN(context), GetAluMShift(context))); 185 } 186 187 public static void Lsrv(ArmEmitterContext context) 188 { 189 SetAluDOrZR(context, context.ShiftRightUI(GetAluN(context), GetAluMShift(context))); 190 } 191 192 public static void Sbc(ArmEmitterContext context) => EmitSbc(context, setFlags: false); 193 public static void Sbcs(ArmEmitterContext context) => EmitSbc(context, setFlags: true); 194 195 private static void EmitSbc(ArmEmitterContext context, bool setFlags) 196 { 197 Operand n = GetAluN(context); 198 Operand m = GetAluM(context); 199 200 Operand d = context.Subtract(n, m); 201 202 Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); 203 204 if (context.CurrOp.RegisterSize == RegisterSize.Int64) 205 { 206 borrow = context.ZeroExtend32(OperandType.I64, borrow); 207 } 208 209 d = context.Subtract(d, borrow); 210 211 if (setFlags) 212 { 213 EmitNZFlagsCheck(context, d); 214 215 EmitSbcsCCheck(context, n, m); 216 EmitSubsVCheck(context, n, m, d); 217 } 218 219 SetAluDOrZR(context, d); 220 } 221 222 public static void Sub(ArmEmitterContext context) 223 { 224 SetAluD(context, context.Subtract(GetAluN(context), GetAluM(context))); 225 } 226 227 public static void Subs(ArmEmitterContext context) 228 { 229 Operand n = GetAluN(context); 230 Operand m = GetAluM(context); 231 232 context.MarkComparison(n, m); 233 234 Operand d = context.Subtract(n, m); 235 236 EmitNZFlagsCheck(context, d); 237 238 EmitSubsCCheck(context, n, m); 239 EmitSubsVCheck(context, n, m, d); 240 241 SetAluDOrZR(context, d); 242 } 243 244 public static void Orn(ArmEmitterContext context) 245 { 246 Operand n = GetAluN(context); 247 Operand m = GetAluM(context); 248 249 Operand d = context.BitwiseOr(n, context.BitwiseNot(m)); 250 251 SetAluD(context, d); 252 } 253 254 public static void Orr(ArmEmitterContext context) 255 { 256 SetAluD(context, context.BitwiseOr(GetAluN(context), GetAluM(context))); 257 } 258 259 public static void Rbit(ArmEmitterContext context) 260 { 261 OpCodeAlu op = (OpCodeAlu)context.CurrOp; 262 263 Operand n = GetIntOrZR(context, op.Rn); 264 Operand d; 265 266 if (op.RegisterSize == RegisterSize.Int32) 267 { 268 d = EmitReverseBits32Op(context, n); 269 } 270 else 271 { 272 d = EmitReverseBits64Op(context, n); 273 } 274 275 SetAluDOrZR(context, d); 276 } 277 278 private static Operand EmitReverseBits64Op(ArmEmitterContext context, Operand op) 279 { 280 Debug.Assert(op.Type == OperandType.I64); 281 282 Operand val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op, Const(0xaaaaaaaaaaaaaaaaul)), Const(1)), 283 context.ShiftLeft(context.BitwiseAnd(op, Const(0x5555555555555555ul)), Const(1))); 284 285 val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xccccccccccccccccul)), Const(2)), 286 context.ShiftLeft(context.BitwiseAnd(val, Const(0x3333333333333333ul)), Const(2))); 287 val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xf0f0f0f0f0f0f0f0ul)), Const(4)), 288 context.ShiftLeft(context.BitwiseAnd(val, Const(0x0f0f0f0f0f0f0f0ful)), Const(4))); 289 val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xff00ff00ff00ff00ul)), Const(8)), 290 context.ShiftLeft(context.BitwiseAnd(val, Const(0x00ff00ff00ff00fful)), Const(8))); 291 val = context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xffff0000ffff0000ul)), Const(16)), 292 context.ShiftLeft(context.BitwiseAnd(val, Const(0x0000ffff0000fffful)), Const(16))); 293 294 return context.BitwiseOr(context.ShiftRightUI(val, Const(32)), context.ShiftLeft(val, Const(32))); 295 } 296 297 public static void Rev16(ArmEmitterContext context) 298 { 299 OpCodeAlu op = (OpCodeAlu)context.CurrOp; 300 301 Operand n = GetIntOrZR(context, op.Rn); 302 Operand d; 303 304 if (op.RegisterSize == RegisterSize.Int32) 305 { 306 d = EmitReverseBytes16_32Op(context, n); 307 } 308 else 309 { 310 d = EmitReverseBytes16_64Op(context, n); 311 } 312 313 SetAluDOrZR(context, d); 314 } 315 316 public static void Rev32(ArmEmitterContext context) 317 { 318 OpCodeAlu op = (OpCodeAlu)context.CurrOp; 319 320 Operand n = GetIntOrZR(context, op.Rn); 321 Operand d; 322 323 if (op.RegisterSize == RegisterSize.Int32) 324 { 325 d = context.ByteSwap(n); 326 } 327 else 328 { 329 d = EmitReverseBytes32_64Op(context, n); 330 } 331 332 SetAluDOrZR(context, d); 333 } 334 335 private static Operand EmitReverseBytes32_64Op(ArmEmitterContext context, Operand op) 336 { 337 Debug.Assert(op.Type == OperandType.I64); 338 339 Operand val = EmitReverseBytes16_64Op(context, op); 340 341 return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(val, Const(0xffff0000ffff0000ul)), Const(16)), 342 context.ShiftLeft(context.BitwiseAnd(val, Const(0x0000ffff0000fffful)), Const(16))); 343 } 344 345 public static void Rev64(ArmEmitterContext context) 346 { 347 OpCodeAlu op = (OpCodeAlu)context.CurrOp; 348 349 SetAluDOrZR(context, context.ByteSwap(GetIntOrZR(context, op.Rn))); 350 } 351 352 public static void Rorv(ArmEmitterContext context) 353 { 354 SetAluDOrZR(context, context.RotateRight(GetAluN(context), GetAluMShift(context))); 355 } 356 357 private static Operand GetAluMShift(ArmEmitterContext context) 358 { 359 IOpCodeAluRs op = (IOpCodeAluRs)context.CurrOp; 360 361 Operand m = GetIntOrZR(context, op.Rm); 362 363 if (op.RegisterSize == RegisterSize.Int64) 364 { 365 m = context.ConvertI64ToI32(m); 366 } 367 368 return context.BitwiseAnd(m, Const(context.CurrOp.GetBitsCount() - 1)); 369 } 370 371 private static void EmitCVFlagsClear(ArmEmitterContext context) 372 { 373 SetFlag(context, PState.CFlag, Const(0)); 374 SetFlag(context, PState.VFlag, Const(0)); 375 } 376 377 public static void SetAluD(ArmEmitterContext context, Operand d) 378 { 379 SetAluD(context, d, x31IsZR: false); 380 } 381 382 public static void SetAluDOrZR(ArmEmitterContext context, Operand d) 383 { 384 SetAluD(context, d, x31IsZR: true); 385 } 386 387 public static void SetAluD(ArmEmitterContext context, Operand d, bool x31IsZR) 388 { 389 IOpCodeAlu op = (IOpCodeAlu)context.CurrOp; 390 391 if ((x31IsZR || op is IOpCodeAluRs) && op.Rd == RegisterConsts.ZeroIndex) 392 { 393 return; 394 } 395 396 SetIntOrSP(context, op.Rd, d); 397 } 398 } 399 }