/ src / ARMeilleure / Instructions / InstEmitBfm.cs
InstEmitBfm.cs
  1  using ARMeilleure.Decoders;
  2  using ARMeilleure.IntermediateRepresentation;
  3  using ARMeilleure.Translation;
  4  
  5  using static ARMeilleure.Instructions.InstEmitHelper;
  6  using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  7  
  8  namespace ARMeilleure.Instructions
  9  {
 10      static partial class InstEmit
 11      {
 12          public static void Bfm(ArmEmitterContext context)
 13          {
 14              OpCodeBfm op = (OpCodeBfm)context.CurrOp;
 15  
 16              Operand d = GetIntOrZR(context, op.Rd);
 17              Operand n = GetIntOrZR(context, op.Rn);
 18  
 19              Operand res;
 20  
 21              if (op.Pos < op.Shift)
 22              {
 23                  // BFI.
 24                  int shift = op.GetBitsCount() - op.Shift;
 25  
 26                  int width = op.Pos + 1;
 27  
 28                  long mask = (long)(ulong.MaxValue >> (64 - width));
 29  
 30                  res = context.ShiftLeft(context.BitwiseAnd(n, Const(n.Type, mask)), Const(shift));
 31  
 32                  res = context.BitwiseOr(res, context.BitwiseAnd(d, Const(d.Type, ~(mask << shift))));
 33              }
 34              else
 35              {
 36                  // BFXIL.
 37                  int shift = op.Shift;
 38  
 39                  int width = op.Pos - shift + 1;
 40  
 41                  long mask = (long)(ulong.MaxValue >> (64 - width));
 42  
 43                  res = context.BitwiseAnd(context.ShiftRightUI(n, Const(shift)), Const(n.Type, mask));
 44  
 45                  res = context.BitwiseOr(res, context.BitwiseAnd(d, Const(d.Type, ~mask)));
 46              }
 47  
 48              SetIntOrZR(context, op.Rd, res);
 49          }
 50  
 51          public static void Sbfm(ArmEmitterContext context)
 52          {
 53              OpCodeBfm op = (OpCodeBfm)context.CurrOp;
 54  
 55              int bitsCount = op.GetBitsCount();
 56  
 57              if (op.Pos + 1 == bitsCount)
 58              {
 59                  EmitSbfmShift(context);
 60              }
 61              else if (op.Pos < op.Shift)
 62              {
 63                  EmitSbfiz(context);
 64              }
 65              else if (op.Pos == 7 && op.Shift == 0)
 66              {
 67                  Operand n = GetIntOrZR(context, op.Rn);
 68  
 69                  SetIntOrZR(context, op.Rd, context.SignExtend8(n.Type, n));
 70              }
 71              else if (op.Pos == 15 && op.Shift == 0)
 72              {
 73                  Operand n = GetIntOrZR(context, op.Rn);
 74  
 75                  SetIntOrZR(context, op.Rd, context.SignExtend16(n.Type, n));
 76              }
 77              else if (op.Pos == 31 && op.Shift == 0)
 78              {
 79                  Operand n = GetIntOrZR(context, op.Rn);
 80  
 81                  SetIntOrZR(context, op.Rd, context.SignExtend32(n.Type, n));
 82              }
 83              else
 84              {
 85                  Operand res = GetIntOrZR(context, op.Rn);
 86  
 87                  res = context.ShiftLeft(res, Const(bitsCount - 1 - op.Pos));
 88                  res = context.ShiftRightSI(res, Const(bitsCount - 1));
 89                  res = context.BitwiseAnd(res, Const(res.Type, ~op.TMask));
 90  
 91                  Operand n2 = GetBfmN(context);
 92  
 93                  SetIntOrZR(context, op.Rd, context.BitwiseOr(res, n2));
 94              }
 95          }
 96  
 97          public static void Ubfm(ArmEmitterContext context)
 98          {
 99              OpCodeBfm op = (OpCodeBfm)context.CurrOp;
100  
101              if (op.Pos + 1 == op.GetBitsCount())
102              {
103                  EmitUbfmShift(context);
104              }
105              else if (op.Pos < op.Shift)
106              {
107                  EmitUbfiz(context);
108              }
109              else if (op.Pos + 1 == op.Shift)
110              {
111                  EmitBfmLsl(context);
112              }
113              else if (op.Pos == 7 && op.Shift == 0)
114              {
115                  Operand n = GetIntOrZR(context, op.Rn);
116  
117                  SetIntOrZR(context, op.Rd, context.BitwiseAnd(n, Const(n.Type, 0xff)));
118              }
119              else if (op.Pos == 15 && op.Shift == 0)
120              {
121                  Operand n = GetIntOrZR(context, op.Rn);
122  
123                  SetIntOrZR(context, op.Rd, context.BitwiseAnd(n, Const(n.Type, 0xffff)));
124              }
125              else
126              {
127                  SetIntOrZR(context, op.Rd, GetBfmN(context));
128              }
129          }
130  
131          private static void EmitSbfiz(ArmEmitterContext context) => EmitBfiz(context, signed: true);
132          private static void EmitUbfiz(ArmEmitterContext context) => EmitBfiz(context, signed: false);
133  
134          private static void EmitBfiz(ArmEmitterContext context, bool signed)
135          {
136              OpCodeBfm op = (OpCodeBfm)context.CurrOp;
137  
138              int width = op.Pos + 1;
139  
140              Operand res = GetIntOrZR(context, op.Rn);
141  
142              res = context.ShiftLeft(res, Const(op.GetBitsCount() - width));
143  
144              res = signed
145                  ? context.ShiftRightSI(res, Const(op.Shift - width))
146                  : context.ShiftRightUI(res, Const(op.Shift - width));
147  
148              SetIntOrZR(context, op.Rd, res);
149          }
150  
151          private static void EmitSbfmShift(ArmEmitterContext context)
152          {
153              EmitBfmShift(context, signed: true);
154          }
155  
156          private static void EmitUbfmShift(ArmEmitterContext context)
157          {
158              EmitBfmShift(context, signed: false);
159          }
160  
161          private static void EmitBfmShift(ArmEmitterContext context, bool signed)
162          {
163              OpCodeBfm op = (OpCodeBfm)context.CurrOp;
164  
165              Operand res = GetIntOrZR(context, op.Rn);
166  
167              res = signed
168                  ? context.ShiftRightSI(res, Const(op.Shift))
169                  : context.ShiftRightUI(res, Const(op.Shift));
170  
171              SetIntOrZR(context, op.Rd, res);
172          }
173  
174          private static void EmitBfmLsl(ArmEmitterContext context)
175          {
176              OpCodeBfm op = (OpCodeBfm)context.CurrOp;
177  
178              Operand res = GetIntOrZR(context, op.Rn);
179  
180              int shift = op.GetBitsCount() - op.Shift;
181  
182              SetIntOrZR(context, op.Rd, context.ShiftLeft(res, Const(shift)));
183          }
184  
185          private static Operand GetBfmN(ArmEmitterContext context)
186          {
187              OpCodeBfm op = (OpCodeBfm)context.CurrOp;
188  
189              Operand res = GetIntOrZR(context, op.Rn);
190  
191              long mask = op.WMask & op.TMask;
192  
193              return context.BitwiseAnd(context.RotateRight(res, Const(op.Shift)), Const(res.Type, mask));
194          }
195      }
196  }