InstEmitHelper.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using Ryujinx.Graphics.Shader.Decoders;
  2. using Ryujinx.Graphics.Shader.IntermediateRepresentation;
  3. using Ryujinx.Graphics.Shader.Translation;
  4. using System;
  5. using System.Runtime.CompilerServices;
  6. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  7. namespace Ryujinx.Graphics.Shader.Instructions
  8. {
  9. static class InstEmitHelper
  10. {
  11. public static Operand GetZF()
  12. {
  13. return Register(0, RegisterType.Flag);
  14. }
  15. public static Operand GetNF()
  16. {
  17. return Register(1, RegisterType.Flag);
  18. }
  19. public static Operand GetCF()
  20. {
  21. return Register(2, RegisterType.Flag);
  22. }
  23. public static Operand GetVF()
  24. {
  25. return Register(3, RegisterType.Flag);
  26. }
  27. public static Operand GetDest(int rd)
  28. {
  29. return Register(rd, RegisterType.Gpr);
  30. }
  31. public static Operand GetDest2(int rd)
  32. {
  33. return Register(rd | 1, RegisterType.Gpr);
  34. }
  35. public static Operand GetSrcCbuf(EmitterContext context, int cbufSlot, int cbufOffset, bool isFP64 = false)
  36. {
  37. if (isFP64)
  38. {
  39. return context.PackDouble2x32(
  40. Cbuf(cbufSlot, cbufOffset),
  41. Cbuf(cbufSlot, cbufOffset + 1));
  42. }
  43. else
  44. {
  45. return Cbuf(cbufSlot, cbufOffset);
  46. }
  47. }
  48. public static Operand GetSrcImm(EmitterContext context, int imm, bool isFP64 = false)
  49. {
  50. if (isFP64)
  51. {
  52. return context.PackDouble2x32(Const(0), Const(imm));
  53. }
  54. else
  55. {
  56. return Const(imm);
  57. }
  58. }
  59. public static Operand GetSrcReg(EmitterContext context, int reg, bool isFP64 = false)
  60. {
  61. if (isFP64)
  62. {
  63. return context.PackDouble2x32(Register(reg, RegisterType.Gpr), Register(reg | 1, RegisterType.Gpr));
  64. }
  65. else
  66. {
  67. return Register(reg, RegisterType.Gpr);
  68. }
  69. }
  70. public static Operand[] GetHalfSrc(
  71. EmitterContext context,
  72. HalfSwizzle swizzle,
  73. int ra,
  74. bool negate,
  75. bool absolute)
  76. {
  77. Operand[] operands = GetHalfUnpacked(context, GetSrcReg(context, ra), swizzle);
  78. return FPAbsNeg(context, operands, absolute, negate);
  79. }
  80. public static Operand[] GetHalfSrc(
  81. EmitterContext context,
  82. HalfSwizzle swizzle,
  83. int cbufSlot,
  84. int cbufOffset,
  85. bool negate,
  86. bool absolute)
  87. {
  88. Operand[] operands = GetHalfUnpacked(context, GetSrcCbuf(context, cbufSlot, cbufOffset), swizzle);
  89. return FPAbsNeg(context, operands, absolute, negate);
  90. }
  91. public static Operand[] GetHalfSrc(EmitterContext context, int immH0, int immH1)
  92. {
  93. ushort low = (ushort)(immH0 << 6);
  94. ushort high = (ushort)(immH1 << 6);
  95. return new Operand[]
  96. {
  97. ConstF((float)Unsafe.As<ushort, Half>(ref low)),
  98. ConstF((float)Unsafe.As<ushort, Half>(ref high))
  99. };
  100. }
  101. public static Operand[] GetHalfSrc(EmitterContext context, int imm32)
  102. {
  103. ushort low = (ushort)imm32;
  104. ushort high = (ushort)(imm32 >> 16);
  105. return new Operand[]
  106. {
  107. ConstF((float)Unsafe.As<ushort, Half>(ref low)),
  108. ConstF((float)Unsafe.As<ushort, Half>(ref high))
  109. };
  110. }
  111. public static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg)
  112. {
  113. for (int index = 0; index < operands.Length; index++)
  114. {
  115. operands[index] = context.FPAbsNeg(operands[index], abs, neg);
  116. }
  117. return operands;
  118. }
  119. public static Operand[] GetHalfUnpacked(EmitterContext context, Operand src, HalfSwizzle swizzle)
  120. {
  121. switch (swizzle)
  122. {
  123. case HalfSwizzle.F16:
  124. return new Operand[]
  125. {
  126. context.UnpackHalf2x16Low (src),
  127. context.UnpackHalf2x16High(src)
  128. };
  129. case HalfSwizzle.F32: return new Operand[] { src, src };
  130. case HalfSwizzle.H0H0:
  131. return new Operand[]
  132. {
  133. context.UnpackHalf2x16Low(src),
  134. context.UnpackHalf2x16Low(src)
  135. };
  136. case HalfSwizzle.H1H1:
  137. return new Operand[]
  138. {
  139. context.UnpackHalf2x16High(src),
  140. context.UnpackHalf2x16High(src)
  141. };
  142. }
  143. throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
  144. }
  145. public static Operand GetHalfPacked(EmitterContext context, OFmt swizzle, Operand[] results, int rd)
  146. {
  147. switch (swizzle)
  148. {
  149. case OFmt.F16: return context.PackHalf2x16(results[0], results[1]);
  150. case OFmt.F32: return results[0];
  151. case OFmt.MrgH0:
  152. {
  153. Operand h1 = GetHalfDest(context, rd, isHigh: true);
  154. return context.PackHalf2x16(results[0], h1);
  155. }
  156. case OFmt.MrgH1:
  157. {
  158. Operand h0 = GetHalfDest(context, rd, isHigh: false);
  159. return context.PackHalf2x16(h0, results[1]);
  160. }
  161. }
  162. throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
  163. }
  164. public static Operand GetHalfDest(EmitterContext context, int rd, bool isHigh)
  165. {
  166. if (isHigh)
  167. {
  168. return context.UnpackHalf2x16High(GetDest(rd));
  169. }
  170. else
  171. {
  172. return context.UnpackHalf2x16Low(GetDest(rd));
  173. }
  174. }
  175. public static Operand GetPredicate(EmitterContext context, int pred, bool not)
  176. {
  177. Operand local = Register(pred, RegisterType.Predicate);
  178. if (not)
  179. {
  180. local = context.BitwiseNot(local);
  181. }
  182. return local;
  183. }
  184. public static void SetDest(EmitterContext context, Operand value, int rd, bool isFP64)
  185. {
  186. if (isFP64)
  187. {
  188. context.Copy(GetDest(rd), context.UnpackDouble2x32Low(value));
  189. context.Copy(GetDest2(rd), context.UnpackDouble2x32High(value));
  190. }
  191. else
  192. {
  193. context.Copy(GetDest(rd), value);
  194. }
  195. }
  196. public static int Imm16ToSInt(int imm16)
  197. {
  198. return (short)imm16;
  199. }
  200. public static int Imm20ToFloat(int imm20)
  201. {
  202. return imm20 << 12;
  203. }
  204. public static int Imm20ToSInt(int imm20)
  205. {
  206. return (imm20 << 12) >> 12;
  207. }
  208. public static int Imm24ToSInt(int imm24)
  209. {
  210. return (imm24 << 8) >> 8;
  211. }
  212. public static Operand SignExtendTo32(EmitterContext context, Operand src, int srcBits)
  213. {
  214. return context.BitfieldExtractS32(src, Const(0), Const(srcBits));
  215. }
  216. public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits)
  217. {
  218. int mask = (int)(uint.MaxValue >> (32 - srcBits));
  219. return context.BitwiseAnd(src, Const(mask));
  220. }
  221. }
  222. }