AInstEmitSimd.cs 31 KB

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