InstEmitSimdMove32.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.Translation;
  4. using static ARMeilleure.Instructions.InstEmitHelper;
  5. using static ARMeilleure.Instructions.InstEmitSimdHelper;
  6. using static ARMeilleure.Instructions.InstEmitSimdHelper32;
  7. using static ARMeilleure.IntermediateRepresentation.OperandHelper;
  8. namespace ARMeilleure.Instructions
  9. {
  10. static partial class InstEmit32
  11. {
  12. public static void Vmov_I(ArmEmitterContext context)
  13. {
  14. EmitVectorImmUnaryOp32(context, (op1) => op1);
  15. }
  16. public static void Vmvn_I(ArmEmitterContext context)
  17. {
  18. EmitVectorImmUnaryOp32(context, (op1) => context.BitwiseExclusiveOr(op1, op1));
  19. }
  20. public static void Vmov_GS(ArmEmitterContext context)
  21. {
  22. OpCode32SimdMovGp op = (OpCode32SimdMovGp)context.CurrOp;
  23. Operand vec = GetVecA32(op.Vn >> 2);
  24. if (op.Op == 1)
  25. {
  26. // To general purpose.
  27. Operand value = context.VectorExtract(OperandType.I32, vec, op.Vn & 0x3);
  28. SetIntA32(context, op.Rt, value);
  29. }
  30. else
  31. {
  32. // From general purpose.
  33. Operand value = GetIntA32(context, op.Rt);
  34. context.Copy(vec, context.VectorInsert(vec, value, op.Vn & 0x3));
  35. }
  36. }
  37. public static void Vmov_G1(ArmEmitterContext context)
  38. {
  39. OpCode32SimdMovGpElem op = (OpCode32SimdMovGpElem)context.CurrOp;
  40. int index = op.Index + ((op.Vd & 1) << (3 - op.Size));
  41. if (op.Op == 1)
  42. {
  43. // To general purpose.
  44. Operand value = EmitVectorExtract32(context, op.Vd >> 1, index, op.Size, !op.U);
  45. SetIntA32(context, op.Rt, value);
  46. }
  47. else
  48. {
  49. // From general purpose.
  50. Operand vec = GetVecA32(op.Vd >> 1);
  51. Operand value = GetIntA32(context, op.Rt);
  52. context.Copy(vec, EmitVectorInsert(context, vec, value, index, op.Size));
  53. }
  54. }
  55. public static void Vmov_G2(ArmEmitterContext context)
  56. {
  57. OpCode32SimdMovGpDouble op = (OpCode32SimdMovGpDouble)context.CurrOp;
  58. Operand vec = GetVecA32(op.Vm >> 2);
  59. int vm1 = op.Vm + 1;
  60. bool sameOwnerVec = (op.Vm >> 2) == (vm1 >> 2);
  61. Operand vec2 = sameOwnerVec ? vec : GetVecA32(vm1 >> 2);
  62. if (op.Op == 1)
  63. {
  64. // To general purpose.
  65. Operand lowValue = context.VectorExtract(OperandType.I32, vec, op.Vm & 3);
  66. SetIntA32(context, op.Rt, lowValue);
  67. Operand highValue = context.VectorExtract(OperandType.I32, vec2, vm1 & 3);
  68. SetIntA32(context, op.Rt2, highValue);
  69. }
  70. else
  71. {
  72. // From general purpose.
  73. Operand lowValue = GetIntA32(context, op.Rt);
  74. Operand resultVec = context.VectorInsert(vec, lowValue, op.Vm & 3);
  75. Operand highValue = GetIntA32(context, op.Rt2);
  76. if (sameOwnerVec)
  77. {
  78. context.Copy(vec, context.VectorInsert(resultVec, highValue, vm1 & 3));
  79. }
  80. else
  81. {
  82. context.Copy(vec, resultVec);
  83. context.Copy(vec2, context.VectorInsert(vec2, highValue, vm1 & 3));
  84. }
  85. }
  86. }
  87. public static void Vmov_GD(ArmEmitterContext context)
  88. {
  89. OpCode32SimdMovGpDouble op = (OpCode32SimdMovGpDouble)context.CurrOp;
  90. Operand vec = GetVecA32(op.Vm >> 1);
  91. if (op.Op == 1)
  92. {
  93. // To general purpose.
  94. Operand value = context.VectorExtract(OperandType.I64, vec, op.Vm & 1);
  95. SetIntA32(context, op.Rt, context.ConvertI64ToI32(value));
  96. SetIntA32(context, op.Rt2, context.ConvertI64ToI32(context.ShiftRightUI(value, Const(32))));
  97. }
  98. else
  99. {
  100. // From general purpose.
  101. Operand lowValue = GetIntA32(context, op.Rt);
  102. Operand highValue = GetIntA32(context, op.Rt2);
  103. Operand value = context.BitwiseOr(
  104. context.ZeroExtend32(OperandType.I64, lowValue),
  105. context.ShiftLeft(context.ZeroExtend32(OperandType.I64, highValue), Const(32)));
  106. context.Copy(vec, context.VectorInsert(vec, value, op.Vm & 1));
  107. }
  108. }
  109. public static void Vtbl(ArmEmitterContext context)
  110. {
  111. OpCode32SimdTbl op = (OpCode32SimdTbl)context.CurrOp;
  112. bool extension = op.Opc == 1;
  113. int elems = op.GetBytesCount() >> op.Size;
  114. int length = op.Length + 1;
  115. (int Qx, int Ix)[] tableTuples = new (int, int)[length];
  116. for (int i = 0; i < length; i++)
  117. {
  118. (int vn, int en) = GetQuadwordAndSubindex(op.Vn + i, op.RegisterSize);
  119. tableTuples[i] = (vn, en);
  120. }
  121. int byteLength = length * 8;
  122. Operand res = GetVecA32(op.Qd);
  123. Operand m = GetVecA32(op.Qm);
  124. for (int index = 0; index < elems; index++)
  125. {
  126. Operand selectedIndex = context.ZeroExtend8(OperandType.I32, context.VectorExtract8(m, index + op.Im));
  127. Operand inRange = context.ICompareLess(selectedIndex, Const(byteLength));
  128. Operand elemRes = null; // Note: This is I64 for ease of calculation.
  129. // TODO: Branching rather than conditional select.
  130. // Get indexed byte.
  131. // To simplify (ha) the il, we get bytes from every vector and use a nested conditional select to choose the right result.
  132. // This does have to extract `length` times for every element but certainly not as bad as it could be.
  133. // Which vector number is the index on.
  134. Operand vecIndex = context.ShiftRightUI(selectedIndex, Const(3));
  135. // What should we shift by to extract it.
  136. Operand subVecIndexShift = context.ShiftLeft(context.BitwiseAnd(selectedIndex, Const(7)), Const(3));
  137. for (int i = 0; i < length; i++)
  138. {
  139. (int qx, int ix) = tableTuples[i];
  140. // Get the whole vector, we'll get a byte out of it.
  141. Operand lookupResult;
  142. if (qx == op.Qd)
  143. {
  144. // Result contains the current state of the vector.
  145. lookupResult = context.VectorExtract(OperandType.I64, res, ix);
  146. }
  147. else
  148. {
  149. lookupResult = EmitVectorExtract32(context, qx, ix, 3, false); // I64
  150. }
  151. lookupResult = context.ShiftRightUI(lookupResult, subVecIndexShift); // Get the relevant byte from this vector.
  152. if (i == 0)
  153. {
  154. elemRes = lookupResult; // First result is always default.
  155. }
  156. else
  157. {
  158. Operand isThisElem = context.ICompareEqual(vecIndex, Const(i));
  159. elemRes = context.ConditionalSelect(isThisElem, lookupResult, elemRes);
  160. }
  161. }
  162. Operand fallback = (extension) ? context.ZeroExtend32(OperandType.I64, EmitVectorExtract32(context, op.Qd, index + op.Id, 0, false)) : Const(0L);
  163. res = EmitVectorInsert(context, res, context.ConditionalSelect(inRange, elemRes, fallback), index + op.Id, 0);
  164. }
  165. context.Copy(GetVecA32(op.Qd), res);
  166. }
  167. public static void Vtrn(ArmEmitterContext context)
  168. {
  169. OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
  170. int elems = op.GetBytesCount() >> op.Size;
  171. int pairs = elems >> 1;
  172. bool overlap = op.Qm == op.Qd;
  173. Operand resD = GetVecA32(op.Qd);
  174. Operand resM = GetVecA32(op.Qm);
  175. for (int index = 0; index < pairs; index++)
  176. {
  177. int pairIndex = index << 1;
  178. Operand d2 = EmitVectorExtract32(context, op.Qd, pairIndex + 1 + op.Id, op.Size, false);
  179. Operand m1 = EmitVectorExtract32(context, op.Qm, pairIndex + op.Im, op.Size, false);
  180. resD = EmitVectorInsert(context, resD, m1, pairIndex + 1 + op.Id, op.Size);
  181. if (overlap)
  182. {
  183. resM = resD;
  184. }
  185. resM = EmitVectorInsert(context, resM, d2, pairIndex + op.Im, op.Size);
  186. if (overlap)
  187. {
  188. resD = resM;
  189. }
  190. }
  191. context.Copy(GetVecA32(op.Qd), resD);
  192. if (!overlap)
  193. {
  194. context.Copy(GetVecA32(op.Qm), resM);
  195. }
  196. }
  197. public static void Vzip(ArmEmitterContext context)
  198. {
  199. OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
  200. int elems = op.GetBytesCount() >> op.Size;
  201. int pairs = elems >> 1;
  202. bool overlap = op.Qm == op.Qd;
  203. Operand resD = GetVecA32(op.Qd);
  204. Operand resM = GetVecA32(op.Qm);
  205. for (int index = 0; index < pairs; index++)
  206. {
  207. int pairIndex = index << 1;
  208. Operand dRowD = EmitVectorExtract32(context, op.Qd, index + op.Id, op.Size, false);
  209. Operand mRowD = EmitVectorExtract32(context, op.Qm, index + op.Im, op.Size, false);
  210. Operand dRowM = EmitVectorExtract32(context, op.Qd, index + op.Id + pairs, op.Size, false);
  211. Operand mRowM = EmitVectorExtract32(context, op.Qm, index + op.Im + pairs, op.Size, false);
  212. resD = EmitVectorInsert(context, resD, dRowD, pairIndex + op.Id, op.Size);
  213. resD = EmitVectorInsert(context, resD, mRowD, pairIndex + 1 + op.Id, op.Size);
  214. if (overlap)
  215. {
  216. resM = resD;
  217. }
  218. resM = EmitVectorInsert(context, resM, dRowM, pairIndex + op.Im, op.Size);
  219. resM = EmitVectorInsert(context, resM, mRowM, pairIndex + 1 + op.Im, op.Size);
  220. if (overlap)
  221. {
  222. resD = resM;
  223. }
  224. }
  225. context.Copy(GetVecA32(op.Qd), resD);
  226. if (!overlap)
  227. {
  228. context.Copy(GetVecA32(op.Qm), resM);
  229. }
  230. }
  231. public static void Vuzp(ArmEmitterContext context)
  232. {
  233. OpCode32SimdCmpZ op = (OpCode32SimdCmpZ)context.CurrOp;
  234. int elems = op.GetBytesCount() >> op.Size;
  235. int pairs = elems >> 1;
  236. bool overlap = op.Qm == op.Qd;
  237. Operand resD = GetVecA32(op.Qd);
  238. Operand resM = GetVecA32(op.Qm);
  239. for (int index = 0; index < elems; index++)
  240. {
  241. Operand dIns, mIns;
  242. if (index >= pairs)
  243. {
  244. int pind = index - pairs;
  245. dIns = EmitVectorExtract32(context, op.Qm, (pind << 1) + op.Im, op.Size, false);
  246. mIns = EmitVectorExtract32(context, op.Qm, ((pind << 1) | 1) + op.Im, op.Size, false);
  247. }
  248. else
  249. {
  250. dIns = EmitVectorExtract32(context, op.Qd, (index << 1) + op.Id, op.Size, false);
  251. mIns = EmitVectorExtract32(context, op.Qd, ((index << 1) | 1) + op.Id, op.Size, false);
  252. }
  253. resD = EmitVectorInsert(context, resD, dIns, index + op.Id, op.Size);
  254. if (overlap)
  255. {
  256. resM = resD;
  257. }
  258. resM = EmitVectorInsert(context, resM, mIns, index + op.Im, op.Size);
  259. if (overlap)
  260. {
  261. resD = resM;
  262. }
  263. }
  264. context.Copy(GetVecA32(op.Qd), resD);
  265. if (!overlap)
  266. {
  267. context.Copy(GetVecA32(op.Qm), resM);
  268. }
  269. }
  270. }
  271. }