InstEmitAlu.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using System;
  5. using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  6. using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper;
  7. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  8. namespace Ryujinx.Graphics.Shader.Instructions
  9. {
  10. static partial class InstEmit
  11. {
  12. public static void Bfe(EmitterContext context)
  13. {
  14. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  15. bool isReverse = op.RawOpCode.Extract(40);
  16. bool isSigned = op.RawOpCode.Extract(48);
  17. Operand srcA = GetSrcA(context);
  18. Operand srcB = GetSrcB(context);
  19. if (isReverse)
  20. {
  21. srcA = context.BitfieldReverse(srcA);
  22. }
  23. Operand position = context.BitwiseAnd(srcB, Const(0xff));
  24. Operand size = context.BitfieldExtractU32(srcB, Const(8), Const(8));
  25. Operand res = isSigned
  26. ? context.BitfieldExtractS32(srcA, position, size)
  27. : context.BitfieldExtractU32(srcA, position, size);
  28. context.Copy(GetDest(context), res);
  29. //TODO: CC, X, corner cases
  30. }
  31. public static void Iadd(EmitterContext context)
  32. {
  33. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  34. bool negateA = false, negateB = false;
  35. if (!(op is OpCodeAluImm32))
  36. {
  37. negateB = op.RawOpCode.Extract(48);
  38. negateA = op.RawOpCode.Extract(49);
  39. }
  40. Operand srcA = context.INegate(GetSrcA(context), negateA);
  41. Operand srcB = context.INegate(GetSrcB(context), negateB);
  42. Operand res = context.IAdd(srcA, srcB);
  43. bool isSubtraction = negateA || negateB;
  44. if (op.Extended)
  45. {
  46. //Add carry, or subtract borrow.
  47. res = context.IAdd(res, isSubtraction
  48. ? context.BitwiseNot(GetCF(context))
  49. : context.BitwiseAnd(GetCF(context), Const(1)));
  50. }
  51. SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, op.Extended, isSubtraction);
  52. context.Copy(GetDest(context), res);
  53. }
  54. public static void Iadd3(EmitterContext context)
  55. {
  56. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  57. IntegerHalfPart partC = (IntegerHalfPart)op.RawOpCode.Extract(31, 2);
  58. IntegerHalfPart partB = (IntegerHalfPart)op.RawOpCode.Extract(33, 2);
  59. IntegerHalfPart partA = (IntegerHalfPart)op.RawOpCode.Extract(35, 2);
  60. IntegerShift mode = (IntegerShift)op.RawOpCode.Extract(37, 2);
  61. bool negateC = op.RawOpCode.Extract(49);
  62. bool negateB = op.RawOpCode.Extract(50);
  63. bool negateA = op.RawOpCode.Extract(51);
  64. Operand Extend(Operand src, IntegerHalfPart part)
  65. {
  66. if (!(op is OpCodeAluReg) || part == IntegerHalfPart.B32)
  67. {
  68. return src;
  69. }
  70. if (part == IntegerHalfPart.H0)
  71. {
  72. return context.BitwiseAnd(src, Const(0xffff));
  73. }
  74. else if (part == IntegerHalfPart.H1)
  75. {
  76. return context.ShiftRightU32(src, Const(16));
  77. }
  78. else
  79. {
  80. //TODO: Warning.
  81. }
  82. return src;
  83. }
  84. Operand srcA = context.INegate(Extend(GetSrcA(context), partA), negateA);
  85. Operand srcB = context.INegate(Extend(GetSrcB(context), partB), negateB);
  86. Operand srcC = context.INegate(Extend(GetSrcC(context), partC), negateC);
  87. Operand res = context.IAdd(srcA, srcB);
  88. if (op is OpCodeAluReg && mode != IntegerShift.NoShift)
  89. {
  90. if (mode == IntegerShift.ShiftLeft)
  91. {
  92. res = context.ShiftLeft(res, Const(16));
  93. }
  94. else if (mode == IntegerShift.ShiftRight)
  95. {
  96. res = context.ShiftRightU32(res, Const(16));
  97. }
  98. else
  99. {
  100. //TODO: Warning.
  101. }
  102. }
  103. res = context.IAdd(res, srcC);
  104. context.Copy(GetDest(context), res);
  105. //TODO: CC, X, corner cases
  106. }
  107. public static void Imnmx(EmitterContext context)
  108. {
  109. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  110. bool isSignedInt = op.RawOpCode.Extract(48);
  111. Operand srcA = GetSrcA(context);
  112. Operand srcB = GetSrcB(context);
  113. Operand resMin = isSignedInt
  114. ? context.IMinimumS32(srcA, srcB)
  115. : context.IMinimumU32(srcA, srcB);
  116. Operand resMax = isSignedInt
  117. ? context.IMaximumS32(srcA, srcB)
  118. : context.IMaximumU32(srcA, srcB);
  119. Operand pred = GetPredicate39(context);
  120. Operand dest = GetDest(context);
  121. context.Copy(dest, context.ConditionalSelect(pred, resMin, resMax));
  122. SetZnFlags(context, dest, op.SetCondCode);
  123. //TODO: X flags.
  124. }
  125. public static void Iscadd(EmitterContext context)
  126. {
  127. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  128. bool negateA = false, negateB = false;
  129. if (!(op is OpCodeAluImm32))
  130. {
  131. negateB = op.RawOpCode.Extract(48);
  132. negateA = op.RawOpCode.Extract(49);
  133. }
  134. int shift = op is OpCodeAluImm32
  135. ? op.RawOpCode.Extract(53, 5)
  136. : op.RawOpCode.Extract(39, 5);
  137. Operand srcA = GetSrcA(context);
  138. Operand srcB = GetSrcB(context);
  139. srcA = context.ShiftLeft(srcA, Const(shift));
  140. srcA = context.INegate(srcA, negateA);
  141. srcB = context.INegate(srcB, negateB);
  142. Operand res = context.IAdd(srcA, srcB);
  143. context.Copy(GetDest(context), res);
  144. //TODO: CC, X
  145. }
  146. public static void Iset(EmitterContext context)
  147. {
  148. OpCodeSet op = (OpCodeSet)context.CurrOp;
  149. bool boolFloat = op.RawOpCode.Extract(44);
  150. bool isSigned = op.RawOpCode.Extract(48);
  151. IntegerCondition cmpOp = (IntegerCondition)op.RawOpCode.Extract(49, 3);
  152. Operand srcA = GetSrcA(context);
  153. Operand srcB = GetSrcB(context);
  154. Operand res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned);
  155. Operand pred = GetPredicate39(context);
  156. res = GetPredLogicalOp(context, op.LogicalOp, res, pred);
  157. Operand dest = GetDest(context);
  158. if (boolFloat)
  159. {
  160. context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0)));
  161. }
  162. else
  163. {
  164. context.Copy(dest, res);
  165. }
  166. //TODO: CC, X
  167. }
  168. public static void Isetp(EmitterContext context)
  169. {
  170. OpCodeSet op = (OpCodeSet)context.CurrOp;
  171. bool isSigned = op.RawOpCode.Extract(48);
  172. IntegerCondition cmpOp = (IntegerCondition)op.RawOpCode.Extract(49, 3);
  173. Operand srcA = GetSrcA(context);
  174. Operand srcB = GetSrcB(context);
  175. Operand p0Res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned);
  176. Operand p1Res = context.BitwiseNot(p0Res);
  177. Operand pred = GetPredicate39(context);
  178. p0Res = GetPredLogicalOp(context, op.LogicalOp, p0Res, pred);
  179. p1Res = GetPredLogicalOp(context, op.LogicalOp, p1Res, pred);
  180. context.Copy(Register(op.Predicate3), p0Res);
  181. context.Copy(Register(op.Predicate0), p1Res);
  182. }
  183. public static void Lop(EmitterContext context)
  184. {
  185. IOpCodeLop op = (IOpCodeLop)context.CurrOp;
  186. Operand srcA = context.BitwiseNot(GetSrcA(context), op.InvertA);
  187. Operand srcB = context.BitwiseNot(GetSrcB(context), op.InvertB);
  188. Operand res = srcB;
  189. switch (op.LogicalOp)
  190. {
  191. case LogicalOperation.And: res = context.BitwiseAnd (srcA, srcB); break;
  192. case LogicalOperation.Or: res = context.BitwiseOr (srcA, srcB); break;
  193. case LogicalOperation.ExclusiveOr: res = context.BitwiseExclusiveOr(srcA, srcB); break;
  194. }
  195. EmitLopPredWrite(context, op, res);
  196. Operand dest = GetDest(context);
  197. context.Copy(dest, res);
  198. SetZnFlags(context, dest, op.SetCondCode, op.Extended);
  199. }
  200. public static void Lop3(EmitterContext context)
  201. {
  202. IOpCodeLop op = (IOpCodeLop)context.CurrOp;
  203. Operand srcA = GetSrcA(context);
  204. Operand srcB = GetSrcB(context);
  205. Operand srcC = GetSrcC(context);
  206. bool regVariant = op is OpCodeLopReg;
  207. int truthTable = regVariant
  208. ? op.RawOpCode.Extract(28, 8)
  209. : op.RawOpCode.Extract(48, 8);
  210. Operand res = Lop3Expression.GetFromTruthTable(context, srcA, srcB, srcC, truthTable);
  211. if (regVariant)
  212. {
  213. EmitLopPredWrite(context, op, res);
  214. }
  215. Operand dest = GetDest(context);
  216. context.Copy(dest, res);
  217. SetZnFlags(context, dest, op.SetCondCode, op.Extended);
  218. }
  219. public static void Psetp(EmitterContext context)
  220. {
  221. OpCodePsetp op = (OpCodePsetp)context.CurrOp;
  222. bool invertA = op.RawOpCode.Extract(15);
  223. bool invertB = op.RawOpCode.Extract(32);
  224. Operand srcA = context.BitwiseNot(Register(op.Predicate12), invertA);
  225. Operand srcB = context.BitwiseNot(Register(op.Predicate29), invertB);
  226. Operand p0Res = GetPredLogicalOp(context, op.LogicalOpAB, srcA, srcB);
  227. Operand p1Res = context.BitwiseNot(p0Res);
  228. Operand pred = GetPredicate39(context);
  229. p0Res = GetPredLogicalOp(context, op.LogicalOp, p0Res, pred);
  230. p1Res = GetPredLogicalOp(context, op.LogicalOp, p1Res, pred);
  231. context.Copy(Register(op.Predicate3), p0Res);
  232. context.Copy(Register(op.Predicate0), p1Res);
  233. }
  234. public static void Rro(EmitterContext context)
  235. {
  236. //This is the range reduction operator,
  237. //we translate it as a simple move, as it
  238. //should be always followed by a matching
  239. //MUFU instruction.
  240. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  241. bool negateB = op.RawOpCode.Extract(45);
  242. bool absoluteB = op.RawOpCode.Extract(49);
  243. Operand srcB = GetSrcB(context);
  244. srcB = context.FPAbsNeg(srcB, absoluteB, negateB);
  245. context.Copy(GetDest(context), srcB);
  246. }
  247. public static void Shl(EmitterContext context)
  248. {
  249. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  250. bool isMasked = op.RawOpCode.Extract(39);
  251. Operand srcB = GetSrcB(context);
  252. if (isMasked)
  253. {
  254. srcB = context.BitwiseAnd(srcB, Const(0x1f));
  255. }
  256. Operand res = context.ShiftLeft(GetSrcA(context), srcB);
  257. if (!isMasked)
  258. {
  259. //Clamped shift value.
  260. Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));
  261. res = context.ConditionalSelect(isLessThan32, res, Const(0));
  262. }
  263. //TODO: X, CC
  264. context.Copy(GetDest(context), res);
  265. }
  266. public static void Shr(EmitterContext context)
  267. {
  268. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  269. bool isMasked = op.RawOpCode.Extract(39);
  270. bool isReverse = op.RawOpCode.Extract(40);
  271. bool isSigned = op.RawOpCode.Extract(48);
  272. Operand srcA = GetSrcA(context);
  273. Operand srcB = GetSrcB(context);
  274. if (isReverse)
  275. {
  276. srcA = context.BitfieldReverse(srcA);
  277. }
  278. if (isMasked)
  279. {
  280. srcB = context.BitwiseAnd(srcB, Const(0x1f));
  281. }
  282. Operand res = isSigned
  283. ? context.ShiftRightS32(srcA, srcB)
  284. : context.ShiftRightU32(srcA, srcB);
  285. if (!isMasked)
  286. {
  287. //Clamped shift value.
  288. Operand resShiftBy32;
  289. if (isSigned)
  290. {
  291. resShiftBy32 = context.ShiftRightS32(srcA, Const(31));
  292. }
  293. else
  294. {
  295. resShiftBy32 = Const(0);
  296. }
  297. Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));
  298. res = context.ConditionalSelect(isLessThan32, res, resShiftBy32);
  299. }
  300. //TODO: X, CC
  301. context.Copy(GetDest(context), res);
  302. }
  303. public static void Xmad(EmitterContext context)
  304. {
  305. OpCodeAlu op = (OpCodeAlu)context.CurrOp;
  306. bool signedA = context.CurrOp.RawOpCode.Extract(48);
  307. bool signedB = context.CurrOp.RawOpCode.Extract(49);
  308. bool highA = context.CurrOp.RawOpCode.Extract(53);
  309. bool highB = false;
  310. XmadCMode mode;
  311. if (op is OpCodeAluReg)
  312. {
  313. highB = context.CurrOp.RawOpCode.Extract(35);
  314. mode = (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 3);
  315. }
  316. else
  317. {
  318. mode = (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 2);
  319. if (!(op is OpCodeAluImm))
  320. {
  321. highB = context.CurrOp.RawOpCode.Extract(52);
  322. }
  323. }
  324. Operand srcA = GetSrcA(context);
  325. Operand srcB = GetSrcB(context);
  326. Operand srcC = GetSrcC(context);
  327. //XMAD immediates are 16-bits unsigned integers.
  328. if (srcB.Type == OperandType.Constant)
  329. {
  330. srcB = Const(srcB.Value & 0xffff);
  331. }
  332. Operand Extend16To32(Operand src, bool high, bool signed)
  333. {
  334. if (signed && high)
  335. {
  336. return context.ShiftRightS32(src, Const(16));
  337. }
  338. else if (signed)
  339. {
  340. return context.BitfieldExtractS32(src, Const(0), Const(16));
  341. }
  342. else if (high)
  343. {
  344. return context.ShiftRightU32(src, Const(16));
  345. }
  346. else
  347. {
  348. return context.BitwiseAnd(src, Const(0xffff));
  349. }
  350. }
  351. srcA = Extend16To32(srcA, highA, signedA);
  352. srcB = Extend16To32(srcB, highB, signedB);
  353. bool productShiftLeft = false;
  354. bool merge = false;
  355. if (!(op is OpCodeAluRegCbuf))
  356. {
  357. productShiftLeft = context.CurrOp.RawOpCode.Extract(36);
  358. merge = context.CurrOp.RawOpCode.Extract(37);
  359. }
  360. bool extended;
  361. if ((op is OpCodeAluReg) || (op is OpCodeAluImm))
  362. {
  363. extended = context.CurrOp.RawOpCode.Extract(38);
  364. }
  365. else
  366. {
  367. extended = context.CurrOp.RawOpCode.Extract(54);
  368. }
  369. Operand res = context.IMultiply(srcA, srcB);
  370. if (productShiftLeft)
  371. {
  372. res = context.ShiftLeft(res, Const(16));
  373. }
  374. switch (mode)
  375. {
  376. case XmadCMode.Cfull: break;
  377. case XmadCMode.Clo: srcC = Extend16To32(srcC, high: false, signed: false); break;
  378. case XmadCMode.Chi: srcC = Extend16To32(srcC, high: true, signed: false); break;
  379. case XmadCMode.Cbcc:
  380. {
  381. srcC = context.IAdd(srcC, context.ShiftLeft(GetSrcB(context), Const(16)));
  382. break;
  383. }
  384. case XmadCMode.Csfu:
  385. {
  386. Operand signAdjustA = context.ShiftLeft(context.ShiftRightU32(srcA, Const(31)), Const(16));
  387. Operand signAdjustB = context.ShiftLeft(context.ShiftRightU32(srcB, Const(31)), Const(16));
  388. srcC = context.ISubtract(srcC, context.IAdd(signAdjustA, signAdjustB));
  389. break;
  390. }
  391. default: /* TODO: Warning */ break;
  392. }
  393. Operand product = res;
  394. if (extended)
  395. {
  396. //Add with carry.
  397. res = context.IAdd(res, context.BitwiseAnd(GetCF(context), Const(1)));
  398. }
  399. else
  400. {
  401. //Add (no carry in).
  402. res = context.IAdd(res, srcC);
  403. }
  404. SetIaddFlags(context, res, product, srcC, op.SetCondCode, extended);
  405. if (merge)
  406. {
  407. res = context.BitwiseAnd(res, Const(0xffff));
  408. res = context.BitwiseOr(res, context.ShiftLeft(GetSrcB(context), Const(16)));
  409. }
  410. context.Copy(GetDest(context), res);
  411. }
  412. private static Operand GetIntComparison(
  413. EmitterContext context,
  414. IntegerCondition cond,
  415. Operand srcA,
  416. Operand srcB,
  417. bool isSigned)
  418. {
  419. Operand res;
  420. if (cond == IntegerCondition.Always)
  421. {
  422. res = Const(IrConsts.True);
  423. }
  424. else if (cond == IntegerCondition.Never)
  425. {
  426. res = Const(IrConsts.False);
  427. }
  428. else
  429. {
  430. Instruction inst;
  431. switch (cond)
  432. {
  433. case IntegerCondition.Less: inst = Instruction.CompareLessU32; break;
  434. case IntegerCondition.Equal: inst = Instruction.CompareEqual; break;
  435. case IntegerCondition.LessOrEqual: inst = Instruction.CompareLessOrEqualU32; break;
  436. case IntegerCondition.Greater: inst = Instruction.CompareGreaterU32; break;
  437. case IntegerCondition.NotEqual: inst = Instruction.CompareNotEqual; break;
  438. case IntegerCondition.GreaterOrEqual: inst = Instruction.CompareGreaterOrEqualU32; break;
  439. default: throw new InvalidOperationException($"Unexpected condition \"{cond}\".");
  440. }
  441. if (isSigned)
  442. {
  443. switch (cond)
  444. {
  445. case IntegerCondition.Less: inst = Instruction.CompareLess; break;
  446. case IntegerCondition.LessOrEqual: inst = Instruction.CompareLessOrEqual; break;
  447. case IntegerCondition.Greater: inst = Instruction.CompareGreater; break;
  448. case IntegerCondition.GreaterOrEqual: inst = Instruction.CompareGreaterOrEqual; break;
  449. }
  450. }
  451. res = context.Add(inst, Local(), srcA, srcB);
  452. }
  453. return res;
  454. }
  455. private static void EmitLopPredWrite(EmitterContext context, IOpCodeLop op, Operand result)
  456. {
  457. if (op is OpCodeLop opLop && !opLop.Predicate48.IsPT)
  458. {
  459. Operand pRes;
  460. if (opLop.CondOp == ConditionalOperation.False)
  461. {
  462. pRes = Const(IrConsts.False);
  463. }
  464. else if (opLop.CondOp == ConditionalOperation.True)
  465. {
  466. pRes = Const(IrConsts.True);
  467. }
  468. else if (opLop.CondOp == ConditionalOperation.Zero)
  469. {
  470. pRes = context.ICompareEqual(result, Const(0));
  471. }
  472. else /* if (opLop.CondOp == ConditionalOperation.NotZero) */
  473. {
  474. pRes = context.ICompareNotEqual(result, Const(0));
  475. }
  476. context.Copy(Register(opLop.Predicate48), pRes);
  477. }
  478. }
  479. private static void SetIaddFlags(
  480. EmitterContext context,
  481. Operand res,
  482. Operand srcA,
  483. Operand srcB,
  484. bool setCC,
  485. bool extended,
  486. bool isSubtraction = false)
  487. {
  488. if (!setCC)
  489. {
  490. return;
  491. }
  492. if (!extended || isSubtraction)
  493. {
  494. //C = d < a
  495. context.Copy(GetCF(context), context.ICompareLessUnsigned(res, srcA));
  496. }
  497. else
  498. {
  499. //C = (d == a && CIn) || d < a
  500. Operand tempC0 = context.ICompareEqual (res, srcA);
  501. Operand tempC1 = context.ICompareLessUnsigned(res, srcA);
  502. tempC0 = context.BitwiseAnd(tempC0, GetCF(context));
  503. context.Copy(GetCF(context), context.BitwiseOr(tempC0, tempC1));
  504. }
  505. //V = (d ^ a) & ~(a ^ b) < 0
  506. Operand tempV0 = context.BitwiseExclusiveOr(res, srcA);
  507. Operand tempV1 = context.BitwiseExclusiveOr(srcA, srcB);
  508. tempV1 = context.BitwiseNot(tempV1);
  509. Operand tempV = context.BitwiseAnd(tempV0, tempV1);
  510. context.Copy(GetVF(context), context.ICompareLess(tempV, Const(0)));
  511. SetZnFlags(context, res, setCC: true, extended: extended);
  512. }
  513. }
  514. }