InstEmitShift.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  5. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  6. namespace Ryujinx.Graphics.Shader.Instructions
  7. {
  8. static partial class InstEmit
  9. {
  10. public static void ShfLR(EmitterContext context)
  11. {
  12. InstShfLR op = context.GetOp<InstShfLR>();
  13. var srcA = GetSrcReg(context, op.SrcA);
  14. var srcB = GetSrcReg(context, op.SrcB);
  15. var srcC = GetSrcReg(context, op.SrcC);
  16. EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC);
  17. }
  18. public static void ShfRR(EmitterContext context)
  19. {
  20. InstShfRR op = context.GetOp<InstShfRR>();
  21. var srcA = GetSrcReg(context, op.SrcA);
  22. var srcB = GetSrcReg(context, op.SrcB);
  23. var srcC = GetSrcReg(context, op.SrcC);
  24. EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC);
  25. }
  26. public static void ShfLI(EmitterContext context)
  27. {
  28. InstShfLI op = context.GetOp<InstShfLI>();
  29. var srcA = GetSrcReg(context, op.SrcA);
  30. var srcB = Const(op.Imm6);
  31. var srcC = GetSrcReg(context, op.SrcC);
  32. EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC);
  33. }
  34. public static void ShfRI(EmitterContext context)
  35. {
  36. InstShfRI op = context.GetOp<InstShfRI>();
  37. var srcA = GetSrcReg(context, op.SrcA);
  38. var srcB = Const(op.Imm6);
  39. var srcC = GetSrcReg(context, op.SrcC);
  40. EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC);
  41. }
  42. public static void ShlR(EmitterContext context)
  43. {
  44. InstShlR op = context.GetOp<InstShlR>();
  45. EmitShl(context, GetSrcReg(context, op.SrcA), GetSrcReg(context, op.SrcB), op.Dest, op.M);
  46. }
  47. public static void ShlI(EmitterContext context)
  48. {
  49. InstShlI op = context.GetOp<InstShlI>();
  50. EmitShl(context, GetSrcReg(context, op.SrcA), GetSrcImm(context, Imm20ToSInt(op.Imm20)), op.Dest, op.M);
  51. }
  52. public static void ShlC(EmitterContext context)
  53. {
  54. InstShlC op = context.GetOp<InstShlC>();
  55. EmitShl(context, GetSrcReg(context, op.SrcA), GetSrcCbuf(context, op.CbufSlot, op.CbufOffset), op.Dest, op.M);
  56. }
  57. public static void ShrR(EmitterContext context)
  58. {
  59. InstShrR op = context.GetOp<InstShrR>();
  60. var srcA = GetSrcReg(context, op.SrcA);
  61. var srcB = GetSrcReg(context, op.SrcB);
  62. EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed);
  63. }
  64. public static void ShrI(EmitterContext context)
  65. {
  66. InstShrI op = context.GetOp<InstShrI>();
  67. var srcA = GetSrcReg(context, op.SrcA);
  68. var srcB = GetSrcImm(context, Imm20ToSInt(op.Imm20));
  69. EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed);
  70. }
  71. public static void ShrC(EmitterContext context)
  72. {
  73. InstShrC op = context.GetOp<InstShrC>();
  74. var srcA = GetSrcReg(context, op.SrcA);
  75. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  76. EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed);
  77. }
  78. private static void EmitShf(
  79. EmitterContext context,
  80. MaxShift maxShift,
  81. Operand srcA,
  82. Operand srcB,
  83. Operand srcC,
  84. int rd,
  85. bool mask,
  86. bool left,
  87. bool writeCC)
  88. {
  89. bool isLongShift = maxShift == MaxShift.U64 || maxShift == MaxShift.S64;
  90. bool signedShift = maxShift == MaxShift.S64;
  91. int maxShiftConst = isLongShift ? 64 : 32;
  92. if (mask)
  93. {
  94. srcB = context.BitwiseAnd(srcB, Const(maxShiftConst - 1));
  95. }
  96. Operand res;
  97. if (left)
  98. {
  99. // res = (C << B) | (A >> (32 - B))
  100. res = context.ShiftLeft(srcC, srcB);
  101. res = context.BitwiseOr(res, context.ShiftRightU32(srcA, context.ISubtract(Const(32), srcB)));
  102. if (isLongShift)
  103. {
  104. // res = B >= 32 ? A << (B - 32) : res
  105. Operand lowerShift = context.ShiftLeft(srcA, context.ISubtract(srcB, Const(32)));
  106. Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
  107. res = context.ConditionalSelect(shiftGreaterThan31, lowerShift, res);
  108. }
  109. }
  110. else
  111. {
  112. // res = (A >> B) | (C << (32 - B))
  113. res = context.ShiftRightU32(srcA, srcB);
  114. res = context.BitwiseOr(res, context.ShiftLeft(srcC, context.ISubtract(Const(32), srcB)));
  115. if (isLongShift)
  116. {
  117. // res = B >= 32 ? C >> (B - 32) : res
  118. Operand upperShift = signedShift
  119. ? context.ShiftRightS32(srcC, context.ISubtract(srcB, Const(32)))
  120. : context.ShiftRightU32(srcC, context.ISubtract(srcB, Const(32)));
  121. Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
  122. res = context.ConditionalSelect(shiftGreaterThan31, upperShift, res);
  123. }
  124. }
  125. if (!mask)
  126. {
  127. // Clamped shift value.
  128. Operand isLessThanMax = context.ICompareLessUnsigned(srcB, Const(maxShiftConst));
  129. res = context.ConditionalSelect(isLessThanMax, res, Const(0));
  130. }
  131. context.Copy(GetDest(rd), res);
  132. if (writeCC)
  133. {
  134. InstEmitAluHelper.SetZnFlags(context, res, writeCC);
  135. }
  136. // TODO: X.
  137. }
  138. private static void EmitShl(EmitterContext context, Operand srcA, Operand srcB, int rd, bool mask)
  139. {
  140. if (mask)
  141. {
  142. srcB = context.BitwiseAnd(srcB, Const(0x1f));
  143. }
  144. Operand res = context.ShiftLeft(srcA, srcB);
  145. if (!mask)
  146. {
  147. // Clamped shift value.
  148. Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));
  149. res = context.ConditionalSelect(isLessThan32, res, Const(0));
  150. }
  151. // TODO: X, CC.
  152. context.Copy(GetDest(rd), res);
  153. }
  154. private static void EmitShr(
  155. EmitterContext context,
  156. Operand srcA,
  157. Operand srcB,
  158. int rd,
  159. bool mask,
  160. bool bitReverse,
  161. bool isSigned)
  162. {
  163. if (bitReverse)
  164. {
  165. srcA = context.BitfieldReverse(srcA);
  166. }
  167. if (mask)
  168. {
  169. srcB = context.BitwiseAnd(srcB, Const(0x1f));
  170. }
  171. Operand res = isSigned
  172. ? context.ShiftRightS32(srcA, srcB)
  173. : context.ShiftRightU32(srcA, srcB);
  174. if (!mask)
  175. {
  176. // Clamped shift value.
  177. Operand resShiftBy32;
  178. if (isSigned)
  179. {
  180. resShiftBy32 = context.ShiftRightS32(srcA, Const(31));
  181. }
  182. else
  183. {
  184. resShiftBy32 = Const(0);
  185. }
  186. Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32));
  187. res = context.ConditionalSelect(isLessThan32, res, resShiftBy32);
  188. }
  189. // TODO: X, CC.
  190. context.Copy(GetDest(rd), res);
  191. }
  192. }
  193. }