/ src / ARMeilleure / Instructions / InstEmitSimdMemory.cs
InstEmitSimdMemory.cs
  1  using ARMeilleure.Decoders;
  2  using ARMeilleure.IntermediateRepresentation;
  3  using ARMeilleure.State;
  4  using ARMeilleure.Translation;
  5  using System.Diagnostics;
  6  
  7  using static ARMeilleure.Instructions.InstEmitHelper;
  8  using static ARMeilleure.Instructions.InstEmitMemoryHelper;
  9  using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 10  
 11  namespace ARMeilleure.Instructions
 12  {
 13      static partial class InstEmit
 14      {
 15          public static void Ld__Vms(ArmEmitterContext context)
 16          {
 17              EmitSimdMemMs(context, isLoad: true);
 18          }
 19  
 20          public static void Ld__Vss(ArmEmitterContext context)
 21          {
 22              EmitSimdMemSs(context, isLoad: true);
 23          }
 24  
 25          public static void St__Vms(ArmEmitterContext context)
 26          {
 27              EmitSimdMemMs(context, isLoad: false);
 28          }
 29  
 30          public static void St__Vss(ArmEmitterContext context)
 31          {
 32              EmitSimdMemSs(context, isLoad: false);
 33          }
 34  
 35          private static void EmitSimdMemMs(ArmEmitterContext context, bool isLoad)
 36          {
 37              OpCodeSimdMemMs op = (OpCodeSimdMemMs)context.CurrOp;
 38  
 39              Operand n = GetIntOrSP(context, op.Rn);
 40  
 41              long offset = 0;
 42  
 43  #pragma warning disable IDE0055 // Disable formatting
 44              for (int rep   = 0; rep   < op.Reps;   rep++)
 45              for (int elem  = 0; elem  < op.Elems;  elem++)
 46              for (int sElem = 0; sElem < op.SElems; sElem++)
 47              {
 48                  int rtt = (op.Rt + rep + sElem) & 0x1f;
 49  
 50                  Operand tt = GetVec(rtt);
 51  
 52                  Operand address = context.Add(n, Const(offset));
 53  
 54                  if (isLoad)
 55                  {
 56                      EmitLoadSimd(context, address, tt, rtt, elem, op.Size);
 57  
 58                      if (op.RegisterSize == RegisterSize.Simd64 && elem == op.Elems - 1)
 59                      {
 60                          context.Copy(tt, context.VectorZeroUpper64(tt));
 61                      }
 62                  }
 63                  else
 64                  {
 65                      EmitStoreSimd(context, address, rtt, elem, op.Size);
 66                  }
 67  
 68                  offset += 1 << op.Size;
 69              }
 70  #pragma warning restore IDE0055
 71  
 72              if (op.WBack)
 73              {
 74                  EmitSimdMemWBack(context, offset);
 75              }
 76          }
 77  
 78          private static void EmitSimdMemSs(ArmEmitterContext context, bool isLoad)
 79          {
 80              OpCodeSimdMemSs op = (OpCodeSimdMemSs)context.CurrOp;
 81  
 82              Operand n = GetIntOrSP(context, op.Rn);
 83  
 84              long offset = 0;
 85  
 86              if (op.Replicate)
 87              {
 88                  // Only loads uses the replicate mode.
 89                  Debug.Assert(isLoad, "Replicate mode is not valid for stores.");
 90  
 91                  int elems = op.GetBytesCount() >> op.Size;
 92  
 93                  for (int sElem = 0; sElem < op.SElems; sElem++)
 94                  {
 95                      int rt = (op.Rt + sElem) & 0x1f;
 96  
 97                      Operand t = GetVec(rt);
 98  
 99                      Operand address = context.Add(n, Const(offset));
100  
101                      for (int index = 0; index < elems; index++)
102                      {
103                          EmitLoadSimd(context, address, t, rt, index, op.Size);
104                      }
105  
106                      if (op.RegisterSize == RegisterSize.Simd64)
107                      {
108                          context.Copy(t, context.VectorZeroUpper64(t));
109                      }
110  
111                      offset += 1 << op.Size;
112                  }
113              }
114              else
115              {
116                  for (int sElem = 0; sElem < op.SElems; sElem++)
117                  {
118                      int rt = (op.Rt + sElem) & 0x1f;
119  
120                      Operand t = GetVec(rt);
121  
122                      Operand address = context.Add(n, Const(offset));
123  
124                      if (isLoad)
125                      {
126                          EmitLoadSimd(context, address, t, rt, op.Index, op.Size);
127                      }
128                      else
129                      {
130                          EmitStoreSimd(context, address, rt, op.Index, op.Size);
131                      }
132  
133                      offset += 1 << op.Size;
134                  }
135              }
136  
137              if (op.WBack)
138              {
139                  EmitSimdMemWBack(context, offset);
140              }
141          }
142  
143          private static void EmitSimdMemWBack(ArmEmitterContext context, long offset)
144          {
145              OpCodeMemReg op = (OpCodeMemReg)context.CurrOp;
146  
147              Operand n = GetIntOrSP(context, op.Rn);
148              Operand m;
149  
150              if (op.Rm != RegisterAlias.Zr)
151              {
152                  m = GetIntOrZR(context, op.Rm);
153              }
154              else
155              {
156                  m = Const(offset);
157              }
158  
159              context.Copy(n, context.Add(n, m));
160          }
161      }
162  }