InstEmitSimdMemory32.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.State; 4 using ARMeilleure.Translation; 5 6 using static ARMeilleure.Instructions.InstEmitHelper; 7 using static ARMeilleure.Instructions.InstEmitMemoryHelper; 8 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 9 10 namespace ARMeilleure.Instructions 11 { 12 static partial class InstEmit32 13 { 14 public static void Vld1(ArmEmitterContext context) 15 { 16 EmitVStoreOrLoadN(context, 1, true); 17 } 18 19 public static void Vld2(ArmEmitterContext context) 20 { 21 EmitVStoreOrLoadN(context, 2, true); 22 } 23 24 public static void Vld3(ArmEmitterContext context) 25 { 26 EmitVStoreOrLoadN(context, 3, true); 27 } 28 29 public static void Vld4(ArmEmitterContext context) 30 { 31 EmitVStoreOrLoadN(context, 4, true); 32 } 33 34 public static void Vst1(ArmEmitterContext context) 35 { 36 EmitVStoreOrLoadN(context, 1, false); 37 } 38 39 public static void Vst2(ArmEmitterContext context) 40 { 41 EmitVStoreOrLoadN(context, 2, false); 42 } 43 44 public static void Vst3(ArmEmitterContext context) 45 { 46 EmitVStoreOrLoadN(context, 3, false); 47 } 48 49 public static void Vst4(ArmEmitterContext context) 50 { 51 EmitVStoreOrLoadN(context, 4, false); 52 } 53 54 public static void EmitVStoreOrLoadN(ArmEmitterContext context, int count, bool load) 55 { 56 if (context.CurrOp is OpCode32SimdMemSingle) 57 { 58 OpCode32SimdMemSingle op = (OpCode32SimdMemSingle)context.CurrOp; 59 60 int eBytes = 1 << op.Size; 61 62 Operand n = context.Copy(GetIntA32(context, op.Rn)); 63 64 // TODO: Check alignment. 65 int offset = 0; 66 int d = op.Vd; 67 68 for (int i = 0; i < count; i++) 69 { 70 // Accesses an element from a double simd register. 71 Operand address = context.Add(n, Const(offset)); 72 if (eBytes == 8) 73 { 74 if (load) 75 { 76 EmitDVectorLoad(context, address, d); 77 } 78 else 79 { 80 EmitDVectorStore(context, address, d); 81 } 82 } 83 else 84 { 85 int index = ((d & 1) << (3 - op.Size)) + op.Index; 86 if (load) 87 { 88 if (op.Replicate) 89 { 90 var regs = (count > 1) ? 1 : op.Increment; 91 for (int reg = 0; reg < regs; reg++) 92 { 93 int dreg = reg + d; 94 int rIndex = ((dreg & 1) << (3 - op.Size)); 95 int limit = rIndex + (1 << (3 - op.Size)); 96 97 while (rIndex < limit) 98 { 99 EmitLoadSimd(context, address, GetVecA32(dreg >> 1), dreg >> 1, rIndex++, op.Size); 100 } 101 } 102 } 103 else 104 { 105 EmitLoadSimd(context, address, GetVecA32(d >> 1), d >> 1, index, op.Size); 106 } 107 } 108 else 109 { 110 EmitStoreSimd(context, address, d >> 1, index, op.Size); 111 } 112 } 113 offset += eBytes; 114 d += op.Increment; 115 } 116 117 if (op.WBack) 118 { 119 if (op.RegisterIndex) 120 { 121 Operand m = GetIntA32(context, op.Rm); 122 SetIntA32(context, op.Rn, context.Add(n, m)); 123 } 124 else 125 { 126 SetIntA32(context, op.Rn, context.Add(n, Const(count * eBytes))); 127 } 128 } 129 } 130 else 131 { 132 OpCode32SimdMemPair op = (OpCode32SimdMemPair)context.CurrOp; 133 134 int increment = count > 1 ? op.Increment : 1; 135 int eBytes = 1 << op.Size; 136 137 Operand n = context.Copy(GetIntA32(context, op.Rn)); 138 int offset = 0; 139 int d = op.Vd; 140 141 for (int reg = 0; reg < op.Regs; reg++) 142 { 143 for (int elem = 0; elem < op.Elems; elem++) 144 { 145 int elemD = d + reg; 146 for (int i = 0; i < count; i++) 147 { 148 // Accesses an element from a double simd register, 149 // add ebytes for each element. 150 Operand address = context.Add(n, Const(offset)); 151 int index = ((elemD & 1) << (3 - op.Size)) + elem; 152 if (eBytes == 8) 153 { 154 if (load) 155 { 156 EmitDVectorLoad(context, address, elemD); 157 } 158 else 159 { 160 EmitDVectorStore(context, address, elemD); 161 } 162 } 163 else 164 { 165 if (load) 166 { 167 EmitLoadSimd(context, address, GetVecA32(elemD >> 1), elemD >> 1, index, op.Size); 168 } 169 else 170 { 171 EmitStoreSimd(context, address, elemD >> 1, index, op.Size); 172 } 173 } 174 175 offset += eBytes; 176 elemD += increment; 177 } 178 } 179 } 180 181 if (op.WBack) 182 { 183 if (op.RegisterIndex) 184 { 185 Operand m = GetIntA32(context, op.Rm); 186 SetIntA32(context, op.Rn, context.Add(n, m)); 187 } 188 else 189 { 190 SetIntA32(context, op.Rn, context.Add(n, Const(count * 8 * op.Regs))); 191 } 192 } 193 } 194 } 195 196 public static void Vldm(ArmEmitterContext context) 197 { 198 OpCode32SimdMemMult op = (OpCode32SimdMemMult)context.CurrOp; 199 200 Operand n = context.Copy(GetIntA32(context, op.Rn)); 201 202 Operand baseAddress = context.Add(n, Const(op.Offset)); 203 204 bool writeBack = op.PostOffset != 0; 205 206 if (writeBack) 207 { 208 SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset))); 209 } 210 211 int range = op.RegisterRange; 212 213 int sReg = (op.DoubleWidth) ? (op.Vd << 1) : op.Vd; 214 int offset = 0; 215 int byteSize = 4; 216 217 for (int num = 0; num < range; num++, sReg++) 218 { 219 Operand address = context.Add(baseAddress, Const(offset)); 220 Operand vec = GetVecA32(sReg >> 2); 221 222 EmitLoadSimd(context, address, vec, sReg >> 2, sReg & 3, WordSizeLog2); 223 offset += byteSize; 224 } 225 } 226 227 public static void Vstm(ArmEmitterContext context) 228 { 229 OpCode32SimdMemMult op = (OpCode32SimdMemMult)context.CurrOp; 230 231 Operand n = context.Copy(GetIntA32(context, op.Rn)); 232 233 Operand baseAddress = context.Add(n, Const(op.Offset)); 234 235 bool writeBack = op.PostOffset != 0; 236 237 if (writeBack) 238 { 239 SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset))); 240 } 241 242 int offset = 0; 243 244 int range = op.RegisterRange; 245 int sReg = (op.DoubleWidth) ? (op.Vd << 1) : op.Vd; 246 int byteSize = 4; 247 248 for (int num = 0; num < range; num++, sReg++) 249 { 250 Operand address = context.Add(baseAddress, Const(offset)); 251 252 EmitStoreSimd(context, address, sReg >> 2, sReg & 3, WordSizeLog2); 253 254 offset += byteSize; 255 } 256 } 257 258 public static void Vldr(ArmEmitterContext context) 259 { 260 EmitVLoadOrStore(context, AccessType.Load); 261 } 262 263 public static void Vstr(ArmEmitterContext context) 264 { 265 EmitVLoadOrStore(context, AccessType.Store); 266 } 267 268 private static void EmitDVectorStore(ArmEmitterContext context, Operand address, int vecD) 269 { 270 int vecQ = vecD >> 1; 271 int vecSElem = (vecD & 1) << 1; 272 Operand lblBigEndian = Label(); 273 Operand lblEnd = Label(); 274 275 context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); 276 277 EmitStoreSimd(context, address, vecQ, vecSElem, WordSizeLog2); 278 EmitStoreSimd(context, context.Add(address, Const(4)), vecQ, vecSElem | 1, WordSizeLog2); 279 280 context.Branch(lblEnd); 281 282 context.MarkLabel(lblBigEndian); 283 284 EmitStoreSimd(context, address, vecQ, vecSElem | 1, WordSizeLog2); 285 EmitStoreSimd(context, context.Add(address, Const(4)), vecQ, vecSElem, WordSizeLog2); 286 287 context.MarkLabel(lblEnd); 288 } 289 290 private static void EmitDVectorLoad(ArmEmitterContext context, Operand address, int vecD) 291 { 292 int vecQ = vecD >> 1; 293 int vecSElem = (vecD & 1) << 1; 294 Operand vec = GetVecA32(vecQ); 295 296 Operand lblBigEndian = Label(); 297 Operand lblEnd = Label(); 298 299 context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); 300 301 EmitLoadSimd(context, address, vec, vecQ, vecSElem, WordSizeLog2); 302 EmitLoadSimd(context, context.Add(address, Const(4)), vec, vecQ, vecSElem | 1, WordSizeLog2); 303 304 context.Branch(lblEnd); 305 306 context.MarkLabel(lblBigEndian); 307 308 EmitLoadSimd(context, address, vec, vecQ, vecSElem | 1, WordSizeLog2); 309 EmitLoadSimd(context, context.Add(address, Const(4)), vec, vecQ, vecSElem, WordSizeLog2); 310 311 context.MarkLabel(lblEnd); 312 } 313 314 private static void EmitVLoadOrStore(ArmEmitterContext context, AccessType accType) 315 { 316 OpCode32SimdMemImm op = (OpCode32SimdMemImm)context.CurrOp; 317 318 Operand n = context.Copy(GetIntA32(context, op.Rn)); 319 Operand m = GetMemM(context, setCarry: false); 320 321 Operand address = op.Add 322 ? context.Add(n, m) 323 : context.Subtract(n, m); 324 325 int size = op.Size; 326 327 if ((accType & AccessType.Load) != 0) 328 { 329 if (size == DWordSizeLog2) 330 { 331 EmitDVectorLoad(context, address, op.Vd); 332 } 333 else 334 { 335 Operand vec = GetVecA32(op.Vd >> 2); 336 EmitLoadSimd(context, address, vec, op.Vd >> 2, (op.Vd & 3) << (2 - size), size); 337 } 338 } 339 else 340 { 341 if (size == DWordSizeLog2) 342 { 343 EmitDVectorStore(context, address, op.Vd); 344 } 345 else 346 { 347 EmitStoreSimd(context, address, op.Vd >> 2, (op.Vd & 3) << (2 - size), size); 348 } 349 } 350 } 351 } 352 }