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. }