InstEmitIntegerComparison.cs 12 KB

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