AInstEmitSimd.cs 36 KB

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