/ src / ARMeilleure / Instructions / InstEmitDiv.cs
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  }