InstEmitSimdHelper32.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.Translation;
  4. using System;
  5. using System.Diagnostics;
  6. using static ARMeilleure.Instructions.InstEmitHelper;
  7. using static ARMeilleure.Instructions.InstEmitSimdHelper;
  8. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  9. namespace ARMeilleure.Instructions
  10. {
  11. using Func1I = Func<Operand, Operand>;
  12. using Func2I = Func<Operand, Operand, Operand>;
  13. using Func3I = Func<Operand, Operand, Operand, Operand>;
  14. static class InstEmitSimdHelper32
  15. {
  16. public static (int, int) GetQuadwordAndSubindex(int index, RegisterSize size)
  17. {
  18. switch (size)
  19. {
  20. case RegisterSize.Simd128:
  21. return (index >> 1, 0);
  22. case RegisterSize.Simd64:
  23. case RegisterSize.Int64:
  24. return (index >> 1, index & 1);
  25. case RegisterSize.Int32:
  26. return (index >> 2, index & 3);
  27. }
  28. throw new ArgumentException("Unrecognized Vector Register Size.");
  29. }
  30. public static Operand ExtractScalar(ArmEmitterContext context, OperandType type, int reg)
  31. {
  32. Debug.Assert(type != OperandType.V128);
  33. if (type == OperandType.FP64 || type == OperandType.I64)
  34. {
  35. // From dreg.
  36. return context.VectorExtract(type, GetVecA32(reg >> 1), reg & 1);
  37. }
  38. else
  39. {
  40. // From sreg.
  41. return context.VectorExtract(type, GetVecA32(reg >> 2), reg & 3);
  42. }
  43. }
  44. public static void InsertScalar(ArmEmitterContext context, int reg, Operand value)
  45. {
  46. Debug.Assert(value.Type != OperandType.V128);
  47. Operand vec, insert;
  48. if (value.Type == OperandType.FP64 || value.Type == OperandType.I64)
  49. {
  50. // From dreg.
  51. vec = GetVecA32(reg >> 1);
  52. insert = context.VectorInsert(vec, value, reg & 1);
  53. }
  54. else
  55. {
  56. // From sreg.
  57. vec = GetVecA32(reg >> 2);
  58. insert = context.VectorInsert(vec, value, reg & 3);
  59. }
  60. context.Copy(vec, insert);
  61. }
  62. public static void EmitVectorImmUnaryOp32(ArmEmitterContext context, Func1I emit)
  63. {
  64. IOpCode32SimdImm op = (IOpCode32SimdImm)context.CurrOp;
  65. Operand imm = Const(op.Immediate);
  66. int elems = op.Elems;
  67. (int index, int subIndex) = GetQuadwordAndSubindex(op.Vd, op.RegisterSize);
  68. Operand vec = GetVecA32(index);
  69. Operand res = vec;
  70. for (int item = 0; item < elems; item++)
  71. {
  72. res = EmitVectorInsert(context, res, emit(imm), item + subIndex * elems, op.Size);
  73. }
  74. context.Copy(vec, res);
  75. }
  76. public static void EmitScalarUnaryOpF32(ArmEmitterContext context, Func1I emit)
  77. {
  78. OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
  79. OperandType type = (op.Size & 1) != 0 ? OperandType.FP64 : OperandType.FP32;
  80. Operand m = ExtractScalar(context, type, op.Vm);
  81. InsertScalar(context, op.Vd, emit(m));
  82. }
  83. public static void EmitScalarBinaryOpF32(ArmEmitterContext context, Func2I emit)
  84. {
  85. OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
  86. OperandType type = (op.Size & 1) != 0 ? OperandType.FP64 : OperandType.FP32;
  87. Operand n = ExtractScalar(context, type, op.Vn);
  88. Operand m = ExtractScalar(context, type, op.Vm);
  89. InsertScalar(context, op.Vd, emit(n, m));
  90. }
  91. public static void EmitScalarBinaryOpI32(ArmEmitterContext context, Func2I emit)
  92. {
  93. OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
  94. OperandType type = (op.Size & 1) != 0 ? OperandType.I64 : OperandType.I32;
  95. if (op.Size < 2)
  96. {
  97. throw new NotSupportedException("Cannot perform a scalar SIMD operation on integers smaller than 32 bits.");
  98. }
  99. Operand n = ExtractScalar(context, type, op.Vn);
  100. Operand m = ExtractScalar(context, type, op.Vm);
  101. InsertScalar(context, op.Vd, emit(n, m));
  102. }
  103. public static void EmitScalarTernaryOpF32(ArmEmitterContext context, Func3I emit)
  104. {
  105. OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
  106. OperandType type = (op.Size & 1) != 0 ? OperandType.FP64 : OperandType.FP32;
  107. Operand a = ExtractScalar(context, type, op.Vd);
  108. Operand n = ExtractScalar(context, type, op.Vn);
  109. Operand m = ExtractScalar(context, type, op.Vm);
  110. InsertScalar(context, op.Vd, emit(a, n, m));
  111. }
  112. public static void EmitVectorUnaryOpF32(ArmEmitterContext context, Func1I emit)
  113. {
  114. OpCode32Simd op = (OpCode32Simd)context.CurrOp;
  115. int sizeF = op.Size & 1;
  116. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  117. int elems = op.GetBytesCount() >> sizeF + 2;
  118. Operand res = GetVecA32(op.Qd);
  119. for (int index = 0; index < elems; index++)
  120. {
  121. Operand me = context.VectorExtract(type, GetVecA32(op.Qm), op.Fm + index);
  122. res = context.VectorInsert(res, emit(me), op.Fd + index);
  123. }
  124. context.Copy(GetVecA32(op.Qd), res);
  125. }
  126. public static void EmitVectorBinaryOpF32(ArmEmitterContext context, Func2I emit)
  127. {
  128. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  129. int sizeF = op.Size & 1;
  130. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  131. int elems = op.GetBytesCount() >> (sizeF + 2);
  132. Operand res = GetVecA32(op.Qd);
  133. for (int index = 0; index < elems; index++)
  134. {
  135. Operand ne = context.VectorExtract(type, GetVecA32(op.Qn), op.Fn + index);
  136. Operand me = context.VectorExtract(type, GetVecA32(op.Qm), op.Fm + index);
  137. res = context.VectorInsert(res, emit(ne, me), op.Fd + index);
  138. }
  139. context.Copy(GetVecA32(op.Qd), res);
  140. }
  141. public static void EmitVectorTernaryOpF32(ArmEmitterContext context, Func3I emit)
  142. {
  143. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  144. int sizeF = op.Size & 1;
  145. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  146. int elems = op.GetBytesCount() >> sizeF + 2;
  147. Operand res = GetVecA32(op.Qd);
  148. for (int index = 0; index < elems; index++)
  149. {
  150. Operand de = context.VectorExtract(type, GetVecA32(op.Qd), op.Fd + index);
  151. Operand ne = context.VectorExtract(type, GetVecA32(op.Qn), op.Fn + index);
  152. Operand me = context.VectorExtract(type, GetVecA32(op.Qm), op.Fm + index);
  153. res = context.VectorInsert(res, emit(de, ne, me), op.Fd + index);
  154. }
  155. context.Copy(GetVecA32(op.Qd), res);
  156. }
  157. // Integer
  158. public static void EmitVectorUnaryOpI32(ArmEmitterContext context, Func1I emit, bool signed)
  159. {
  160. OpCode32Simd op = (OpCode32Simd)context.CurrOp;
  161. Operand res = GetVecA32(op.Qd);
  162. int elems = op.GetBytesCount() >> op.Size;
  163. for (int index = 0; index < elems; index++)
  164. {
  165. Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, signed);
  166. res = EmitVectorInsert(context, res, emit(me), op.Id + index, op.Size);
  167. }
  168. context.Copy(GetVecA32(op.Qd), res);
  169. }
  170. public static void EmitVectorBinaryOpI32(ArmEmitterContext context, Func2I emit, bool signed)
  171. {
  172. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  173. Operand res = GetVecA32(op.Qd);
  174. int elems = op.GetBytesCount() >> op.Size;
  175. for (int index = 0; index < elems; index++)
  176. {
  177. Operand ne = EmitVectorExtract32(context, op.Qn, op.In + index, op.Size, signed);
  178. Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, signed);
  179. res = EmitVectorInsert(context, res, emit(ne, me), op.Id + index, op.Size);
  180. }
  181. context.Copy(GetVecA32(op.Qd), res);
  182. }
  183. public static void EmitVectorTernaryOpI32(ArmEmitterContext context, Func3I emit, bool signed)
  184. {
  185. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  186. Operand res = GetVecA32(op.Qd);
  187. int elems = op.GetBytesCount() >> op.Size;
  188. for (int index = 0; index < elems; index++)
  189. {
  190. Operand de = EmitVectorExtract32(context, op.Qd, op.Id + index, op.Size, signed);
  191. Operand ne = EmitVectorExtract32(context, op.Qn, op.In + index, op.Size, signed);
  192. Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, signed);
  193. res = EmitVectorInsert(context, res, emit(de, ne, me), op.Id + index, op.Size);
  194. }
  195. context.Copy(GetVecA32(op.Qd), res);
  196. }
  197. public static void EmitVectorUnaryOpSx32(ArmEmitterContext context, Func1I emit)
  198. {
  199. EmitVectorUnaryOpI32(context, emit, true);
  200. }
  201. public static void EmitVectorBinaryOpSx32(ArmEmitterContext context, Func2I emit)
  202. {
  203. EmitVectorBinaryOpI32(context, emit, true);
  204. }
  205. public static void EmitVectorTernaryOpSx32(ArmEmitterContext context, Func3I emit)
  206. {
  207. EmitVectorTernaryOpI32(context, emit, true);
  208. }
  209. public static void EmitVectorUnaryOpZx32(ArmEmitterContext context, Func1I emit)
  210. {
  211. EmitVectorUnaryOpI32(context, emit, false);
  212. }
  213. public static void EmitVectorBinaryOpZx32(ArmEmitterContext context, Func2I emit)
  214. {
  215. EmitVectorBinaryOpI32(context, emit, false);
  216. }
  217. public static void EmitVectorTernaryOpZx32(ArmEmitterContext context, Func3I emit)
  218. {
  219. EmitVectorTernaryOpI32(context, emit, false);
  220. }
  221. // Vector by scalar
  222. public static void EmitVectorByScalarOpF32(ArmEmitterContext context, Func2I emit)
  223. {
  224. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  225. int sizeF = op.Size & 1;
  226. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  227. int elems = op.GetBytesCount() >> sizeF + 2;
  228. Operand m = ExtractScalar(context, type, op.Vm);
  229. Operand res = GetVecA32(op.Qd);
  230. for (int index = 0; index < elems; index++)
  231. {
  232. Operand ne = context.VectorExtract(type, GetVecA32(op.Qn), op.Fn + index);
  233. res = context.VectorInsert(res, emit(ne, m), op.Fd + index);
  234. }
  235. context.Copy(GetVecA32(op.Qd), res);
  236. }
  237. public static void EmitVectorByScalarOpI32(ArmEmitterContext context, Func2I emit, bool signed)
  238. {
  239. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  240. Operand m = EmitVectorExtract32(context, op.Vm >> (4 - op.Size), op.Vm & ((1 << (4 - op.Size)) - 1), op.Size, signed);
  241. Operand res = GetVecA32(op.Qd);
  242. int elems = op.GetBytesCount() >> op.Size;
  243. for (int index = 0; index < elems; index++)
  244. {
  245. Operand ne = EmitVectorExtract32(context, op.Qn, op.In + index, op.Size, signed);
  246. res = EmitVectorInsert(context, res, emit(ne, m), op.In + index, op.Size);
  247. }
  248. context.Copy(GetVecA32(op.Qd), res);
  249. }
  250. public static void EmitVectorsByScalarOpF32(ArmEmitterContext context, Func3I emit)
  251. {
  252. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  253. int sizeF = op.Size & 1;
  254. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  255. int elems = op.GetBytesCount() >> sizeF + 2;
  256. Operand m = ExtractScalar(context, type, op.Vm);
  257. Operand res = GetVecA32(op.Qd);
  258. for (int index = 0; index < elems; index++)
  259. {
  260. Operand de = context.VectorExtract(type, GetVecA32(op.Qd), op.Fd + index);
  261. Operand ne = context.VectorExtract(type, GetVecA32(op.Qn), op.Fn + index);
  262. res = context.VectorInsert(res, emit(de, ne, m), op.Fd + index);
  263. }
  264. context.Copy(GetVecA32(op.Qd), res);
  265. }
  266. public static void EmitVectorsByScalarOpI32(ArmEmitterContext context, Func3I emit, bool signed)
  267. {
  268. OpCode32SimdRegElem op = (OpCode32SimdRegElem)context.CurrOp;
  269. Operand m = EmitVectorExtract32(context, op.Vm >> (4 - op.Size), op.Vm & ((1 << (4 - op.Size)) - 1), op.Size, signed);
  270. Operand res = GetVecA32(op.Qd);
  271. int elems = op.GetBytesCount() >> op.Size;
  272. for (int index = 0; index < elems; index++)
  273. {
  274. Operand de = EmitVectorExtract32(context, op.Qd, op.Id + index, op.Size, signed);
  275. Operand ne = EmitVectorExtract32(context, op.Qn, op.In + index, op.Size, signed);
  276. res = EmitVectorInsert(context, res, emit(de, ne, m), op.Id + index, op.Size);
  277. }
  278. context.Copy(GetVecA32(op.Qd), res);
  279. }
  280. // Pairwise
  281. public static void EmitVectorPairwiseOpF32(ArmEmitterContext context, Func2I emit)
  282. {
  283. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  284. int sizeF = op.Size & 1;
  285. OperandType type = sizeF != 0 ? OperandType.FP64 : OperandType.FP32;
  286. int elems = op.GetBytesCount() >> (sizeF + 2);
  287. int pairs = elems >> 1;
  288. Operand res = GetVecA32(op.Qd);
  289. Operand mvec = GetVecA32(op.Qm);
  290. Operand nvec = GetVecA32(op.Qn);
  291. for (int index = 0; index < pairs; index++)
  292. {
  293. int pairIndex = index << 1;
  294. Operand n1 = context.VectorExtract(type, nvec, op.Fn + pairIndex);
  295. Operand n2 = context.VectorExtract(type, nvec, op.Fn + pairIndex + 1);
  296. res = context.VectorInsert(res, emit(n1, n2), op.Fd + index);
  297. Operand m1 = context.VectorExtract(type, mvec, op.Fm + pairIndex);
  298. Operand m2 = context.VectorExtract(type, mvec, op.Fm + pairIndex + 1);
  299. res = context.VectorInsert(res, emit(m1, m2), op.Fd + index + pairs);
  300. }
  301. context.Copy(GetVecA32(op.Qd), res);
  302. }
  303. public static void EmitVectorPairwiseOpI32(ArmEmitterContext context, Func2I emit, bool signed)
  304. {
  305. OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
  306. int elems = op.GetBytesCount() >> op.Size;
  307. int pairs = elems >> 1;
  308. Operand res = GetVecA32(op.Qd);
  309. for (int index = 0; index < pairs; index++)
  310. {
  311. int pairIndex = index << 1;
  312. Operand n1 = EmitVectorExtract32(context, op.Qn, op.In + pairIndex, op.Size, signed);
  313. Operand n2 = EmitVectorExtract32(context, op.Qn, op.In + pairIndex + 1, op.Size, signed);
  314. Operand m1 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex, op.Size, signed);
  315. Operand m2 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex + 1, op.Size, signed);
  316. res = EmitVectorInsert(context, res, emit(n1, n2), op.Id + index, op.Size);
  317. res = EmitVectorInsert(context, res, emit(m1, m2), op.Id + index + pairs, op.Size);
  318. }
  319. context.Copy(GetVecA32(op.Qd), res);
  320. }
  321. // Narrow
  322. public static void EmitVectorUnaryNarrowOp32(ArmEmitterContext context, Func1I emit)
  323. {
  324. OpCode32Simd op = (OpCode32Simd)context.CurrOp;
  325. int elems = 8 >> op.Size; // Size contains the target element size. (for when it becomes a doubleword)
  326. Operand res = GetVecA32(op.Qd);
  327. int id = (op.Vd & 1) << (3 - op.Size); // Target doubleword base.
  328. for (int index = 0; index < elems; index++)
  329. {
  330. Operand m = EmitVectorExtract32(context, op.Qm, index, op.Size + 1, false);
  331. res = EmitVectorInsert(context, res, emit(m), id + index, op.Size);
  332. }
  333. context.Copy(GetVecA32(op.Qd), res);
  334. }
  335. // Generic Functions
  336. public static Operand EmitSoftFloatCallDefaultFpscr(
  337. ArmEmitterContext context,
  338. _F32_F32_Bool f32,
  339. _F64_F64_Bool f64,
  340. params Operand[] callArgs)
  341. {
  342. IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
  343. Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
  344. Array.Resize(ref callArgs, callArgs.Length + 1);
  345. callArgs[callArgs.Length - 1] = Const(1);
  346. return context.Call(dlg, callArgs);
  347. }
  348. public static Operand EmitSoftFloatCallDefaultFpscr(
  349. ArmEmitterContext context,
  350. _F32_F32_F32_Bool f32,
  351. _F64_F64_F64_Bool f64,
  352. params Operand[] callArgs)
  353. {
  354. IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
  355. Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
  356. Array.Resize(ref callArgs, callArgs.Length + 1);
  357. callArgs[callArgs.Length - 1] = Const(1);
  358. return context.Call(dlg, callArgs);
  359. }
  360. public static Operand EmitSoftFloatCallDefaultFpscr(
  361. ArmEmitterContext context,
  362. _F32_F32_F32_F32_Bool f32,
  363. _F64_F64_F64_F64_Bool f64,
  364. params Operand[] callArgs)
  365. {
  366. IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
  367. Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
  368. Array.Resize(ref callArgs, callArgs.Length + 1);
  369. callArgs[callArgs.Length - 1] = Const(1);
  370. return context.Call(dlg, callArgs);
  371. }
  372. public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size)
  373. {
  374. return EmitVectorExtract32(context, reg, index, size, true);
  375. }
  376. public static Operand EmitVectorExtractZx32(ArmEmitterContext context, int reg, int index, int size)
  377. {
  378. return EmitVectorExtract32(context, reg, index, size, false);
  379. }
  380. public static Operand EmitVectorExtract32(ArmEmitterContext context, int reg, int index, int size, bool signed)
  381. {
  382. ThrowIfInvalid(index, size);
  383. Operand res = null;
  384. switch (size)
  385. {
  386. case 0:
  387. res = context.VectorExtract8(GetVec(reg), index);
  388. break;
  389. case 1:
  390. res = context.VectorExtract16(GetVec(reg), index);
  391. break;
  392. case 2:
  393. res = context.VectorExtract(OperandType.I32, GetVec(reg), index);
  394. break;
  395. case 3:
  396. res = context.VectorExtract(OperandType.I64, GetVec(reg), index);
  397. break;
  398. }
  399. if (signed)
  400. {
  401. switch (size)
  402. {
  403. case 0: res = context.SignExtend8(OperandType.I32, res); break;
  404. case 1: res = context.SignExtend16(OperandType.I32, res); break;
  405. }
  406. }
  407. else
  408. {
  409. switch (size)
  410. {
  411. case 0: res = context.ZeroExtend8(OperandType.I32, res); break;
  412. case 1: res = context.ZeroExtend16(OperandType.I32, res); break;
  413. }
  414. }
  415. return res;
  416. }
  417. }
  418. }