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