AInstEmitSimd.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. using ChocolArm64.Decoder;
  2. using ChocolArm64.State;
  3. using ChocolArm64.Translation;
  4. using System;
  5. using System.Reflection;
  6. using System.Reflection.Emit;
  7. using static ChocolArm64.Instruction.AInstEmitMemoryHelper;
  8. namespace ChocolArm64.Instruction
  9. {
  10. static partial class AInstEmit
  11. {
  12. public static void Add_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.Add);
  13. public static void Addp_V(AILEmitterCtx Context)
  14. {
  15. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  16. Context.EmitLdvec(Op.Rn);
  17. Context.EmitLdvec(Op.Rm);
  18. Context.EmitLdc_I4(Op.Size);
  19. ASoftFallback.EmitCall(Context,
  20. nameof(ASoftFallback.Addp64),
  21. nameof(ASoftFallback.Addp128));
  22. Context.EmitStvec(Op.Rd);
  23. }
  24. public static void Addv_V(AILEmitterCtx Context) => EmitVectorAddv(Context);
  25. public static void And_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.And);
  26. public static void Bic_V(AILEmitterCtx Context) => EmitVectorBic(Context);
  27. public static void Bic_Vi(AILEmitterCtx Context)
  28. {
  29. AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
  30. Context.EmitLdvec(Op.Rd);
  31. Context.EmitLdc_I8(Op.Imm);
  32. Context.EmitLdc_I4(Op.Size);
  33. ASoftFallback.EmitCall(Context,
  34. nameof(ASoftFallback.Bic_Vi64),
  35. nameof(ASoftFallback.Bic_Vi128));
  36. Context.EmitStvec(Op.Rd);
  37. }
  38. public static void Bsl_V(AILEmitterCtx Context) => EmitVectorBsl(Context);
  39. public static void Cmeq_V(AILEmitterCtx Context) => EmitVectorCmp(Context, OpCodes.Beq_S);
  40. public static void Cmge_V(AILEmitterCtx Context) => EmitVectorCmp(Context, OpCodes.Bge_S);
  41. public static void Cmgt_V(AILEmitterCtx Context) => EmitVectorCmp(Context, OpCodes.Bgt_S);
  42. public static void Cmhi_V(AILEmitterCtx Context) => EmitVectorCmp(Context, OpCodes.Bgt_Un_S);
  43. public static void Cmhs_V(AILEmitterCtx Context) => EmitVectorCmp(Context, OpCodes.Bge_Un_S);
  44. public static void Cmle_V(AILEmitterCtx Context) => EmitVectorCmp(Context, OpCodes.Ble_S);
  45. public static void Cmlt_V(AILEmitterCtx Context) => EmitVectorCmp(Context, OpCodes.Blt_S);
  46. public static void Cnt_V(AILEmitterCtx Context)
  47. {
  48. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  49. Context.EmitLdvec(Op.Rn);
  50. ASoftFallback.EmitCall(Context,
  51. nameof(ASoftFallback.Cnt64),
  52. nameof(ASoftFallback.Cnt128));
  53. Context.EmitStvec(Op.Rd);
  54. }
  55. public static void Dup_Gp(AILEmitterCtx Context)
  56. {
  57. AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
  58. Context.EmitLdintzr(Op.Rn);
  59. Context.EmitLdc_I4(Op.Size);
  60. ASoftFallback.EmitCall(Context,
  61. nameof(ASoftFallback.Dup_Gp64),
  62. nameof(ASoftFallback.Dup_Gp128));
  63. Context.EmitStvec(Op.Rd);
  64. }
  65. public static void Dup_V(AILEmitterCtx Context)
  66. {
  67. AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
  68. Context.EmitLdvec(Op.Rn);
  69. Context.EmitLdc_I4(Op.DstIndex);
  70. Context.EmitLdc_I4(Op.Size);
  71. ASoftFallback.EmitCall(Context,
  72. nameof(ASoftFallback.Dup_V64),
  73. nameof(ASoftFallback.Dup_V128));
  74. Context.EmitStvec(Op.Rd);
  75. }
  76. public static void Eor_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.Xor);
  77. public static void Fadd_V(AILEmitterCtx Context)
  78. {
  79. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  80. Context.EmitLdvec(Op.Rn);
  81. Context.EmitLdvec(Op.Rm);
  82. Context.EmitLdc_I4(Op.SizeF);
  83. ASoftFallback.EmitCall(Context,
  84. nameof(ASoftFallback.Fadd64),
  85. nameof(ASoftFallback.Fadd128));
  86. Context.EmitStvec(Op.Rd);
  87. }
  88. public static void Fcvtzs_V(AILEmitterCtx Context)
  89. {
  90. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  91. Context.EmitLdvec(Op.Rn);
  92. Context.EmitLdc_I4(0);
  93. Context.EmitLdc_I4(Op.SizeF);
  94. ASoftFallback.EmitCall(Context,
  95. nameof(ASoftFallback.Fcvtzs_V64),
  96. nameof(ASoftFallback.Fcvtzs_V128));
  97. Context.EmitStvec(Op.Rd);
  98. }
  99. public static void Fcvtzs_V_Fix(AILEmitterCtx Context)
  100. {
  101. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  102. Context.EmitLdvec(Op.Rn);
  103. Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm);
  104. Context.EmitLdc_I4(Op.Size - 2);
  105. ASoftFallback.EmitCall(Context,
  106. nameof(ASoftFallback.Fcvtzs_V64),
  107. nameof(ASoftFallback.Fcvtzs_V128));
  108. Context.EmitStvec(Op.Rd);
  109. }
  110. public static void Fcvtzu_V(AILEmitterCtx Context)
  111. {
  112. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  113. Context.EmitLdvec(Op.Rn);
  114. Context.EmitLdc_I4(0);
  115. Context.EmitLdc_I4(Op.SizeF);
  116. ASoftFallback.EmitCall(Context,
  117. nameof(ASoftFallback.Fcvtzu_V_64),
  118. nameof(ASoftFallback.Fcvtzu_V_128));
  119. Context.EmitStvec(Op.Rd);
  120. }
  121. public static void Fcvtzu_V_Fix(AILEmitterCtx Context)
  122. {
  123. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  124. Context.EmitLdvec(Op.Rn);
  125. Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm);
  126. Context.EmitLdc_I4(Op.Size - 2);
  127. ASoftFallback.EmitCall(Context,
  128. nameof(ASoftFallback.Fcvtzu_V_64),
  129. nameof(ASoftFallback.Fcvtzu_V_128));
  130. Context.EmitStvec(Op.Rd);
  131. }
  132. public static void Fmla_V(AILEmitterCtx Context)
  133. {
  134. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  135. Context.EmitLdvec(Op.Rd);
  136. Context.EmitLdvec(Op.Rn);
  137. Context.EmitLdvec(Op.Rm);
  138. Context.EmitLdc_I4(Op.SizeF);
  139. ASoftFallback.EmitCall(Context,
  140. nameof(ASoftFallback.Fmla64),
  141. nameof(ASoftFallback.Fmla128));
  142. Context.EmitStvec(Op.Rd);
  143. }
  144. public static void Fmla_Vs(AILEmitterCtx Context)
  145. {
  146. AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
  147. Context.EmitLdvec(Op.Rd);
  148. Context.EmitLdvec(Op.Rn);
  149. Context.EmitLdvec(Op.Rm);
  150. Context.EmitLdc_I4(Op.Index);
  151. Context.EmitLdc_I4(Op.SizeF);
  152. ASoftFallback.EmitCall(Context,
  153. nameof(ASoftFallback.Fmla_Ve64),
  154. nameof(ASoftFallback.Fmla_Ve128));
  155. Context.EmitStvec(Op.Rd);
  156. }
  157. public static void Fmov_V(AILEmitterCtx Context)
  158. {
  159. AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
  160. Context.EmitLdc_I8(Op.Imm);
  161. Context.EmitLdc_I4(Op.Size + 2);
  162. ASoftFallback.EmitCall(Context,
  163. nameof(ASoftFallback.Dup_Gp64),
  164. nameof(ASoftFallback.Dup_Gp128));
  165. Context.EmitStvec(Op.Rd);
  166. }
  167. public static void Fmul_V(AILEmitterCtx Context)
  168. {
  169. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  170. Context.EmitLdvec(Op.Rn);
  171. Context.EmitLdvec(Op.Rm);
  172. Context.EmitLdc_I4(Op.SizeF);
  173. ASoftFallback.EmitCall(Context,
  174. nameof(ASoftFallback.Fmul64),
  175. nameof(ASoftFallback.Fmul128));
  176. Context.EmitStvec(Op.Rd);
  177. }
  178. public static void Fmul_Vs(AILEmitterCtx Context)
  179. {
  180. AOpCodeSimdRegElem Op = (AOpCodeSimdRegElem)Context.CurrOp;
  181. Context.EmitLdvec(Op.Rn);
  182. Context.EmitLdvec(Op.Rm);
  183. Context.EmitLdc_I4(Op.Index);
  184. Context.EmitLdc_I4(Op.SizeF);
  185. ASoftFallback.EmitCall(Context,
  186. nameof(ASoftFallback.Fmul_Ve64),
  187. nameof(ASoftFallback.Fmul_Ve128));
  188. Context.EmitStvec(Op.Rd);
  189. }
  190. public static void Fsub_V(AILEmitterCtx Context)
  191. {
  192. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  193. Context.EmitLdvec(Op.Rn);
  194. Context.EmitLdvec(Op.Rm);
  195. Context.EmitLdc_I4(Op.SizeF);
  196. ASoftFallback.EmitCall(Context,
  197. nameof(ASoftFallback.Fsub64),
  198. nameof(ASoftFallback.Fsub128));
  199. Context.EmitStvec(Op.Rd);
  200. }
  201. public static void Ins_Gp(AILEmitterCtx Context)
  202. {
  203. AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
  204. Context.EmitLdvec(Op.Rd);
  205. Context.EmitLdintzr(Op.Rn);
  206. Context.EmitLdc_I4(Op.DstIndex);
  207. Context.EmitLdc_I4(Op.Size);
  208. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Ins_Gp));
  209. Context.EmitStvec(Op.Rd);
  210. }
  211. public static void Ins_V(AILEmitterCtx Context)
  212. {
  213. AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
  214. Context.EmitLdvec(Op.Rd);
  215. Context.EmitLdvec(Op.Rn);
  216. Context.EmitLdc_I4(Op.SrcIndex);
  217. Context.EmitLdc_I4(Op.DstIndex);
  218. Context.EmitLdc_I4(Op.Size);
  219. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Ins_V));
  220. Context.EmitStvec(Op.Rd);
  221. }
  222. public static void Ld__Vms(AILEmitterCtx Context) => EmitSimdMemMs(Context, IsLoad: true);
  223. public static void Ld__Vss(AILEmitterCtx Context) => EmitSimdMemSs(Context, IsLoad: true);
  224. public static void Mla_V(AILEmitterCtx Context) => EmitVectorMla(Context);
  225. public static void Movi_V(AILEmitterCtx Context) => EmitMovi_V(Context, false);
  226. public static void Mul_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.Mul);
  227. public static void Mvni_V(AILEmitterCtx Context) => EmitMovi_V(Context, true);
  228. private static void EmitMovi_V(AILEmitterCtx Context, bool Not)
  229. {
  230. AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
  231. Context.EmitLdc_I8(Not ? ~Op.Imm : Op.Imm);
  232. Context.EmitLdc_I4(Op.Size);
  233. ASoftFallback.EmitCall(Context,
  234. nameof(ASoftFallback.Dup_Gp64),
  235. nameof(ASoftFallback.Dup_Gp128));
  236. Context.EmitStvec(Op.Rd);
  237. }
  238. public static void Neg_V(AILEmitterCtx Context) => EmitVectorUnarySx(Context, OpCodes.Neg);
  239. public static void Not_V(AILEmitterCtx Context) => EmitVectorUnaryZx(Context, OpCodes.Not);
  240. public static void Orr_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.Or);
  241. public static void Orr_Vi(AILEmitterCtx Context)
  242. {
  243. AOpCodeSimdImm Op = (AOpCodeSimdImm)Context.CurrOp;
  244. Context.EmitLdvec(Op.Rd);
  245. Context.EmitLdc_I8(Op.Imm);
  246. Context.EmitLdc_I4(Op.Size);
  247. ASoftFallback.EmitCall(Context,
  248. nameof(ASoftFallback.Orr_Vi64),
  249. nameof(ASoftFallback.Orr_Vi128));
  250. Context.EmitStvec(Op.Rd);
  251. }
  252. public static void Saddw_V(AILEmitterCtx Context)
  253. {
  254. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  255. Context.EmitLdvec(Op.Rn);
  256. Context.EmitLdvec(Op.Rm);
  257. Context.EmitLdc_I4(Op.Size);
  258. ASoftFallback.EmitCall(Context,
  259. nameof(ASoftFallback.Saddw),
  260. nameof(ASoftFallback.Saddw2));
  261. Context.EmitStvec(Op.Rd);
  262. }
  263. public static void Scvtf_V(AILEmitterCtx Context)
  264. {
  265. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  266. Context.EmitLdvec(Op.Rn);
  267. Context.EmitLdc_I4(Op.SizeF);
  268. ASoftFallback.EmitCall(Context,
  269. nameof(ASoftFallback.Scvtf_V64),
  270. nameof(ASoftFallback.Scvtf_V128));
  271. Context.EmitStvec(Op.Rd);
  272. }
  273. public static void Shl_V(AILEmitterCtx Context)
  274. {
  275. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  276. EmitVectorImmBinaryZx(Context, OpCodes.Shl, Op.Imm - (8 << Op.Size));
  277. }
  278. public static void Smax_V(AILEmitterCtx Context) => EmitVectorSmax(Context);
  279. public static void Smin_V(AILEmitterCtx Context) => EmitVectorSmin(Context);
  280. public static void Sshl_V(AILEmitterCtx Context) => EmitVectorSshl(Context);
  281. public static void Sshll_V(AILEmitterCtx Context)
  282. {
  283. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  284. Context.EmitLdvec(Op.Rn);
  285. Context.EmitLdc_I4(Op.Imm - (8 << Op.Size));
  286. Context.EmitLdc_I4(Op.Size);
  287. ASoftFallback.EmitCall(Context,
  288. nameof(ASoftFallback.Sshll),
  289. nameof(ASoftFallback.Sshll2));
  290. Context.EmitStvec(Op.Rd);
  291. }
  292. public static void Sshr_V(AILEmitterCtx Context)
  293. {
  294. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  295. EmitVectorImmBinarySx(Context, OpCodes.Shr, (8 << (Op.Size + 1)) - Op.Imm);
  296. }
  297. public static void St__V(AILEmitterCtx Context) => EmitSimdMemMs(Context, IsLoad: false);
  298. public static void Sub_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.Sub);
  299. public static void Tbl_V(AILEmitterCtx Context)
  300. {
  301. AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp;
  302. Context.EmitLdvec(Op.Rm);
  303. for (int Index = 0; Index < Op.Size; Index++)
  304. {
  305. Context.EmitLdvec((Op.Rn + Index) & 0x1f);
  306. }
  307. switch (Op.Size)
  308. {
  309. case 1: ASoftFallback.EmitCall(Context,
  310. nameof(ASoftFallback.Tbl1_V64),
  311. nameof(ASoftFallback.Tbl1_V128)); break;
  312. case 2: ASoftFallback.EmitCall(Context,
  313. nameof(ASoftFallback.Tbl2_V64),
  314. nameof(ASoftFallback.Tbl2_V128)); break;
  315. case 3: ASoftFallback.EmitCall(Context,
  316. nameof(ASoftFallback.Tbl3_V64),
  317. nameof(ASoftFallback.Tbl3_V128)); break;
  318. case 4: ASoftFallback.EmitCall(Context,
  319. nameof(ASoftFallback.Tbl4_V64),
  320. nameof(ASoftFallback.Tbl4_V128)); break;
  321. default: throw new InvalidOperationException();
  322. }
  323. Context.EmitStvec(Op.Rd);
  324. }
  325. public static void Uaddlv_V(AILEmitterCtx Context)
  326. {
  327. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  328. Context.EmitLdvec(Op.Rn);
  329. Context.EmitLdc_I4(Op.Size);
  330. ASoftFallback.EmitCall(Context,
  331. nameof(ASoftFallback.Uaddlv64),
  332. nameof(ASoftFallback.Uaddlv128));
  333. Context.EmitStvec(Op.Rd);
  334. }
  335. public static void Uaddw_V(AILEmitterCtx Context)
  336. {
  337. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  338. Context.EmitLdvec(Op.Rn);
  339. Context.EmitLdvec(Op.Rm);
  340. Context.EmitLdc_I4(Op.Size);
  341. ASoftFallback.EmitCall(Context,
  342. nameof(ASoftFallback.Uaddw),
  343. nameof(ASoftFallback.Uaddw2));
  344. Context.EmitStvec(Op.Rd);
  345. }
  346. public static void Ucvtf_V(AILEmitterCtx Context)
  347. {
  348. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  349. Context.EmitLdvec(Op.Rn);
  350. if (Op.Size == 0)
  351. {
  352. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Ucvtf_V_F));
  353. }
  354. else if (Op.Size == 1)
  355. {
  356. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Ucvtf_V_D));
  357. }
  358. else
  359. {
  360. throw new InvalidOperationException();
  361. }
  362. Context.EmitStvec(Op.Rd);
  363. }
  364. public static void Umov_S(AILEmitterCtx Context)
  365. {
  366. AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
  367. Context.EmitLdvec(Op.Rn);
  368. Context.EmitLdc_I4(Op.DstIndex);
  369. Context.EmitLdc_I4(Op.Size);
  370. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
  371. Context.EmitStintzr(Op.Rd);
  372. }
  373. public static void Ushl_V(AILEmitterCtx Context) => EmitVectorUshl(Context);
  374. public static void Ushll_V(AILEmitterCtx Context)
  375. {
  376. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  377. Context.EmitLdvec(Op.Rn);
  378. Context.EmitLdc_I4(Op.Imm - (8 << Op.Size));
  379. Context.EmitLdc_I4(Op.Size);
  380. ASoftFallback.EmitCall(Context,
  381. nameof(ASoftFallback.Ushll),
  382. nameof(ASoftFallback.Ushll2));
  383. Context.EmitStvec(Op.Rd);
  384. }
  385. public static void Ushr_V(AILEmitterCtx Context)
  386. {
  387. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  388. Context.EmitLdvec(Op.Rn);
  389. Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm);
  390. Context.EmitLdc_I4(Op.Size);
  391. ASoftFallback.EmitCall(Context,
  392. nameof(ASoftFallback.Ushr64),
  393. nameof(ASoftFallback.Ushr128));
  394. Context.EmitStvec(Op.Rd);
  395. }
  396. public static void Usra_V(AILEmitterCtx Context)
  397. {
  398. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  399. Context.EmitLdvec(Op.Rd);
  400. Context.EmitLdvec(Op.Rn);
  401. Context.EmitLdc_I4((8 << (Op.Size + 1)) - Op.Imm);
  402. Context.EmitLdc_I4(Op.Size);
  403. ASoftFallback.EmitCall(Context,
  404. nameof(ASoftFallback.Usra64),
  405. nameof(ASoftFallback.Usra128));
  406. Context.EmitStvec(Op.Rd);
  407. }
  408. public static void Uzp1_V(AILEmitterCtx Context)
  409. {
  410. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  411. Context.EmitLdvec(Op.Rn);
  412. Context.EmitLdvec(Op.Rm);
  413. Context.EmitLdc_I4(Op.Size);
  414. ASoftFallback.EmitCall(Context,
  415. nameof(ASoftFallback.Uzp1_V64),
  416. nameof(ASoftFallback.Uzp1_V128));
  417. Context.EmitStvec(Op.Rd);
  418. }
  419. public static void Xtn_V(AILEmitterCtx Context)
  420. {
  421. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  422. Context.EmitLdvec(Op.Rn);
  423. Context.EmitLdc_I4(Op.Size);
  424. ASoftFallback.EmitCall(Context,
  425. nameof(ASoftFallback.Xtn),
  426. nameof(ASoftFallback.Xtn2));
  427. Context.EmitStvec(Op.Rd);
  428. }
  429. private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad)
  430. {
  431. AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp;
  432. int Offset = 0;
  433. for (int Rep = 0; Rep < Op.Reps; Rep++)
  434. for (int Elem = 0; Elem < Op.Elems; Elem++)
  435. for (int SElem = 0; SElem < Op.SElems; SElem++)
  436. {
  437. int Rtt = (Op.Rt + Rep + SElem) & 0x1f;
  438. if (IsLoad)
  439. {
  440. Context.EmitLdvec(Rtt);
  441. Context.EmitLdc_I4(Elem);
  442. Context.EmitLdc_I4(Op.Size);
  443. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  444. Context.EmitLdint(Op.Rn);
  445. Context.EmitLdc_I8(Offset);
  446. Context.Emit(OpCodes.Add);
  447. EmitReadZxCall(Context, Op.Size);
  448. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  449. Context.EmitStvec(Rtt);
  450. if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1)
  451. {
  452. EmitVectorZeroUpper(Context, Rtt);
  453. }
  454. }
  455. else
  456. {
  457. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  458. Context.EmitLdint(Op.Rn);
  459. Context.EmitLdc_I8(Offset);
  460. Context.Emit(OpCodes.Add);
  461. Context.EmitLdvec(Rtt);
  462. Context.EmitLdc_I4(Elem);
  463. Context.EmitLdc_I4(Op.Size);
  464. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
  465. EmitWriteCall(Context, Op.Size);
  466. }
  467. Offset += 1 << Op.Size;
  468. }
  469. if (Op.WBack)
  470. {
  471. Context.EmitLdint(Op.Rn);
  472. if (Op.Rm != ARegisters.ZRIndex)
  473. {
  474. Context.EmitLdint(Op.Rm);
  475. }
  476. else
  477. {
  478. Context.EmitLdc_I8(Offset);
  479. }
  480. Context.Emit(OpCodes.Add);
  481. Context.EmitStint(Op.Rn);
  482. }
  483. }
  484. private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad)
  485. {
  486. AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp;
  487. //TODO: Replicate mode.
  488. int Offset = 0;
  489. for (int SElem = 0; SElem < Op.SElems; SElem++)
  490. {
  491. int Rt = (Op.Rt + SElem) & 0x1f;
  492. if (IsLoad)
  493. {
  494. Context.EmitLdvec(Rt);
  495. Context.EmitLdc_I4(Op.Index);
  496. Context.EmitLdc_I4(Op.Size);
  497. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  498. Context.EmitLdint(Op.Rn);
  499. Context.EmitLdc_I8(Offset);
  500. Context.Emit(OpCodes.Add);
  501. EmitReadZxCall(Context, Op.Size);
  502. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  503. Context.EmitStvec(Rt);
  504. if (Op.RegisterSize == ARegisterSize.SIMD64)
  505. {
  506. EmitVectorZeroUpper(Context, Rt);
  507. }
  508. }
  509. else
  510. {
  511. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  512. Context.EmitLdint(Op.Rn);
  513. Context.EmitLdc_I8(Offset);
  514. Context.Emit(OpCodes.Add);
  515. Context.EmitLdvec(Rt);
  516. Context.EmitLdc_I4(Op.Index);
  517. Context.EmitLdc_I4(Op.Size);
  518. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
  519. EmitWriteCall(Context, Op.Size);
  520. }
  521. Offset += 1 << Op.Size;
  522. }
  523. if (Op.WBack)
  524. {
  525. Context.EmitLdint(Op.Rn);
  526. if (Op.Rm != ARegisters.ZRIndex)
  527. {
  528. Context.EmitLdint(Op.Rm);
  529. }
  530. else
  531. {
  532. Context.EmitLdc_I8(Offset);
  533. }
  534. Context.Emit(OpCodes.Add);
  535. Context.EmitStint(Op.Rn);
  536. }
  537. }
  538. private static void EmitVectorAddv(AILEmitterCtx Context)
  539. {
  540. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  541. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  542. EmitVectorZeroLower(Context, Op.Rd);
  543. EmitVectorZeroUpper(Context, Op.Rd);
  544. Context.EmitLdvec(Op.Rd);
  545. Context.EmitLdc_I4(0);
  546. Context.EmitLdc_I4(Op.Size);
  547. EmitVectorExtractZx(Context, Op.Rn, 0);
  548. for (int Index = 1; Index < (Bytes >> Op.Size); Index++)
  549. {
  550. EmitVectorExtractZx(Context, Op.Rn, Index);
  551. Context.Emit(OpCodes.Add);
  552. }
  553. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  554. Context.EmitStvec(Op.Rd);
  555. }
  556. private static void EmitVectorBic(AILEmitterCtx Context)
  557. {
  558. EmitVectorBinaryZx(Context, () =>
  559. {
  560. Context.Emit(OpCodes.Not);
  561. Context.Emit(OpCodes.And);
  562. });
  563. }
  564. private static void EmitVectorBsl(AILEmitterCtx Context)
  565. {
  566. EmitVectorTernaryZx(Context, () =>
  567. {
  568. Context.EmitSttmp();
  569. Context.EmitLdtmp();
  570. Context.Emit(OpCodes.Xor);
  571. Context.Emit(OpCodes.And);
  572. Context.EmitLdtmp();
  573. Context.Emit(OpCodes.Xor);
  574. });
  575. }
  576. private static void EmitVectorMla(AILEmitterCtx Context)
  577. {
  578. EmitVectorTernaryZx(Context, () =>
  579. {
  580. Context.Emit(OpCodes.Mul);
  581. Context.Emit(OpCodes.Add);
  582. });
  583. }
  584. private static void EmitVectorSmax(AILEmitterCtx Context)
  585. {
  586. Type[] Types = new Type[] { typeof(long), typeof(long) };
  587. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  588. EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo));
  589. }
  590. private static void EmitVectorSmin(AILEmitterCtx Context)
  591. {
  592. Type[] Types = new Type[] { typeof(long), typeof(long) };
  593. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  594. EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo));
  595. }
  596. private static void EmitVectorSshl(AILEmitterCtx Context) => EmitVectorShl(Context, true);
  597. private static void EmitVectorUshl(AILEmitterCtx Context) => EmitVectorShl(Context, false);
  598. private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
  599. {
  600. //This instruction shifts the value on vector A by the number of bits
  601. //specified on the signed, lower 8 bits of vector B. If the shift value
  602. //is greater or equal to the data size of each lane, then the result is zero.
  603. //Additionally, negative shifts produces right shifts by the negated shift value.
  604. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  605. int MaxShift = 8 << Op.Size;
  606. EmitVectorBinaryZx(Context, () =>
  607. {
  608. AILLabel LblShl = new AILLabel();
  609. AILLabel LblZero = new AILLabel();
  610. AILLabel LblEnd = new AILLabel();
  611. void EmitShift(OpCode ILOp)
  612. {
  613. Context.Emit(OpCodes.Dup);
  614. Context.EmitLdc_I4(MaxShift);
  615. Context.Emit(OpCodes.Bge_S, LblZero);
  616. Context.Emit(ILOp);
  617. Context.Emit(OpCodes.Br_S, LblEnd);
  618. }
  619. Context.Emit(OpCodes.Conv_I1);
  620. Context.Emit(OpCodes.Dup);
  621. Context.EmitLdc_I4(0);
  622. Context.Emit(OpCodes.Bge_S, LblShl);
  623. Context.Emit(OpCodes.Neg);
  624. EmitShift(Signed
  625. ? OpCodes.Shr
  626. : OpCodes.Shr_Un);
  627. Context.MarkLabel(LblShl);
  628. EmitShift(OpCodes.Shl);
  629. Context.MarkLabel(LblZero);
  630. Context.Emit(OpCodes.Pop);
  631. Context.Emit(OpCodes.Pop);
  632. Context.EmitLdc_I8(0);
  633. Context.MarkLabel(LblEnd);
  634. });
  635. }
  636. private static void EmitVectorUnarySx(AILEmitterCtx Context, OpCode ILOp)
  637. {
  638. EmitVectorUnarySx(Context, () => Context.Emit(ILOp));
  639. }
  640. private static void EmitVectorUnaryZx(AILEmitterCtx Context, OpCode ILOp)
  641. {
  642. EmitVectorUnaryZx(Context, () => Context.Emit(ILOp));
  643. }
  644. private static void EmitVectorBinaryZx(AILEmitterCtx Context, OpCode ILOp)
  645. {
  646. EmitVectorBinaryZx(Context, () => Context.Emit(ILOp));
  647. }
  648. private static void EmitVectorUnarySx(AILEmitterCtx Context, Action Emit)
  649. {
  650. EmitVectorOp(Context, Emit, 1, true);
  651. }
  652. private static void EmitVectorBinarySx(AILEmitterCtx Context, Action Emit)
  653. {
  654. EmitVectorOp(Context, Emit, 2, true);
  655. }
  656. private static void EmitVectorUnaryZx(AILEmitterCtx Context, Action Emit)
  657. {
  658. EmitVectorOp(Context, Emit, 1, false);
  659. }
  660. private static void EmitVectorBinaryZx(AILEmitterCtx Context, Action Emit)
  661. {
  662. EmitVectorOp(Context, Emit, 2, false);
  663. }
  664. private static void EmitVectorTernaryZx(AILEmitterCtx Context, Action Emit)
  665. {
  666. EmitVectorOp(Context, Emit, 3, false);
  667. }
  668. private static void EmitVectorOp(AILEmitterCtx Context, Action Emit, int Opers, bool Signed)
  669. {
  670. if (Opers < 1 || Opers > 3)
  671. {
  672. throw new ArgumentOutOfRangeException(nameof(Opers));
  673. }
  674. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  675. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  676. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  677. {
  678. Context.EmitLdvec(Op.Rd);
  679. Context.EmitLdc_I4(Index);
  680. Context.EmitLdc_I4(Op.Size);
  681. if (Opers == 3)
  682. {
  683. EmitVectorExtract(Context, Op.Rd, Index, Signed);
  684. }
  685. if (Opers >= 1)
  686. {
  687. EmitVectorExtract(Context, Op.Rn, Index, Signed);
  688. }
  689. if (Opers >= 2)
  690. {
  691. EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Signed);
  692. }
  693. Emit();
  694. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  695. Context.EmitStvec(Op.Rd);
  696. }
  697. if (Op.RegisterSize == ARegisterSize.SIMD64)
  698. {
  699. EmitVectorZeroUpper(Context, Op.Rd);
  700. }
  701. }
  702. private static void EmitVectorImmBinarySx(AILEmitterCtx Context, OpCode ILOp, long Imm)
  703. {
  704. EmitVectorImmBinarySx(Context, () => Context.Emit(ILOp), Imm);
  705. }
  706. private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, OpCode ILOp, long Imm)
  707. {
  708. EmitVectorImmBinaryZx(Context, () => Context.Emit(ILOp), Imm);
  709. }
  710. private static void EmitVectorImmBinarySx(AILEmitterCtx Context, Action Emit, long Imm)
  711. {
  712. EmitVectorImmBinaryOp(Context, Emit, Imm, true);
  713. }
  714. private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, Action Emit, long Imm)
  715. {
  716. EmitVectorImmBinaryOp(Context, Emit, Imm, false);
  717. }
  718. private static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit, long Imm, bool Signed)
  719. {
  720. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  721. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  722. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  723. {
  724. Context.EmitLdvec(Op.Rd);
  725. Context.EmitLdc_I4(Index);
  726. Context.EmitLdc_I4(Op.Size);
  727. EmitVectorExtract(Context, Op.Rn, Index, Signed);
  728. Context.EmitLdc_I8(Imm);
  729. Emit();
  730. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  731. Context.EmitStvec(Op.Rd);
  732. }
  733. if (Op.RegisterSize == ARegisterSize.SIMD64)
  734. {
  735. EmitVectorZeroUpper(Context, Op.Rd);
  736. }
  737. }
  738. private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp)
  739. {
  740. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  741. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  742. ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
  743. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  744. {
  745. EmitVectorExtractSx(Context, Op.Rn, Index);
  746. if (Op is AOpCodeSimdReg BinOp)
  747. {
  748. EmitVectorExtractSx(Context, BinOp.Rm, Index);
  749. }
  750. else
  751. {
  752. Context.EmitLdc_I8(0);
  753. }
  754. AILLabel LblTrue = new AILLabel();
  755. AILLabel LblEnd = new AILLabel();
  756. Context.Emit(ILOp, LblTrue);
  757. EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
  758. Context.Emit(OpCodes.Br_S, LblEnd);
  759. Context.MarkLabel(LblTrue);
  760. EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
  761. Context.MarkLabel(LblEnd);
  762. }
  763. if (Op.RegisterSize == ARegisterSize.SIMD64)
  764. {
  765. EmitVectorZeroUpper(Context, Op.Rd);
  766. }
  767. }
  768. private static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index)
  769. {
  770. EmitVectorExtract(Context, Reg, Index, true);
  771. }
  772. private static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index)
  773. {
  774. EmitVectorExtract(Context, Reg, Index, false);
  775. }
  776. private static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, bool Signed)
  777. {
  778. IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
  779. Context.EmitLdvec(Reg);
  780. Context.EmitLdc_I4(Index);
  781. Context.EmitLdc_I4(Op.Size);
  782. ASoftFallback.EmitCall(Context, Signed
  783. ? nameof(ASoftFallback.ExtractSVec)
  784. : nameof(ASoftFallback.ExtractVec));
  785. }
  786. private static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd)
  787. {
  788. EmitVectorInsert(Context, Rd, 0, 3, 0);
  789. }
  790. private static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd)
  791. {
  792. EmitVectorInsert(Context, Rd, 1, 3, 0);
  793. }
  794. private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value)
  795. {
  796. Context.EmitLdvec(Reg);
  797. Context.EmitLdc_I4(Index);
  798. Context.EmitLdc_I4(Size);
  799. Context.EmitLdc_I8(Value);
  800. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  801. Context.EmitStvec(Reg);
  802. }
  803. }
  804. }