ShaderDecodeAlu.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299
  1. using System;
  2. using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
  3. namespace Ryujinx.Graphics.Gal.Shader
  4. {
  5. static partial class ShaderDecode
  6. {
  7. private enum HalfOutputType
  8. {
  9. PackedFp16,
  10. Fp32,
  11. MergeH0,
  12. MergeH1
  13. }
  14. public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position)
  15. {
  16. EmitBfe(Block, OpCode, ShaderOper.CR);
  17. }
  18. public static void Bfe_I(ShaderIrBlock Block, long OpCode, int Position)
  19. {
  20. EmitBfe(Block, OpCode, ShaderOper.Imm);
  21. }
  22. public static void Bfe_R(ShaderIrBlock Block, long OpCode, int Position)
  23. {
  24. EmitBfe(Block, OpCode, ShaderOper.RR);
  25. }
  26. public static void Fadd_C(ShaderIrBlock Block, long OpCode, int Position)
  27. {
  28. EmitFadd(Block, OpCode, ShaderOper.CR);
  29. }
  30. public static void Fadd_I(ShaderIrBlock Block, long OpCode, int Position)
  31. {
  32. EmitFadd(Block, OpCode, ShaderOper.Immf);
  33. }
  34. public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position)
  35. {
  36. ShaderIrNode OperA = OpCode.Gpr8();
  37. ShaderIrNode OperB = OpCode.Immf32_20();
  38. bool NegB = OpCode.Read(53);
  39. bool AbsA = OpCode.Read(54);
  40. bool NegA = OpCode.Read(56);
  41. bool AbsB = OpCode.Read(57);
  42. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  43. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  44. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
  45. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  46. }
  47. public static void Fadd_R(ShaderIrBlock Block, long OpCode, int Position)
  48. {
  49. EmitFadd(Block, OpCode, ShaderOper.RR);
  50. }
  51. public static void Ffma_CR(ShaderIrBlock Block, long OpCode, int Position)
  52. {
  53. EmitFfma(Block, OpCode, ShaderOper.CR);
  54. }
  55. public static void Ffma_I(ShaderIrBlock Block, long OpCode, int Position)
  56. {
  57. EmitFfma(Block, OpCode, ShaderOper.Immf);
  58. }
  59. public static void Ffma_RC(ShaderIrBlock Block, long OpCode, int Position)
  60. {
  61. EmitFfma(Block, OpCode, ShaderOper.RC);
  62. }
  63. public static void Ffma_RR(ShaderIrBlock Block, long OpCode, int Position)
  64. {
  65. EmitFfma(Block, OpCode, ShaderOper.RR);
  66. }
  67. public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, int Position)
  68. {
  69. EmitFmnmx(Block, OpCode, ShaderOper.CR);
  70. }
  71. public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, int Position)
  72. {
  73. EmitFmnmx(Block, OpCode, ShaderOper.Immf);
  74. }
  75. public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, int Position)
  76. {
  77. EmitFmnmx(Block, OpCode, ShaderOper.RR);
  78. }
  79. public static void Fmul_I32(ShaderIrBlock Block, long OpCode, int Position)
  80. {
  81. ShaderIrNode OperA = OpCode.Gpr8();
  82. ShaderIrNode OperB = OpCode.Immf32_20();
  83. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
  84. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  85. }
  86. public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position)
  87. {
  88. EmitFmul(Block, OpCode, ShaderOper.CR);
  89. }
  90. public static void Fmul_I(ShaderIrBlock Block, long OpCode, int Position)
  91. {
  92. EmitFmul(Block, OpCode, ShaderOper.Immf);
  93. }
  94. public static void Fmul_R(ShaderIrBlock Block, long OpCode, int Position)
  95. {
  96. EmitFmul(Block, OpCode, ShaderOper.RR);
  97. }
  98. public static void Fset_C(ShaderIrBlock Block, long OpCode, int Position)
  99. {
  100. EmitFset(Block, OpCode, ShaderOper.CR);
  101. }
  102. public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position)
  103. {
  104. EmitFset(Block, OpCode, ShaderOper.Immf);
  105. }
  106. public static void Fset_R(ShaderIrBlock Block, long OpCode, int Position)
  107. {
  108. EmitFset(Block, OpCode, ShaderOper.RR);
  109. }
  110. public static void Fsetp_C(ShaderIrBlock Block, long OpCode, int Position)
  111. {
  112. EmitFsetp(Block, OpCode, ShaderOper.CR);
  113. }
  114. public static void Fsetp_I(ShaderIrBlock Block, long OpCode, int Position)
  115. {
  116. EmitFsetp(Block, OpCode, ShaderOper.Immf);
  117. }
  118. public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position)
  119. {
  120. EmitFsetp(Block, OpCode, ShaderOper.RR);
  121. }
  122. public static void Hadd2_R(ShaderIrBlock Block, long OpCode, int Position)
  123. {
  124. EmitBinaryHalfOp(Block, OpCode, ShaderIrInst.Fadd);
  125. }
  126. public static void Hmul2_R(ShaderIrBlock Block, long OpCode, int Position)
  127. {
  128. EmitBinaryHalfOp(Block, OpCode, ShaderIrInst.Fmul);
  129. }
  130. public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position)
  131. {
  132. EmitIadd(Block, OpCode, ShaderOper.CR);
  133. }
  134. public static void Iadd_I(ShaderIrBlock Block, long OpCode, int Position)
  135. {
  136. EmitIadd(Block, OpCode, ShaderOper.Imm);
  137. }
  138. public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position)
  139. {
  140. ShaderIrNode OperA = OpCode.Gpr8();
  141. ShaderIrNode OperB = OpCode.Imm32_20();
  142. bool NegA = OpCode.Read(56);
  143. OperA = GetAluIneg(OperA, NegA);
  144. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);
  145. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  146. }
  147. public static void Iadd_R(ShaderIrBlock Block, long OpCode, int Position)
  148. {
  149. EmitIadd(Block, OpCode, ShaderOper.RR);
  150. }
  151. public static void Iadd3_C(ShaderIrBlock Block, long OpCode, int Position)
  152. {
  153. EmitIadd3(Block, OpCode, ShaderOper.CR);
  154. }
  155. public static void Iadd3_I(ShaderIrBlock Block, long OpCode, int Position)
  156. {
  157. EmitIadd3(Block, OpCode, ShaderOper.Imm);
  158. }
  159. public static void Iadd3_R(ShaderIrBlock Block, long OpCode, int Position)
  160. {
  161. EmitIadd3(Block, OpCode, ShaderOper.RR);
  162. }
  163. public static void Imnmx_C(ShaderIrBlock Block, long OpCode, int Position)
  164. {
  165. EmitImnmx(Block, OpCode, ShaderOper.CR);
  166. }
  167. public static void Imnmx_I(ShaderIrBlock Block, long OpCode, int Position)
  168. {
  169. EmitImnmx(Block, OpCode, ShaderOper.Imm);
  170. }
  171. public static void Imnmx_R(ShaderIrBlock Block, long OpCode, int Position)
  172. {
  173. EmitImnmx(Block, OpCode, ShaderOper.RR);
  174. }
  175. public static void Ipa(ShaderIrBlock Block, long OpCode, int Position)
  176. {
  177. ShaderIrNode OperA = OpCode.Abuf28();
  178. ShaderIrNode OperB = OpCode.Gpr20();
  179. ShaderIpaMode Mode = (ShaderIpaMode)(OpCode.Read(54, 3));
  180. ShaderIrMetaIpa Meta = new ShaderIrMetaIpa(Mode);
  181. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ipa, OperA, OperB, null, Meta);
  182. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  183. }
  184. public static void Iscadd_C(ShaderIrBlock Block, long OpCode, int Position)
  185. {
  186. EmitIscadd(Block, OpCode, ShaderOper.CR);
  187. }
  188. public static void Iscadd_I(ShaderIrBlock Block, long OpCode, int Position)
  189. {
  190. EmitIscadd(Block, OpCode, ShaderOper.Imm);
  191. }
  192. public static void Iscadd_R(ShaderIrBlock Block, long OpCode, int Position)
  193. {
  194. EmitIscadd(Block, OpCode, ShaderOper.RR);
  195. }
  196. public static void Iset_C(ShaderIrBlock Block, long OpCode, int Position)
  197. {
  198. EmitIset(Block, OpCode, ShaderOper.CR);
  199. }
  200. public static void Iset_I(ShaderIrBlock Block, long OpCode, int Position)
  201. {
  202. EmitIset(Block, OpCode, ShaderOper.Imm);
  203. }
  204. public static void Iset_R(ShaderIrBlock Block, long OpCode, int Position)
  205. {
  206. EmitIset(Block, OpCode, ShaderOper.RR);
  207. }
  208. public static void Isetp_C(ShaderIrBlock Block, long OpCode, int Position)
  209. {
  210. EmitIsetp(Block, OpCode, ShaderOper.CR);
  211. }
  212. public static void Isetp_I(ShaderIrBlock Block, long OpCode, int Position)
  213. {
  214. EmitIsetp(Block, OpCode, ShaderOper.Imm);
  215. }
  216. public static void Isetp_R(ShaderIrBlock Block, long OpCode, int Position)
  217. {
  218. EmitIsetp(Block, OpCode, ShaderOper.RR);
  219. }
  220. public static void Lop_I32(ShaderIrBlock Block, long OpCode, int Position)
  221. {
  222. int SubOp = OpCode.Read(53, 3);
  223. bool InvA = OpCode.Read(55);
  224. bool InvB = OpCode.Read(56);
  225. ShaderIrInst Inst = 0;
  226. switch (SubOp)
  227. {
  228. case 0: Inst = ShaderIrInst.And; break;
  229. case 1: Inst = ShaderIrInst.Or; break;
  230. case 2: Inst = ShaderIrInst.Xor; break;
  231. }
  232. ShaderIrNode OperB = GetAluNot(OpCode.Imm32_20(), InvB);
  233. //SubOp == 3 is pass, used by the not instruction
  234. //which just moves the inverted register value.
  235. if (SubOp < 3)
  236. {
  237. ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA);
  238. ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB);
  239. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  240. }
  241. else
  242. {
  243. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperB)));
  244. }
  245. }
  246. public static void Lop_C(ShaderIrBlock Block, long OpCode, int Position)
  247. {
  248. EmitLop(Block, OpCode, ShaderOper.CR);
  249. }
  250. public static void Lop_I(ShaderIrBlock Block, long OpCode, int Position)
  251. {
  252. EmitLop(Block, OpCode, ShaderOper.Imm);
  253. }
  254. public static void Lop_R(ShaderIrBlock Block, long OpCode, int Position)
  255. {
  256. EmitLop(Block, OpCode, ShaderOper.RR);
  257. }
  258. public static void Mufu(ShaderIrBlock Block, long OpCode, int Position)
  259. {
  260. int SubOp = OpCode.Read(20, 0xf);
  261. bool AbsA = OpCode.Read(46);
  262. bool NegA = OpCode.Read(48);
  263. ShaderIrInst Inst = 0;
  264. switch (SubOp)
  265. {
  266. case 0: Inst = ShaderIrInst.Fcos; break;
  267. case 1: Inst = ShaderIrInst.Fsin; break;
  268. case 2: Inst = ShaderIrInst.Fex2; break;
  269. case 3: Inst = ShaderIrInst.Flg2; break;
  270. case 4: Inst = ShaderIrInst.Frcp; break;
  271. case 5: Inst = ShaderIrInst.Frsq; break;
  272. case 8: Inst = ShaderIrInst.Fsqrt; break;
  273. default: throw new NotImplementedException(SubOp.ToString());
  274. }
  275. ShaderIrNode OperA = OpCode.Gpr8();
  276. ShaderIrOp Op = new ShaderIrOp(Inst, GetAluFabsFneg(OperA, AbsA, NegA));
  277. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  278. }
  279. public static void Psetp(ShaderIrBlock Block, long OpCode, int Position)
  280. {
  281. bool NegA = OpCode.Read(15);
  282. bool NegB = OpCode.Read(32);
  283. bool NegP = OpCode.Read(42);
  284. ShaderIrInst LopInst = OpCode.BLop24();
  285. ShaderIrNode OperA = OpCode.Pred12();
  286. ShaderIrNode OperB = OpCode.Pred29();
  287. if (NegA)
  288. {
  289. OperA = new ShaderIrOp(ShaderIrInst.Bnot, OperA);
  290. }
  291. if (NegB)
  292. {
  293. OperB = new ShaderIrOp(ShaderIrInst.Bnot, OperB);
  294. }
  295. ShaderIrOp Op = new ShaderIrOp(LopInst, OperA, OperB);
  296. ShaderIrOperPred P0Node = OpCode.Pred3();
  297. ShaderIrOperPred P1Node = OpCode.Pred0();
  298. ShaderIrOperPred P2Node = OpCode.Pred39();
  299. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  300. LopInst = OpCode.BLop45();
  301. if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
  302. {
  303. return;
  304. }
  305. ShaderIrNode P2NNode = P2Node;
  306. if (NegP)
  307. {
  308. P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
  309. }
  310. Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);
  311. Op = new ShaderIrOp(LopInst, Op, P2NNode);
  312. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op)));
  313. Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
  314. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  315. }
  316. public static void Rro_C(ShaderIrBlock Block, long OpCode, int Position)
  317. {
  318. EmitRro(Block, OpCode, ShaderOper.CR);
  319. }
  320. public static void Rro_I(ShaderIrBlock Block, long OpCode, int Position)
  321. {
  322. EmitRro(Block, OpCode, ShaderOper.Immf);
  323. }
  324. public static void Rro_R(ShaderIrBlock Block, long OpCode, int Position)
  325. {
  326. EmitRro(Block, OpCode, ShaderOper.RR);
  327. }
  328. public static void Shl_C(ShaderIrBlock Block, long OpCode, int Position)
  329. {
  330. EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
  331. }
  332. public static void Shl_I(ShaderIrBlock Block, long OpCode, int Position)
  333. {
  334. EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl);
  335. }
  336. public static void Shl_R(ShaderIrBlock Block, long OpCode, int Position)
  337. {
  338. EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl);
  339. }
  340. public static void Shr_C(ShaderIrBlock Block, long OpCode, int Position)
  341. {
  342. EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode));
  343. }
  344. public static void Shr_I(ShaderIrBlock Block, long OpCode, int Position)
  345. {
  346. EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode));
  347. }
  348. public static void Shr_R(ShaderIrBlock Block, long OpCode, int Position)
  349. {
  350. EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode));
  351. }
  352. private static ShaderIrInst GetShrInst(long OpCode)
  353. {
  354. bool Signed = OpCode.Read(48);
  355. return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  356. }
  357. public static void Vmad(ShaderIrBlock Block, long OpCode, int Position)
  358. {
  359. ShaderIrNode OperA = OpCode.Gpr8();
  360. ShaderIrNode OperB;
  361. if (OpCode.Read(50))
  362. {
  363. OperB = OpCode.Gpr20();
  364. }
  365. else
  366. {
  367. OperB = OpCode.Imm19_20();
  368. }
  369. ShaderIrOperGpr OperC = OpCode.Gpr39();
  370. ShaderIrNode Tmp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB);
  371. ShaderIrNode Final = new ShaderIrOp(ShaderIrInst.Add, Tmp, OperC);
  372. int Shr = OpCode.Read(51, 3);
  373. if (Shr != 0)
  374. {
  375. int Shift = (Shr == 2) ? 15 : 7;
  376. Final = new ShaderIrOp(ShaderIrInst.Lsr, Final, new ShaderIrOperImm(Shift));
  377. }
  378. Block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c"));
  379. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final)));
  380. }
  381. public static void Xmad_CR(ShaderIrBlock Block, long OpCode, int Position)
  382. {
  383. EmitXmad(Block, OpCode, ShaderOper.CR);
  384. }
  385. public static void Xmad_I(ShaderIrBlock Block, long OpCode, int Position)
  386. {
  387. EmitXmad(Block, OpCode, ShaderOper.Imm);
  388. }
  389. public static void Xmad_RC(ShaderIrBlock Block, long OpCode, int Position)
  390. {
  391. EmitXmad(Block, OpCode, ShaderOper.RC);
  392. }
  393. public static void Xmad_RR(ShaderIrBlock Block, long OpCode, int Position)
  394. {
  395. EmitXmad(Block, OpCode, ShaderOper.RR);
  396. }
  397. private static void EmitAluBinary(
  398. ShaderIrBlock Block,
  399. long OpCode,
  400. ShaderOper Oper,
  401. ShaderIrInst Inst)
  402. {
  403. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  404. switch (Oper)
  405. {
  406. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  407. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  408. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  409. default: throw new ArgumentException(nameof(Oper));
  410. }
  411. ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
  412. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  413. }
  414. private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  415. {
  416. //TODO: Handle the case where position + length
  417. //is greater than the word size, in this case the sign bit
  418. //needs to be replicated to fill the remaining space.
  419. bool NegB = OpCode.Read(48);
  420. bool NegA = OpCode.Read(49);
  421. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  422. switch (Oper)
  423. {
  424. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  425. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  426. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  427. default: throw new ArgumentException(nameof(Oper));
  428. }
  429. ShaderIrNode Op;
  430. bool Signed = OpCode.Read(48); //?
  431. if (OperB is ShaderIrOperImm PosLen)
  432. {
  433. int Position = (PosLen.Value >> 0) & 0xff;
  434. int Length = (PosLen.Value >> 8) & 0xff;
  435. int LSh = 32 - (Position + Length);
  436. ShaderIrInst RightShift = Signed
  437. ? ShaderIrInst.Asr
  438. : ShaderIrInst.Lsr;
  439. Op = new ShaderIrOp(ShaderIrInst.Lsl, OperA, new ShaderIrOperImm(LSh));
  440. Op = new ShaderIrOp(RightShift, Op, new ShaderIrOperImm(LSh + Position));
  441. }
  442. else
  443. {
  444. ShaderIrOperImm Shift = new ShaderIrOperImm(8);
  445. ShaderIrOperImm Mask = new ShaderIrOperImm(0xff);
  446. ShaderIrNode OpPos, OpLen;
  447. OpPos = new ShaderIrOp(ShaderIrInst.And, OperB, Mask);
  448. OpLen = new ShaderIrOp(ShaderIrInst.Lsr, OperB, Shift);
  449. OpLen = new ShaderIrOp(ShaderIrInst.And, OpLen, Mask);
  450. Op = new ShaderIrOp(ShaderIrInst.Lsr, OperA, OpPos);
  451. Op = ExtendTo32(Op, Signed, OpLen);
  452. }
  453. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  454. }
  455. private static void EmitFadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  456. {
  457. bool NegB = OpCode.Read(45);
  458. bool AbsA = OpCode.Read(46);
  459. bool NegA = OpCode.Read(48);
  460. bool AbsB = OpCode.Read(49);
  461. bool Sat = OpCode.Read(50);
  462. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  463. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  464. switch (Oper)
  465. {
  466. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  467. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  468. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  469. default: throw new ArgumentException(nameof(Oper));
  470. }
  471. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  472. ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
  473. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
  474. }
  475. private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  476. {
  477. bool NegB = OpCode.Read(48);
  478. bool Sat = OpCode.Read(50);
  479. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  480. switch (Oper)
  481. {
  482. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  483. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  484. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  485. default: throw new ArgumentException(nameof(Oper));
  486. }
  487. OperB = GetAluFneg(OperB, NegB);
  488. ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
  489. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
  490. }
  491. private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  492. {
  493. bool NegB = OpCode.Read(48);
  494. bool NegC = OpCode.Read(49);
  495. bool Sat = OpCode.Read(50);
  496. ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
  497. switch (Oper)
  498. {
  499. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  500. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  501. case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
  502. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  503. default: throw new ArgumentException(nameof(Oper));
  504. }
  505. OperB = GetAluFneg(OperB, NegB);
  506. if (Oper == ShaderOper.RC)
  507. {
  508. OperC = GetAluFneg(OpCode.Cbuf34(), NegC);
  509. }
  510. else
  511. {
  512. OperC = GetAluFneg(OpCode.Gpr39(), NegC);
  513. }
  514. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
  515. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
  516. }
  517. private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  518. {
  519. ShaderIrNode OperA = OpCode.Gpr8();
  520. ShaderIrNode OperB;
  521. switch (Oper)
  522. {
  523. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  524. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  525. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  526. default: throw new ArgumentException(nameof(Oper));
  527. }
  528. bool NegA = OpCode.Read(49);
  529. bool NegB = OpCode.Read(48);
  530. OperA = GetAluIneg(OperA, NegA);
  531. OperB = GetAluIneg(OperB, NegB);
  532. ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB);
  533. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  534. }
  535. private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  536. {
  537. int Mode = OpCode.Read(37, 3);
  538. bool Neg1 = OpCode.Read(51);
  539. bool Neg2 = OpCode.Read(50);
  540. bool Neg3 = OpCode.Read(49);
  541. int Height1 = OpCode.Read(35, 3);
  542. int Height2 = OpCode.Read(33, 3);
  543. int Height3 = OpCode.Read(31, 3);
  544. ShaderIrNode OperB;
  545. switch (Oper)
  546. {
  547. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  548. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  549. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  550. default: throw new ArgumentException(nameof(Oper));
  551. }
  552. ShaderIrNode ApplyHeight(ShaderIrNode Src, int Height)
  553. {
  554. if (Oper != ShaderOper.RR)
  555. {
  556. return Src;
  557. }
  558. switch (Height)
  559. {
  560. case 0: return Src;
  561. case 1: return new ShaderIrOp(ShaderIrInst.And, Src, new ShaderIrOperImm(0xffff));
  562. case 2: return new ShaderIrOp(ShaderIrInst.Lsr, Src, new ShaderIrOperImm(16));
  563. default: throw new InvalidOperationException();
  564. }
  565. }
  566. ShaderIrNode Src1 = GetAluIneg(ApplyHeight(OpCode.Gpr8(), Height1), Neg1);
  567. ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2);
  568. ShaderIrNode Src3 = GetAluIneg(ApplyHeight(OpCode.Gpr39(), Height3), Neg3);
  569. ShaderIrOp Sum = new ShaderIrOp(ShaderIrInst.Add, Src1, Src2);
  570. if (Oper == ShaderOper.RR)
  571. {
  572. switch (Mode)
  573. {
  574. case 1: Sum = new ShaderIrOp(ShaderIrInst.Lsr, Sum, new ShaderIrOperImm(16)); break;
  575. case 2: Sum = new ShaderIrOp(ShaderIrInst.Lsl, Sum, new ShaderIrOperImm(16)); break;
  576. }
  577. }
  578. //Note: Here there should be a "+ 1" when carry flag is set
  579. //but since carry is mostly ignored by other instructions, it's excluded for now
  580. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3))));
  581. }
  582. private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  583. {
  584. bool NegB = OpCode.Read(48);
  585. bool NegA = OpCode.Read(49);
  586. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  587. ShaderIrOperImm Scale = OpCode.Imm5_39();
  588. switch (Oper)
  589. {
  590. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  591. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  592. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  593. default: throw new ArgumentException(nameof(Oper));
  594. }
  595. OperA = GetAluIneg(OperA, NegA);
  596. OperB = GetAluIneg(OperB, NegB);
  597. ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale);
  598. ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp);
  599. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
  600. }
  601. private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  602. {
  603. EmitMnmx(Block, OpCode, true, Oper);
  604. }
  605. private static void EmitImnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  606. {
  607. EmitMnmx(Block, OpCode, false, Oper);
  608. }
  609. private static void EmitMnmx(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  610. {
  611. bool NegB = OpCode.Read(45);
  612. bool AbsA = OpCode.Read(46);
  613. bool NegA = OpCode.Read(48);
  614. bool AbsB = OpCode.Read(49);
  615. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  616. if (IsFloat)
  617. {
  618. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  619. }
  620. else
  621. {
  622. OperA = GetAluIabsIneg(OperA, AbsA, NegA);
  623. }
  624. switch (Oper)
  625. {
  626. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  627. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  628. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  629. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  630. default: throw new ArgumentException(nameof(Oper));
  631. }
  632. if (IsFloat)
  633. {
  634. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  635. }
  636. else
  637. {
  638. OperB = GetAluIabsIneg(OperB, AbsB, NegB);
  639. }
  640. ShaderIrOperPred Pred = OpCode.Pred39();
  641. ShaderIrOp Op;
  642. ShaderIrInst MaxInst = IsFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max;
  643. ShaderIrInst MinInst = IsFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min;
  644. if (Pred.IsConst)
  645. {
  646. bool IsMax = OpCode.Read(42);
  647. Op = new ShaderIrOp(IsMax
  648. ? MaxInst
  649. : MinInst, OperA, OperB);
  650. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  651. }
  652. else
  653. {
  654. ShaderIrNode PredN = OpCode.Pred39N();
  655. ShaderIrOp OpMax = new ShaderIrOp(MaxInst, OperA, OperB);
  656. ShaderIrOp OpMin = new ShaderIrOp(MinInst, OperA, OperB);
  657. ShaderIrAsg AsgMax = new ShaderIrAsg(OpCode.Gpr0(), OpMax);
  658. ShaderIrAsg AsgMin = new ShaderIrAsg(OpCode.Gpr0(), OpMin);
  659. Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMax, Not: true)));
  660. Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMin, Not: false)));
  661. }
  662. }
  663. private static void EmitRro(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  664. {
  665. //Note: this is a range reduction instruction and is supposed to
  666. //be used with Mufu, here it just moves the value and ignores the operation.
  667. bool NegA = OpCode.Read(45);
  668. bool AbsA = OpCode.Read(49);
  669. ShaderIrNode OperA;
  670. switch (Oper)
  671. {
  672. case ShaderOper.CR: OperA = OpCode.Cbuf34(); break;
  673. case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break;
  674. case ShaderOper.RR: OperA = OpCode.Gpr20(); break;
  675. default: throw new ArgumentException(nameof(Oper));
  676. }
  677. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  678. Block.AddNode(new ShaderIrCmnt("Stubbed."));
  679. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA)));
  680. }
  681. private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  682. {
  683. EmitSet(Block, OpCode, true, Oper);
  684. }
  685. private static void EmitIset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  686. {
  687. EmitSet(Block, OpCode, false, Oper);
  688. }
  689. private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  690. {
  691. bool NegA = OpCode.Read(43);
  692. bool AbsB = OpCode.Read(44);
  693. bool NegB = OpCode.Read(53);
  694. bool AbsA = OpCode.Read(54);
  695. bool BoolFloat = OpCode.Read(IsFloat ? 52 : 44);
  696. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  697. switch (Oper)
  698. {
  699. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  700. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  701. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  702. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  703. default: throw new ArgumentException(nameof(Oper));
  704. }
  705. ShaderIrInst CmpInst;
  706. if (IsFloat)
  707. {
  708. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  709. OperB = GetAluFabsFneg(OperB, AbsB, NegB);
  710. CmpInst = OpCode.CmpF();
  711. }
  712. else
  713. {
  714. CmpInst = OpCode.Cmp();
  715. }
  716. ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
  717. ShaderIrInst LopInst = OpCode.BLop45();
  718. ShaderIrOperPred PNode = OpCode.Pred39();
  719. ShaderIrNode Imm0, Imm1;
  720. if (BoolFloat)
  721. {
  722. Imm0 = new ShaderIrOperImmf(0);
  723. Imm1 = new ShaderIrOperImmf(1);
  724. }
  725. else
  726. {
  727. Imm0 = new ShaderIrOperImm(0);
  728. Imm1 = new ShaderIrOperImm(-1);
  729. }
  730. ShaderIrNode Asg0 = new ShaderIrAsg(OpCode.Gpr0(), Imm0);
  731. ShaderIrNode Asg1 = new ShaderIrAsg(OpCode.Gpr0(), Imm1);
  732. if (LopInst != ShaderIrInst.Band || !PNode.IsConst)
  733. {
  734. ShaderIrOp Op2 = new ShaderIrOp(LopInst, Op, PNode);
  735. Asg0 = new ShaderIrCond(Op2, Asg0, Not: true);
  736. Asg1 = new ShaderIrCond(Op2, Asg1, Not: false);
  737. }
  738. else
  739. {
  740. Asg0 = new ShaderIrCond(Op, Asg0, Not: true);
  741. Asg1 = new ShaderIrCond(Op, Asg1, Not: false);
  742. }
  743. Block.AddNode(OpCode.PredNode(Asg0));
  744. Block.AddNode(OpCode.PredNode(Asg1));
  745. }
  746. private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  747. {
  748. EmitSetp(Block, OpCode, true, Oper);
  749. }
  750. private static void EmitIsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  751. {
  752. EmitSetp(Block, OpCode, false, Oper);
  753. }
  754. private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
  755. {
  756. bool AbsA = OpCode.Read(7);
  757. bool NegP = OpCode.Read(42);
  758. bool NegA = OpCode.Read(43);
  759. bool AbsB = OpCode.Read(44);
  760. ShaderIrNode OperA = OpCode.Gpr8(), OperB;
  761. switch (Oper)
  762. {
  763. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  764. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  765. case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break;
  766. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  767. default: throw new ArgumentException(nameof(Oper));
  768. }
  769. ShaderIrInst CmpInst;
  770. if (IsFloat)
  771. {
  772. OperA = GetAluFabsFneg(OperA, AbsA, NegA);
  773. OperB = GetAluFabs (OperB, AbsB);
  774. CmpInst = OpCode.CmpF();
  775. }
  776. else
  777. {
  778. CmpInst = OpCode.Cmp();
  779. }
  780. ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
  781. ShaderIrOperPred P0Node = OpCode.Pred3();
  782. ShaderIrOperPred P1Node = OpCode.Pred0();
  783. ShaderIrOperPred P2Node = OpCode.Pred39();
  784. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  785. ShaderIrInst LopInst = OpCode.BLop45();
  786. if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
  787. {
  788. return;
  789. }
  790. ShaderIrNode P2NNode = P2Node;
  791. if (NegP)
  792. {
  793. P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
  794. }
  795. Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);
  796. Op = new ShaderIrOp(LopInst, Op, P2NNode);
  797. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op)));
  798. Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
  799. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op)));
  800. }
  801. private static void EmitBinaryHalfOp(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
  802. {
  803. bool AbsB = OpCode.Read(30);
  804. bool NegB = OpCode.Read(31);
  805. bool Sat = OpCode.Read(32);
  806. bool AbsA = OpCode.Read(44);
  807. ShaderIrOperGpr[] VecA = OpCode.GprHalfVec8();
  808. ShaderIrOperGpr[] VecB = OpCode.GprHalfVec20();
  809. HalfOutputType OutputType = (HalfOutputType)OpCode.Read(49, 3);
  810. int Elems = OutputType == HalfOutputType.PackedFp16 ? 2 : 1;
  811. int First = OutputType == HalfOutputType.MergeH1 ? 1 : 0;
  812. for (int Index = First; Index < Elems; Index++)
  813. {
  814. ShaderIrNode OperA = GetAluFabs (VecA[Index], AbsA);
  815. ShaderIrNode OperB = GetAluFabsFneg(VecB[Index], AbsB, NegB);
  816. ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
  817. ShaderIrOperGpr Dst = GetHalfDst(OpCode, OutputType, Index);
  818. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, GetAluFsat(Op, Sat))));
  819. }
  820. }
  821. private static ShaderIrOperGpr GetHalfDst(long OpCode, HalfOutputType OutputType, int Index)
  822. {
  823. switch (OutputType)
  824. {
  825. case HalfOutputType.PackedFp16: return OpCode.GprHalf0(Index);
  826. case HalfOutputType.Fp32: return OpCode.Gpr0();
  827. case HalfOutputType.MergeH0: return OpCode.GprHalf0(0);
  828. case HalfOutputType.MergeH1: return OpCode.GprHalf0(1);
  829. }
  830. throw new ArgumentException(nameof(OutputType));
  831. }
  832. private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  833. {
  834. int SubOp = OpCode.Read(41, 3);
  835. bool InvA = OpCode.Read(39);
  836. bool InvB = OpCode.Read(40);
  837. ShaderIrInst Inst = 0;
  838. switch (SubOp)
  839. {
  840. case 0: Inst = ShaderIrInst.And; break;
  841. case 1: Inst = ShaderIrInst.Or; break;
  842. case 2: Inst = ShaderIrInst.Xor; break;
  843. }
  844. ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA);
  845. ShaderIrNode OperB;
  846. switch (Oper)
  847. {
  848. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  849. case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
  850. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  851. default: throw new ArgumentException(nameof(Oper));
  852. }
  853. OperB = GetAluNot(OperB, InvB);
  854. ShaderIrNode Op;
  855. if (SubOp < 3)
  856. {
  857. Op = new ShaderIrOp(Inst, OperA, OperB);
  858. }
  859. else
  860. {
  861. Op = OperB;
  862. }
  863. ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0));
  864. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Pred48(), Compare)));
  865. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
  866. }
  867. private enum XmadMode
  868. {
  869. Cfull = 0,
  870. Clo = 1,
  871. Chi = 2,
  872. Csfu = 3,
  873. Cbcc = 4
  874. }
  875. private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
  876. {
  877. bool SignedA = OpCode.Read(48);
  878. bool SignedB = OpCode.Read(49);
  879. bool HighB = OpCode.Read(52);
  880. bool HighA = OpCode.Read(53);
  881. int Mode = OpCode.Read(50, 7);
  882. ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
  883. switch (Oper)
  884. {
  885. case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
  886. case ShaderOper.Imm: OperB = OpCode.ImmU16_20(); break;
  887. case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
  888. case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
  889. default: throw new ArgumentException(nameof(Oper));
  890. }
  891. ShaderIrNode OperB2 = OperB;
  892. if (Oper == ShaderOper.Imm)
  893. {
  894. int Imm = ((ShaderIrOperImm)OperB2).Value;
  895. if (!HighB)
  896. {
  897. Imm <<= 16;
  898. }
  899. if (SignedB)
  900. {
  901. Imm >>= 16;
  902. }
  903. else
  904. {
  905. Imm = (int)((uint)Imm >> 16);
  906. }
  907. OperB2 = new ShaderIrOperImm(Imm);
  908. }
  909. ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);
  910. //If we are working with the lower 16-bits of the A/B operands,
  911. //we need to shift the lower 16-bits to the top 16-bits. Later,
  912. //they will be right shifted. For U16 types, this will be a logical
  913. //right shift, and for S16 types, a arithmetic right shift.
  914. if (!HighA)
  915. {
  916. OperA = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Imm16);
  917. }
  918. if (!HighB && Oper != ShaderOper.Imm)
  919. {
  920. OperB2 = new ShaderIrOp(ShaderIrInst.Lsl, OperB2, Imm16);
  921. }
  922. ShaderIrInst ShiftA = SignedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  923. ShaderIrInst ShiftB = SignedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
  924. OperA = new ShaderIrOp(ShiftA, OperA, Imm16);
  925. if (Oper != ShaderOper.Imm)
  926. {
  927. OperB2 = new ShaderIrOp(ShiftB, OperB2, Imm16);
  928. }
  929. bool ProductShiftLeft = false;
  930. bool Merge = false;
  931. if (Oper == ShaderOper.RC)
  932. {
  933. OperC = OpCode.Cbuf34();
  934. }
  935. else
  936. {
  937. OperC = OpCode.Gpr39();
  938. ProductShiftLeft = OpCode.Read(36);
  939. Merge = OpCode.Read(37);
  940. }
  941. ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB2);
  942. if (ProductShiftLeft)
  943. {
  944. MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
  945. }
  946. switch ((XmadMode)Mode)
  947. {
  948. case XmadMode.Clo: OperC = ExtendTo32(OperC, Signed: false, Size: 16); break;
  949. case XmadMode.Chi: OperC = new ShaderIrOp(ShaderIrInst.Lsr, OperC, Imm16); break;
  950. case XmadMode.Cbcc:
  951. {
  952. ShaderIrOp OperBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
  953. OperC = new ShaderIrOp(ShaderIrInst.Add, OperC, OperBLsh16);
  954. break;
  955. }
  956. case XmadMode.Csfu:
  957. {
  958. ShaderIrOperImm Imm31 = new ShaderIrOperImm(31);
  959. ShaderIrOp SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, OperA, Imm31);
  960. ShaderIrOp SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, OperB2, Imm31);
  961. SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustA, Imm16);
  962. SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustB, Imm16);
  963. ShaderIrOp SignAdjust = new ShaderIrOp(ShaderIrInst.Add, SignAdjustA, SignAdjustB);
  964. OperC = new ShaderIrOp(ShaderIrInst.Sub, OperC, SignAdjust);
  965. break;
  966. }
  967. }
  968. ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);
  969. if (Merge)
  970. {
  971. ShaderIrOperImm Imm16Mask = new ShaderIrOperImm(0xffff);
  972. AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, Imm16Mask);
  973. OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
  974. AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
  975. }
  976. Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp)));
  977. }
  978. }
  979. }