AInstEmitSimd.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  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) => EmitVectorScvtf(Context);
  192. public static void Shl_V(AILEmitterCtx Context)
  193. {
  194. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  195. EmitVectorImmBinaryZx(Context, OpCodes.Shl, Op.Imm - (8 << Op.Size));
  196. }
  197. public static void Smax_V(AILEmitterCtx Context) => EmitVectorSmax(Context);
  198. public static void Smin_V(AILEmitterCtx Context) => EmitVectorSmin(Context);
  199. public static void Sshl_V(AILEmitterCtx Context) => EmitVectorSshl(Context);
  200. public static void Sshll_V(AILEmitterCtx Context)
  201. {
  202. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  203. Context.EmitLdvec(Op.Rn);
  204. Context.EmitLdc_I4(Op.Imm - (8 << Op.Size));
  205. Context.EmitLdc_I4(Op.Size);
  206. ASoftFallback.EmitCall(Context,
  207. nameof(ASoftFallback.Sshll),
  208. nameof(ASoftFallback.Sshll2));
  209. Context.EmitStvec(Op.Rd);
  210. }
  211. public static void Sshr_V(AILEmitterCtx Context)
  212. {
  213. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  214. EmitVectorImmBinarySx(Context, OpCodes.Shr, (8 << (Op.Size + 1)) - Op.Imm);
  215. }
  216. public static void St__V(AILEmitterCtx Context) => EmitSimdMemMs(Context, IsLoad: false);
  217. public static void Sub_V(AILEmitterCtx Context) => EmitVectorBinaryZx(Context, OpCodes.Sub);
  218. public static void Tbl_V(AILEmitterCtx Context)
  219. {
  220. AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp;
  221. Context.EmitLdvec(Op.Rm);
  222. for (int Index = 0; Index < Op.Size; Index++)
  223. {
  224. Context.EmitLdvec((Op.Rn + Index) & 0x1f);
  225. }
  226. switch (Op.Size)
  227. {
  228. case 1: ASoftFallback.EmitCall(Context,
  229. nameof(ASoftFallback.Tbl1_V64),
  230. nameof(ASoftFallback.Tbl1_V128)); break;
  231. case 2: ASoftFallback.EmitCall(Context,
  232. nameof(ASoftFallback.Tbl2_V64),
  233. nameof(ASoftFallback.Tbl2_V128)); break;
  234. case 3: ASoftFallback.EmitCall(Context,
  235. nameof(ASoftFallback.Tbl3_V64),
  236. nameof(ASoftFallback.Tbl3_V128)); break;
  237. case 4: ASoftFallback.EmitCall(Context,
  238. nameof(ASoftFallback.Tbl4_V64),
  239. nameof(ASoftFallback.Tbl4_V128)); break;
  240. default: throw new InvalidOperationException();
  241. }
  242. Context.EmitStvec(Op.Rd);
  243. }
  244. public static void Uaddlv_V(AILEmitterCtx Context)
  245. {
  246. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  247. Context.EmitLdvec(Op.Rn);
  248. Context.EmitLdc_I4(Op.Size);
  249. ASoftFallback.EmitCall(Context,
  250. nameof(ASoftFallback.Uaddlv64),
  251. nameof(ASoftFallback.Uaddlv128));
  252. Context.EmitStvec(Op.Rd);
  253. }
  254. public static void Uaddw_V(AILEmitterCtx Context)
  255. {
  256. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  257. Context.EmitLdvec(Op.Rn);
  258. Context.EmitLdvec(Op.Rm);
  259. Context.EmitLdc_I4(Op.Size);
  260. ASoftFallback.EmitCall(Context,
  261. nameof(ASoftFallback.Uaddw),
  262. nameof(ASoftFallback.Uaddw2));
  263. Context.EmitStvec(Op.Rd);
  264. }
  265. public static void Ucvtf_V(AILEmitterCtx Context)
  266. {
  267. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  268. Context.EmitLdvec(Op.Rn);
  269. if (Op.Size == 0)
  270. {
  271. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Ucvtf_V_F));
  272. }
  273. else if (Op.Size == 1)
  274. {
  275. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Ucvtf_V_D));
  276. }
  277. else
  278. {
  279. throw new InvalidOperationException();
  280. }
  281. Context.EmitStvec(Op.Rd);
  282. }
  283. public static void Umov_S(AILEmitterCtx Context)
  284. {
  285. AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
  286. Context.EmitLdvec(Op.Rn);
  287. Context.EmitLdc_I4(Op.DstIndex);
  288. Context.EmitLdc_I4(Op.Size);
  289. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
  290. Context.EmitStintzr(Op.Rd);
  291. }
  292. public static void Ushl_V(AILEmitterCtx Context) => EmitVectorUshl(Context);
  293. public static void Ushll_V(AILEmitterCtx Context)
  294. {
  295. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  296. Context.EmitLdvec(Op.Rn);
  297. Context.EmitLdc_I4(Op.Imm - (8 << Op.Size));
  298. Context.EmitLdc_I4(Op.Size);
  299. ASoftFallback.EmitCall(Context,
  300. nameof(ASoftFallback.Ushll),
  301. nameof(ASoftFallback.Ushll2));
  302. Context.EmitStvec(Op.Rd);
  303. }
  304. public static void Ushr_V(AILEmitterCtx Context)
  305. {
  306. EmitVectorShr(Context, ShrFlags.None);
  307. }
  308. public static void Usra_V(AILEmitterCtx Context)
  309. {
  310. EmitVectorShr(Context, ShrFlags.Accumulate);
  311. }
  312. public static void Uzp1_V(AILEmitterCtx Context)
  313. {
  314. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  315. Context.EmitLdvec(Op.Rn);
  316. Context.EmitLdvec(Op.Rm);
  317. Context.EmitLdc_I4(Op.Size);
  318. ASoftFallback.EmitCall(Context,
  319. nameof(ASoftFallback.Uzp1_V64),
  320. nameof(ASoftFallback.Uzp1_V128));
  321. Context.EmitStvec(Op.Rd);
  322. }
  323. public static void Xtn_V(AILEmitterCtx Context)
  324. {
  325. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  326. Context.EmitLdvec(Op.Rn);
  327. Context.EmitLdc_I4(Op.Size);
  328. ASoftFallback.EmitCall(Context,
  329. nameof(ASoftFallback.Xtn),
  330. nameof(ASoftFallback.Xtn2));
  331. Context.EmitStvec(Op.Rd);
  332. }
  333. private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad)
  334. {
  335. AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp;
  336. int Offset = 0;
  337. for (int Rep = 0; Rep < Op.Reps; Rep++)
  338. for (int Elem = 0; Elem < Op.Elems; Elem++)
  339. for (int SElem = 0; SElem < Op.SElems; SElem++)
  340. {
  341. int Rtt = (Op.Rt + Rep + SElem) & 0x1f;
  342. if (IsLoad)
  343. {
  344. Context.EmitLdvec(Rtt);
  345. Context.EmitLdc_I4(Elem);
  346. Context.EmitLdc_I4(Op.Size);
  347. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  348. Context.EmitLdint(Op.Rn);
  349. Context.EmitLdc_I8(Offset);
  350. Context.Emit(OpCodes.Add);
  351. EmitReadZxCall(Context, Op.Size);
  352. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  353. Context.EmitStvec(Rtt);
  354. if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1)
  355. {
  356. EmitVectorZeroUpper(Context, Rtt);
  357. }
  358. }
  359. else
  360. {
  361. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  362. Context.EmitLdint(Op.Rn);
  363. Context.EmitLdc_I8(Offset);
  364. Context.Emit(OpCodes.Add);
  365. Context.EmitLdvec(Rtt);
  366. Context.EmitLdc_I4(Elem);
  367. Context.EmitLdc_I4(Op.Size);
  368. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
  369. EmitWriteCall(Context, Op.Size);
  370. }
  371. Offset += 1 << Op.Size;
  372. }
  373. if (Op.WBack)
  374. {
  375. Context.EmitLdint(Op.Rn);
  376. if (Op.Rm != ARegisters.ZRIndex)
  377. {
  378. Context.EmitLdint(Op.Rm);
  379. }
  380. else
  381. {
  382. Context.EmitLdc_I8(Offset);
  383. }
  384. Context.Emit(OpCodes.Add);
  385. Context.EmitStint(Op.Rn);
  386. }
  387. }
  388. private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad)
  389. {
  390. AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp;
  391. //TODO: Replicate mode.
  392. int Offset = 0;
  393. for (int SElem = 0; SElem < Op.SElems; SElem++)
  394. {
  395. int Rt = (Op.Rt + SElem) & 0x1f;
  396. if (IsLoad)
  397. {
  398. Context.EmitLdvec(Rt);
  399. Context.EmitLdc_I4(Op.Index);
  400. Context.EmitLdc_I4(Op.Size);
  401. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  402. Context.EmitLdint(Op.Rn);
  403. Context.EmitLdc_I8(Offset);
  404. Context.Emit(OpCodes.Add);
  405. EmitReadZxCall(Context, Op.Size);
  406. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  407. Context.EmitStvec(Rt);
  408. if (Op.RegisterSize == ARegisterSize.SIMD64)
  409. {
  410. EmitVectorZeroUpper(Context, Rt);
  411. }
  412. }
  413. else
  414. {
  415. Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
  416. Context.EmitLdint(Op.Rn);
  417. Context.EmitLdc_I8(Offset);
  418. Context.Emit(OpCodes.Add);
  419. Context.EmitLdvec(Rt);
  420. Context.EmitLdc_I4(Op.Index);
  421. Context.EmitLdc_I4(Op.Size);
  422. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ExtractVec));
  423. EmitWriteCall(Context, Op.Size);
  424. }
  425. Offset += 1 << Op.Size;
  426. }
  427. if (Op.WBack)
  428. {
  429. Context.EmitLdint(Op.Rn);
  430. if (Op.Rm != ARegisters.ZRIndex)
  431. {
  432. Context.EmitLdint(Op.Rm);
  433. }
  434. else
  435. {
  436. Context.EmitLdc_I8(Offset);
  437. }
  438. Context.Emit(OpCodes.Add);
  439. Context.EmitStint(Op.Rn);
  440. }
  441. }
  442. private static void EmitVectorAddv(AILEmitterCtx Context)
  443. {
  444. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  445. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  446. EmitVectorZeroLower(Context, Op.Rd);
  447. EmitVectorZeroUpper(Context, Op.Rd);
  448. Context.EmitLdvec(Op.Rd);
  449. Context.EmitLdc_I4(0);
  450. Context.EmitLdc_I4(Op.Size);
  451. EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size);
  452. for (int Index = 1; Index < (Bytes >> Op.Size); Index++)
  453. {
  454. EmitVectorExtractZx(Context, Op.Rn, Op.Size, Index);
  455. Context.Emit(OpCodes.Add);
  456. }
  457. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  458. Context.EmitStvec(Op.Rd);
  459. }
  460. private static void EmitVectorBic(AILEmitterCtx Context)
  461. {
  462. EmitVectorBinaryZx(Context, () =>
  463. {
  464. Context.Emit(OpCodes.Not);
  465. Context.Emit(OpCodes.And);
  466. });
  467. }
  468. private static void EmitVectorBsl(AILEmitterCtx Context)
  469. {
  470. EmitVectorTernaryZx(Context, () =>
  471. {
  472. Context.EmitSttmp();
  473. Context.EmitLdtmp();
  474. Context.Emit(OpCodes.Xor);
  475. Context.Emit(OpCodes.And);
  476. Context.EmitLdtmp();
  477. Context.Emit(OpCodes.Xor);
  478. });
  479. }
  480. private static void EmitVectorMla(AILEmitterCtx Context)
  481. {
  482. EmitVectorTernaryZx(Context, () =>
  483. {
  484. Context.Emit(OpCodes.Mul);
  485. Context.Emit(OpCodes.Add);
  486. });
  487. }
  488. private static void EmitVectorSmax(AILEmitterCtx Context)
  489. {
  490. Type[] Types = new Type[] { typeof(long), typeof(long) };
  491. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Max), Types);
  492. EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo));
  493. }
  494. private static void EmitVectorSmin(AILEmitterCtx Context)
  495. {
  496. Type[] Types = new Type[] { typeof(long), typeof(long) };
  497. MethodInfo MthdInfo = typeof(Math).GetMethod(nameof(Math.Min), Types);
  498. EmitVectorBinarySx(Context, () => Context.EmitCall(MthdInfo));
  499. }
  500. private static void EmitVectorSshl(AILEmitterCtx Context) => EmitVectorShl(Context, true);
  501. private static void EmitVectorUshl(AILEmitterCtx Context) => EmitVectorShl(Context, false);
  502. private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
  503. {
  504. //This instruction shifts the value on vector A by the number of bits
  505. //specified on the signed, lower 8 bits of vector B. If the shift value
  506. //is greater or equal to the data size of each lane, then the result is zero.
  507. //Additionally, negative shifts produces right shifts by the negated shift value.
  508. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  509. int MaxShift = 8 << Op.Size;
  510. Action Emit = () =>
  511. {
  512. AILLabel LblShl = new AILLabel();
  513. AILLabel LblZero = new AILLabel();
  514. AILLabel LblEnd = new AILLabel();
  515. void EmitShift(OpCode ILOp)
  516. {
  517. Context.Emit(OpCodes.Dup);
  518. Context.EmitLdc_I4(MaxShift);
  519. Context.Emit(OpCodes.Bge_S, LblZero);
  520. Context.Emit(ILOp);
  521. Context.Emit(OpCodes.Br_S, LblEnd);
  522. }
  523. Context.Emit(OpCodes.Conv_I1);
  524. Context.Emit(OpCodes.Dup);
  525. Context.EmitLdc_I4(0);
  526. Context.Emit(OpCodes.Bge_S, LblShl);
  527. Context.Emit(OpCodes.Neg);
  528. EmitShift(Signed
  529. ? OpCodes.Shr
  530. : OpCodes.Shr_Un);
  531. Context.MarkLabel(LblShl);
  532. EmitShift(OpCodes.Shl);
  533. Context.MarkLabel(LblZero);
  534. Context.Emit(OpCodes.Pop);
  535. Context.Emit(OpCodes.Pop);
  536. Context.EmitLdc_I8(0);
  537. Context.MarkLabel(LblEnd);
  538. };
  539. if (Signed)
  540. {
  541. EmitVectorBinarySx(Context, Emit);
  542. }
  543. else
  544. {
  545. EmitVectorBinaryZx(Context, Emit);
  546. }
  547. }
  548. private enum ShrFlags
  549. {
  550. None = 0,
  551. Signed = 1 << 0,
  552. Rounding = 1 << 1,
  553. Accumulate = 1 << 2
  554. }
  555. private static void EmitVectorShr(AILEmitterCtx Context, ShrFlags Flags)
  556. {
  557. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  558. int Shift = (8 << (Op.Size + 1)) - Op.Imm;
  559. if (Flags.HasFlag(ShrFlags.Accumulate))
  560. {
  561. Action Emit = () =>
  562. {
  563. Context.EmitLdc_I4(Shift);
  564. Context.Emit(OpCodes.Shr_Un);
  565. Context.Emit(OpCodes.Add);
  566. };
  567. EmitVectorOp(Context, Emit, OperFlags.RdRn, Signed: false);
  568. }
  569. else
  570. {
  571. EmitVectorUnaryZx(Context, () =>
  572. {
  573. Context.EmitLdc_I4(Shift);
  574. Context.Emit(OpCodes.Shr_Un);
  575. });
  576. }
  577. }
  578. private static void EmitVectorFcvts(AILEmitterCtx Context)
  579. {
  580. EmitVectorFcvtOp(Context, Signed: true);
  581. }
  582. private static void EmitVectorFcvtu(AILEmitterCtx Context)
  583. {
  584. EmitVectorFcvtOp(Context, Signed: false);
  585. }
  586. private static void EmitVectorScvtf(AILEmitterCtx Context)
  587. {
  588. EmitVectorCvtfOp(Context, Signed: true);
  589. }
  590. private static void EmitVectorUcvtf(AILEmitterCtx Context)
  591. {
  592. EmitVectorCvtfOp(Context, Signed: false);
  593. }
  594. private static void EmitVectorFcvtOp(AILEmitterCtx Context, bool Signed)
  595. {
  596. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  597. int SizeF = Op.Size & 1;
  598. int SizeI = SizeF + 2;
  599. int FBits = GetFBits(Context);
  600. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  601. for (int Index = 0; Index < (Bytes >> SizeI); Index++)
  602. {
  603. EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
  604. Context.EmitLdc_I4(FBits);
  605. if (SizeF == 0)
  606. {
  607. ASoftFallback.EmitCall(Context, Signed
  608. ? nameof(ASoftFallback.SatSingleToInt32)
  609. : nameof(ASoftFallback.SatSingleToUInt32));
  610. }
  611. else if (SizeF == 1)
  612. {
  613. ASoftFallback.EmitCall(Context, Signed
  614. ? nameof(ASoftFallback.SatDoubleToInt64)
  615. : nameof(ASoftFallback.SatDoubleToUInt64));
  616. }
  617. EmitVectorInsert(Context, Op.Rd, Index, SizeI);
  618. }
  619. if (Op.RegisterSize == ARegisterSize.SIMD64)
  620. {
  621. EmitVectorZeroUpper(Context, Op.Rd);
  622. }
  623. }
  624. private static void EmitVectorCvtfOp(AILEmitterCtx Context, bool Signed)
  625. {
  626. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  627. int SizeF = Op.Size & 1;
  628. int SizeI = SizeF + 2;
  629. int FBits = GetFBits(Context);
  630. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  631. for (int Index = 0; Index < (Bytes >> SizeI); Index++)
  632. {
  633. EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed);
  634. Context.EmitLdc_I4(FBits);
  635. if (SizeF == 0)
  636. {
  637. Context.Emit(OpCodes.Conv_I4);
  638. ASoftFallback.EmitCall(Context, Signed
  639. ? nameof(ASoftFallback.Int32ToSingle)
  640. : nameof(ASoftFallback.UInt32ToSingle));
  641. }
  642. else if (SizeF == 1)
  643. {
  644. ASoftFallback.EmitCall(Context, Signed
  645. ? nameof(ASoftFallback.Int64ToDouble)
  646. : nameof(ASoftFallback.UInt64ToDouble));
  647. }
  648. EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
  649. }
  650. if (Op.RegisterSize == ARegisterSize.SIMD64)
  651. {
  652. EmitVectorZeroUpper(Context, Op.Rd);
  653. }
  654. }
  655. private static int GetFBits(AILEmitterCtx Context)
  656. {
  657. if (Context.CurrOp is AOpCodeSimdShImm Op)
  658. {
  659. return (8 << (Op.Size + 1)) - Op.Imm;
  660. }
  661. return 0;
  662. }
  663. private static void EmitVectorBinaryFOp(AILEmitterCtx Context, OpCode ILOp)
  664. {
  665. EmitVectorBinaryFOp(Context, () => Context.Emit(ILOp));
  666. }
  667. private static void EmitVectorBinaryFOp(AILEmitterCtx Context, Action Emit)
  668. {
  669. AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
  670. int SizeF = Op.Size & 1;
  671. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  672. for (int Index = 0; Index < (Bytes >> SizeF + 2); Index++)
  673. {
  674. EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
  675. EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
  676. Emit();
  677. EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
  678. }
  679. if (Op.RegisterSize == ARegisterSize.SIMD64)
  680. {
  681. EmitVectorZeroUpper(Context, Op.Rd);
  682. }
  683. }
  684. private static void EmitVectorUnarySx(AILEmitterCtx Context, OpCode ILOp)
  685. {
  686. EmitVectorUnarySx(Context, () => Context.Emit(ILOp));
  687. }
  688. private static void EmitVectorUnaryZx(AILEmitterCtx Context, OpCode ILOp)
  689. {
  690. EmitVectorUnaryZx(Context, () => Context.Emit(ILOp));
  691. }
  692. private static void EmitVectorBinaryZx(AILEmitterCtx Context, OpCode ILOp)
  693. {
  694. EmitVectorBinaryZx(Context, () => Context.Emit(ILOp));
  695. }
  696. private static void EmitVectorUnarySx(AILEmitterCtx Context, Action Emit)
  697. {
  698. EmitVectorOp(Context, Emit, OperFlags.Rn, true);
  699. }
  700. private static void EmitVectorBinarySx(AILEmitterCtx Context, Action Emit)
  701. {
  702. EmitVectorOp(Context, Emit, OperFlags.RnRm, true);
  703. }
  704. private static void EmitVectorUnaryZx(AILEmitterCtx Context, Action Emit)
  705. {
  706. EmitVectorOp(Context, Emit, OperFlags.Rn, false);
  707. }
  708. private static void EmitVectorBinaryZx(AILEmitterCtx Context, Action Emit)
  709. {
  710. EmitVectorOp(Context, Emit, OperFlags.RnRm, false);
  711. }
  712. private static void EmitVectorTernaryZx(AILEmitterCtx Context, Action Emit)
  713. {
  714. EmitVectorOp(Context, Emit, OperFlags.RdRnRm, false);
  715. }
  716. [Flags]
  717. private enum OperFlags
  718. {
  719. Rd = 1 << 0,
  720. Rn = 1 << 1,
  721. Rm = 1 << 2,
  722. RnRm = Rn | Rm,
  723. RdRn = Rd | Rn,
  724. RdRnRm = Rd | Rn | Rm
  725. }
  726. private static void EmitVectorOp(AILEmitterCtx Context, Action Emit, OperFlags Opers, bool Signed)
  727. {
  728. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  729. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  730. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  731. {
  732. Context.EmitLdvec(Op.Rd);
  733. Context.EmitLdc_I4(Index);
  734. Context.EmitLdc_I4(Op.Size);
  735. if (Opers.HasFlag(OperFlags.Rd))
  736. {
  737. EmitVectorExtract(Context, Op.Rd, Index, Op.Size, Signed);
  738. }
  739. if (Opers.HasFlag(OperFlags.Rn))
  740. {
  741. EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
  742. }
  743. if (Opers.HasFlag(OperFlags.Rm))
  744. {
  745. EmitVectorExtract(Context, ((AOpCodeSimdReg)Op).Rm, Index, Op.Size, Signed);
  746. }
  747. Emit();
  748. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  749. Context.EmitStvec(Op.Rd);
  750. }
  751. if (Op.RegisterSize == ARegisterSize.SIMD64)
  752. {
  753. EmitVectorZeroUpper(Context, Op.Rd);
  754. }
  755. }
  756. private static void EmitVectorImmBinarySx(AILEmitterCtx Context, OpCode ILOp, long Imm)
  757. {
  758. EmitVectorImmBinarySx(Context, () => Context.Emit(ILOp), Imm);
  759. }
  760. private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, OpCode ILOp, long Imm)
  761. {
  762. EmitVectorImmBinaryZx(Context, () => Context.Emit(ILOp), Imm);
  763. }
  764. private static void EmitVectorImmBinarySx(AILEmitterCtx Context, Action Emit, long Imm)
  765. {
  766. EmitVectorImmBinaryOp(Context, Emit, Imm, true);
  767. }
  768. private static void EmitVectorImmBinaryZx(AILEmitterCtx Context, Action Emit, long Imm)
  769. {
  770. EmitVectorImmBinaryOp(Context, Emit, Imm, false);
  771. }
  772. private static void EmitVectorImmBinaryOp(AILEmitterCtx Context, Action Emit, long Imm, bool Signed)
  773. {
  774. AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
  775. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  776. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  777. {
  778. Context.EmitLdvec(Op.Rd);
  779. Context.EmitLdc_I4(Index);
  780. Context.EmitLdc_I4(Op.Size);
  781. EmitVectorExtract(Context, Op.Rn, Index, Op.Size, Signed);
  782. Context.EmitLdc_I8(Imm);
  783. Emit();
  784. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  785. Context.EmitStvec(Op.Rd);
  786. }
  787. if (Op.RegisterSize == ARegisterSize.SIMD64)
  788. {
  789. EmitVectorZeroUpper(Context, Op.Rd);
  790. }
  791. }
  792. private static void EmitVectorCmp(AILEmitterCtx Context, OpCode ILOp)
  793. {
  794. AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
  795. int Bytes = Context.CurrOp.GetBitsCount() >> 3;
  796. ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
  797. for (int Index = 0; Index < (Bytes >> Op.Size); Index++)
  798. {
  799. EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size);
  800. if (Op is AOpCodeSimdReg BinOp)
  801. {
  802. EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size);
  803. }
  804. else
  805. {
  806. Context.EmitLdc_I8(0);
  807. }
  808. AILLabel LblTrue = new AILLabel();
  809. AILLabel LblEnd = new AILLabel();
  810. Context.Emit(ILOp, LblTrue);
  811. EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
  812. Context.Emit(OpCodes.Br_S, LblEnd);
  813. Context.MarkLabel(LblTrue);
  814. EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
  815. Context.MarkLabel(LblEnd);
  816. }
  817. if (Op.RegisterSize == ARegisterSize.SIMD64)
  818. {
  819. EmitVectorZeroUpper(Context, Op.Rd);
  820. }
  821. }
  822. private static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size)
  823. {
  824. Context.EmitLdvec(Reg);
  825. Context.EmitLdc_I4(Index);
  826. if (Size == 0)
  827. {
  828. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractSingle));
  829. }
  830. else if (Size == 1)
  831. {
  832. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorExtractDouble));
  833. }
  834. else
  835. {
  836. throw new ArgumentOutOfRangeException(nameof(Size));
  837. }
  838. }
  839. private static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size)
  840. {
  841. EmitVectorExtract(Context, Reg, Index, Size, true);
  842. }
  843. private static void EmitVectorExtractZx(AILEmitterCtx Context, int Reg, int Index, int Size)
  844. {
  845. EmitVectorExtract(Context, Reg, Index, Size, false);
  846. }
  847. private static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed)
  848. {
  849. IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
  850. Context.EmitLdvec(Reg);
  851. Context.EmitLdc_I4(Index);
  852. Context.EmitLdc_I4(Size);
  853. ASoftFallback.EmitCall(Context, Signed
  854. ? nameof(ASoftFallback.ExtractSVec)
  855. : nameof(ASoftFallback.ExtractVec));
  856. }
  857. private static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd)
  858. {
  859. EmitVectorInsert(Context, Rd, 0, 3, 0);
  860. }
  861. private static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd)
  862. {
  863. EmitVectorInsert(Context, Rd, 1, 3, 0);
  864. }
  865. private static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size)
  866. {
  867. Context.EmitLdvec(Reg);
  868. Context.EmitLdc_I4(Index);
  869. if (Size == 0)
  870. {
  871. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertSingle));
  872. }
  873. else if (Size == 1)
  874. {
  875. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertDouble));
  876. }
  877. else
  878. {
  879. throw new ArgumentOutOfRangeException(nameof(Size));
  880. }
  881. Context.EmitStvec(Reg);
  882. }
  883. private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size)
  884. {
  885. Context.EmitLdvec(Reg);
  886. Context.EmitLdc_I4(Index);
  887. Context.EmitLdc_I4(Size);
  888. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.VectorInsertInt));
  889. Context.EmitStvec(Reg);
  890. }
  891. private static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value)
  892. {
  893. Context.EmitLdvec(Reg);
  894. Context.EmitLdc_I4(Index);
  895. Context.EmitLdc_I4(Size);
  896. Context.EmitLdc_I8(Value);
  897. ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InsertVec));
  898. Context.EmitStvec(Reg);
  899. }
  900. }
  901. }