InstEmitIntegerComparison.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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.InstEmitAluHelper;
  6. using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  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 Csetp(EmitterContext context)
  13. {
  14. InstCsetp op = context.GetOp<InstCsetp>();
  15. // TODO: Implement that properly.
  16. Operand p0Res = Const(IrConsts.True);
  17. Operand p1Res = context.BitwiseNot(p0Res);
  18. Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
  19. p0Res = GetPredLogicalOp(context, op.Bop, p0Res, srcPred);
  20. p1Res = GetPredLogicalOp(context, op.Bop, p1Res, srcPred);
  21. context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res);
  22. context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res);
  23. }
  24. public static void IcmpR(EmitterContext context)
  25. {
  26. InstIcmpR op = context.GetOp<InstIcmpR>();
  27. var srcA = GetSrcReg(context, op.SrcA);
  28. var srcB = GetSrcReg(context, op.SrcB);
  29. var srcC = GetSrcReg(context, op.SrcC);
  30. EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed);
  31. }
  32. public static void IcmpI(EmitterContext context)
  33. {
  34. InstIcmpI op = context.GetOp<InstIcmpI>();
  35. var srcA = GetSrcReg(context, op.SrcA);
  36. var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
  37. var srcC = GetSrcReg(context, op.SrcC);
  38. EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed);
  39. }
  40. public static void IcmpC(EmitterContext context)
  41. {
  42. InstIcmpC op = context.GetOp<InstIcmpC>();
  43. var srcA = GetSrcReg(context, op.SrcA);
  44. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  45. var srcC = GetSrcReg(context, op.SrcC);
  46. EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed);
  47. }
  48. public static void IcmpRc(EmitterContext context)
  49. {
  50. InstIcmpRc op = context.GetOp<InstIcmpRc>();
  51. var srcA = GetSrcReg(context, op.SrcA);
  52. var srcB = GetSrcReg(context, op.SrcC);
  53. var srcC = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  54. EmitIcmp(context, op.IComp, srcA, srcB, srcC, op.Dest, op.Signed);
  55. }
  56. public static void IsetR(EmitterContext context)
  57. {
  58. InstIsetR op = context.GetOp<InstIsetR>();
  59. var srcA = GetSrcReg(context, op.SrcA);
  60. var srcB = GetSrcReg(context, op.SrcB);
  61. EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC);
  62. }
  63. public static void IsetI(EmitterContext context)
  64. {
  65. InstIsetI op = context.GetOp<InstIsetI>();
  66. var srcA = GetSrcReg(context, op.SrcA);
  67. var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
  68. EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC);
  69. }
  70. public static void IsetC(EmitterContext context)
  71. {
  72. InstIsetC op = context.GetOp<InstIsetC>();
  73. var srcA = GetSrcReg(context, op.SrcA);
  74. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  75. EmitIset(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.Dest, op.BVal, op.Signed, op.X, op.WriteCC);
  76. }
  77. public static void IsetpR(EmitterContext context)
  78. {
  79. InstIsetpR op = context.GetOp<InstIsetpR>();
  80. var srcA = GetSrcReg(context, op.SrcA);
  81. var srcB = GetSrcReg(context, op.SrcB);
  82. EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X);
  83. }
  84. public static void IsetpI(EmitterContext context)
  85. {
  86. InstIsetpI op = context.GetOp<InstIsetpI>();
  87. var srcA = GetSrcReg(context, op.SrcA);
  88. var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
  89. EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X);
  90. }
  91. public static void IsetpC(EmitterContext context)
  92. {
  93. InstIsetpC op = context.GetOp<InstIsetpC>();
  94. var srcA = GetSrcReg(context, op.SrcA);
  95. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  96. EmitIsetp(context, op.IComp, op.Bop, srcA, srcB, op.SrcPred, op.SrcPredInv, op.DestPred, op.DestPredInv, op.Signed, op.X);
  97. }
  98. private static void EmitIcmp(
  99. EmitterContext context,
  100. IComp cmpOp,
  101. Operand srcA,
  102. Operand srcB,
  103. Operand srcC,
  104. int rd,
  105. bool isSigned)
  106. {
  107. Operand cmpRes = GetIntComparison(context, cmpOp, srcC, Const(0), isSigned);
  108. Operand res = context.ConditionalSelect(cmpRes, srcA, srcB);
  109. context.Copy(GetDest(rd), res);
  110. }
  111. private static void EmitIset(
  112. EmitterContext context,
  113. IComp cmpOp,
  114. BoolOp logicOp,
  115. Operand srcA,
  116. Operand srcB,
  117. int srcPred,
  118. bool srcPredInv,
  119. int rd,
  120. bool boolFloat,
  121. bool isSigned,
  122. bool extended,
  123. bool writeCC)
  124. {
  125. Operand res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned, extended);
  126. Operand pred = GetPredicate(context, srcPred, srcPredInv);
  127. res = GetPredLogicalOp(context, logicOp, res, pred);
  128. Operand dest = GetDest(rd);
  129. if (boolFloat)
  130. {
  131. res = context.ConditionalSelect(res, ConstF(1), Const(0));
  132. context.Copy(dest, res);
  133. SetFPZnFlags(context, res, writeCC);
  134. }
  135. else
  136. {
  137. context.Copy(dest, res);
  138. SetZnFlags(context, res, writeCC, extended);
  139. }
  140. }
  141. private static void EmitIsetp(
  142. EmitterContext context,
  143. IComp cmpOp,
  144. BoolOp logicOp,
  145. Operand srcA,
  146. Operand srcB,
  147. int srcPred,
  148. bool srcPredInv,
  149. int destPred,
  150. int destPredInv,
  151. bool isSigned,
  152. bool extended)
  153. {
  154. Operand p0Res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned, extended);
  155. Operand p1Res = context.BitwiseNot(p0Res);
  156. Operand pred = GetPredicate(context, srcPred, srcPredInv);
  157. p0Res = GetPredLogicalOp(context, logicOp, p0Res, pred);
  158. p1Res = GetPredLogicalOp(context, logicOp, p1Res, pred);
  159. context.Copy(Register(destPred, RegisterType.Predicate), p0Res);
  160. context.Copy(Register(destPredInv, RegisterType.Predicate), p1Res);
  161. }
  162. private static Operand GetIntComparison(
  163. EmitterContext context,
  164. IComp cond,
  165. Operand srcA,
  166. Operand srcB,
  167. bool isSigned,
  168. bool extended)
  169. {
  170. return extended
  171. ? GetIntComparisonExtended(context, cond, srcA, srcB, isSigned)
  172. : GetIntComparison(context, cond, srcA, srcB, isSigned);
  173. }
  174. private static Operand GetIntComparisonExtended(EmitterContext context, IComp cond, Operand srcA, Operand srcB, bool isSigned)
  175. {
  176. Operand res;
  177. if (cond == IComp.T)
  178. {
  179. res = Const(IrConsts.True);
  180. }
  181. else if (cond == IComp.F)
  182. {
  183. res = Const(IrConsts.False);
  184. }
  185. else
  186. {
  187. res = context.ISubtract(srcA, srcB);
  188. res = context.IAdd(res, context.BitwiseNot(GetCF()));
  189. switch (cond)
  190. {
  191. case IComp.Eq: // r = xh == yh && xl == yl
  192. res = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), GetZF());
  193. break;
  194. case IComp.Lt: // r = xh < yh || (xh == yh && xl < yl)
  195. Operand notC = context.BitwiseNot(GetCF());
  196. Operand prevLt = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), notC);
  197. res = isSigned
  198. ? context.BitwiseOr(context.ICompareLess(srcA, srcB), prevLt)
  199. : context.BitwiseOr(context.ICompareLessUnsigned(srcA, srcB), prevLt);
  200. break;
  201. case IComp.Le: // r = xh < yh || (xh == yh && xl <= yl)
  202. Operand zOrNotC = context.BitwiseOr(GetZF(), context.BitwiseNot(GetCF()));
  203. Operand prevLe = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), zOrNotC);
  204. res = isSigned
  205. ? context.BitwiseOr(context.ICompareLess(srcA, srcB), prevLe)
  206. : context.BitwiseOr(context.ICompareLessUnsigned(srcA, srcB), prevLe);
  207. break;
  208. case IComp.Gt: // r = xh > yh || (xh == yh && xl > yl)
  209. Operand notZAndC = context.BitwiseAnd(context.BitwiseNot(GetZF()), GetCF());
  210. Operand prevGt = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), notZAndC);
  211. res = isSigned
  212. ? context.BitwiseOr(context.ICompareGreater(srcA, srcB), prevGt)
  213. : context.BitwiseOr(context.ICompareGreaterUnsigned(srcA, srcB), prevGt);
  214. break;
  215. case IComp.Ge: // r = xh > yh || (xh == yh && xl >= yl)
  216. Operand prevGe = context.BitwiseAnd(context.ICompareEqual(srcA, srcB), GetCF());
  217. res = isSigned
  218. ? context.BitwiseOr(context.ICompareGreater(srcA, srcB), prevGe)
  219. : context.BitwiseOr(context.ICompareGreaterUnsigned(srcA, srcB), prevGe);
  220. break;
  221. case IComp.Ne: // r = xh != yh || xl != yl
  222. res = context.BitwiseOr(context.ICompareNotEqual(srcA, srcB), context.BitwiseNot(GetZF()));
  223. break;
  224. default:
  225. throw new ArgumentException($"Unexpected condition \"{cond}\".");
  226. }
  227. }
  228. return res;
  229. }
  230. private static Operand GetIntComparison(EmitterContext context, IComp cond, Operand srcA, Operand srcB, bool isSigned)
  231. {
  232. Operand res;
  233. if (cond == IComp.T)
  234. {
  235. res = Const(IrConsts.True);
  236. }
  237. else if (cond == IComp.F)
  238. {
  239. res = Const(IrConsts.False);
  240. }
  241. else
  242. {
  243. var inst = cond switch
  244. {
  245. IComp.Lt => Instruction.CompareLessU32,
  246. IComp.Eq => Instruction.CompareEqual,
  247. IComp.Le => Instruction.CompareLessOrEqualU32,
  248. IComp.Gt => Instruction.CompareGreaterU32,
  249. IComp.Ne => Instruction.CompareNotEqual,
  250. IComp.Ge => Instruction.CompareGreaterOrEqualU32,
  251. _ => throw new InvalidOperationException($"Unexpected condition \"{cond}\".")
  252. };
  253. if (isSigned)
  254. {
  255. switch (cond)
  256. {
  257. case IComp.Lt: inst = Instruction.CompareLess; break;
  258. case IComp.Le: inst = Instruction.CompareLessOrEqual; break;
  259. case IComp.Gt: inst = Instruction.CompareGreater; break;
  260. case IComp.Ge: inst = Instruction.CompareGreaterOrEqual; break;
  261. }
  262. }
  263. res = context.Add(inst, Local(), srcA, srcB);
  264. }
  265. return res;
  266. }
  267. }
  268. }