InstEmitDiv.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.Translation; 4 using static ARMeilleure.Instructions.InstEmitHelper; 5 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 6 7 namespace ARMeilleure.Instructions 8 { 9 static partial class InstEmit 10 { 11 public static void Sdiv(ArmEmitterContext context) => EmitDiv(context, unsigned: false); 12 public static void Udiv(ArmEmitterContext context) => EmitDiv(context, unsigned: true); 13 14 private static void EmitDiv(ArmEmitterContext context, bool unsigned) 15 { 16 OpCodeAluBinary op = (OpCodeAluBinary)context.CurrOp; 17 18 // If Rm == 0, Rd = 0 (division by zero). 19 Operand n = GetIntOrZR(context, op.Rn); 20 Operand m = GetIntOrZR(context, op.Rm); 21 22 Operand divisorIsZero = context.ICompareEqual(m, Const(m.Type, 0)); 23 24 Operand lblBadDiv = Label(); 25 Operand lblEnd = Label(); 26 27 context.BranchIfTrue(lblBadDiv, divisorIsZero); 28 29 if (!unsigned) 30 { 31 // If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). 32 bool is32Bits = op.RegisterSize == RegisterSize.Int32; 33 34 Operand intMin = is32Bits ? Const(int.MinValue) : Const(long.MinValue); 35 Operand minus1 = is32Bits ? Const(-1) : Const(-1L); 36 37 Operand nIsIntMin = context.ICompareEqual(n, intMin); 38 Operand mIsMinus1 = context.ICompareEqual(m, minus1); 39 40 Operand lblGoodDiv = Label(); 41 42 context.BranchIfFalse(lblGoodDiv, context.BitwiseAnd(nIsIntMin, mIsMinus1)); 43 44 SetAluDOrZR(context, intMin); 45 46 context.Branch(lblEnd); 47 48 context.MarkLabel(lblGoodDiv); 49 } 50 51 Operand d = unsigned 52 ? context.DivideUI(n, m) 53 : context.Divide(n, m); 54 55 SetAluDOrZR(context, d); 56 57 context.Branch(lblEnd); 58 59 context.MarkLabel(lblBadDiv); 60 61 SetAluDOrZR(context, Const(op.GetOperandType(), 0)); 62 63 context.MarkLabel(lblEnd); 64 } 65 } 66 }