InstEmitHelper.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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.IntermediateRepresentation.OperandHelper;
  6. namespace Ryujinx.Graphics.Shader.Instructions
  7. {
  8. static class InstEmitHelper
  9. {
  10. public static Operand GetZF(EmitterContext context)
  11. {
  12. return Register(0, RegisterType.Flag);
  13. }
  14. public static Operand GetNF(EmitterContext context)
  15. {
  16. return Register(1, RegisterType.Flag);
  17. }
  18. public static Operand GetCF(EmitterContext context)
  19. {
  20. return Register(2, RegisterType.Flag);
  21. }
  22. public static Operand GetVF(EmitterContext context)
  23. {
  24. return Register(3, RegisterType.Flag);
  25. }
  26. public static Operand GetDest(EmitterContext context)
  27. {
  28. return Register(((IOpCodeRd)context.CurrOp).Rd);
  29. }
  30. public static Operand GetSrcA(EmitterContext context)
  31. {
  32. return Register(((IOpCodeRa)context.CurrOp).Ra);
  33. }
  34. public static Operand GetSrcB(EmitterContext context, FPType floatType)
  35. {
  36. if (floatType == FPType.FP32)
  37. {
  38. return GetSrcB(context);
  39. }
  40. else if (floatType == FPType.FP16)
  41. {
  42. int h = context.CurrOp.RawOpCode.Extract(41, 1);
  43. return GetHalfUnpacked(context, GetSrcB(context), FPHalfSwizzle.FP16)[h];
  44. }
  45. else if (floatType == FPType.FP64)
  46. {
  47. // TODO.
  48. }
  49. throw new ArgumentException($"Invalid floating point type \"{floatType}\".");
  50. }
  51. public static Operand GetSrcB(EmitterContext context)
  52. {
  53. switch (context.CurrOp)
  54. {
  55. case IOpCodeCbuf op:
  56. return Cbuf(op.Slot, op.Offset);
  57. case IOpCodeImm op:
  58. return Const(op.Immediate);
  59. case IOpCodeImmF op:
  60. return ConstF(op.Immediate);
  61. case IOpCodeReg op:
  62. return Register(op.Rb);
  63. case IOpCodeRegCbuf op:
  64. return Register(op.Rc);
  65. }
  66. throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\".");
  67. }
  68. public static Operand GetSrcC(EmitterContext context)
  69. {
  70. switch (context.CurrOp)
  71. {
  72. case IOpCodeRegCbuf op:
  73. return Cbuf(op.Slot, op.Offset);
  74. case IOpCodeRc op:
  75. return Register(op.Rc);
  76. }
  77. throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\".");
  78. }
  79. public static Operand[] GetHalfSrcA(EmitterContext context)
  80. {
  81. OpCode op = context.CurrOp;
  82. bool absoluteA = false, negateA = false;
  83. if (op is IOpCodeCbuf || op is IOpCodeImm)
  84. {
  85. negateA = op.RawOpCode.Extract(43);
  86. absoluteA = op.RawOpCode.Extract(44);
  87. }
  88. else if (op is IOpCodeReg)
  89. {
  90. absoluteA = op.RawOpCode.Extract(44);
  91. }
  92. else if (op is OpCodeAluImm32 && op.Emitter == InstEmit.Hadd2)
  93. {
  94. negateA = op.RawOpCode.Extract(56);
  95. }
  96. FPHalfSwizzle swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(47, 2);
  97. Operand[] operands = GetHalfUnpacked(context, GetSrcA(context), swizzle);
  98. return FPAbsNeg(context, operands, absoluteA, negateA);
  99. }
  100. public static Operand[] GetHalfSrcB(EmitterContext context)
  101. {
  102. OpCode op = context.CurrOp;
  103. FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
  104. bool absoluteB = false, negateB = false;
  105. if (op is IOpCodeReg)
  106. {
  107. swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(28, 2);
  108. absoluteB = op.RawOpCode.Extract(30);
  109. negateB = op.RawOpCode.Extract(31);
  110. }
  111. else if (op is IOpCodeCbuf)
  112. {
  113. swizzle = FPHalfSwizzle.FP32;
  114. absoluteB = op.RawOpCode.Extract(54);
  115. }
  116. Operand[] operands = GetHalfUnpacked(context, GetSrcB(context), swizzle);
  117. return FPAbsNeg(context, operands, absoluteB, negateB);
  118. }
  119. public static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg)
  120. {
  121. for (int index = 0; index < operands.Length; index++)
  122. {
  123. operands[index] = context.FPAbsNeg(operands[index], abs, neg);
  124. }
  125. return operands;
  126. }
  127. public static Operand[] GetHalfUnpacked(EmitterContext context, Operand src, FPHalfSwizzle swizzle)
  128. {
  129. switch (swizzle)
  130. {
  131. case FPHalfSwizzle.FP16:
  132. return new Operand[]
  133. {
  134. context.UnpackHalf2x16Low (src),
  135. context.UnpackHalf2x16High(src)
  136. };
  137. case FPHalfSwizzle.FP32: return new Operand[] { src, src };
  138. case FPHalfSwizzle.DupH0:
  139. return new Operand[]
  140. {
  141. context.UnpackHalf2x16Low(src),
  142. context.UnpackHalf2x16Low(src)
  143. };
  144. case FPHalfSwizzle.DupH1:
  145. return new Operand[]
  146. {
  147. context.UnpackHalf2x16High(src),
  148. context.UnpackHalf2x16High(src)
  149. };
  150. }
  151. throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
  152. }
  153. public static Operand GetHalfPacked(EmitterContext context, Operand[] results)
  154. {
  155. OpCode op = context.CurrOp;
  156. FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
  157. if (!(op is OpCodeAluImm32))
  158. {
  159. swizzle = (FPHalfSwizzle)context.CurrOp.RawOpCode.Extract(49, 2);
  160. }
  161. switch (swizzle)
  162. {
  163. case FPHalfSwizzle.FP16: return context.PackHalf2x16(results[0], results[1]);
  164. case FPHalfSwizzle.FP32: return results[0];
  165. case FPHalfSwizzle.DupH0:
  166. {
  167. Operand h1 = GetHalfDest(context, isHigh: true);
  168. return context.PackHalf2x16(results[0], h1);
  169. }
  170. case FPHalfSwizzle.DupH1:
  171. {
  172. Operand h0 = GetHalfDest(context, isHigh: false);
  173. return context.PackHalf2x16(h0, results[1]);
  174. }
  175. }
  176. throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
  177. }
  178. public static Operand GetHalfDest(EmitterContext context, bool isHigh)
  179. {
  180. if (isHigh)
  181. {
  182. return context.UnpackHalf2x16High(GetDest(context));
  183. }
  184. else
  185. {
  186. return context.UnpackHalf2x16Low(GetDest(context));
  187. }
  188. }
  189. public static Operand GetPredicate39(EmitterContext context)
  190. {
  191. IOpCodeAlu op = (IOpCodeAlu)context.CurrOp;
  192. Operand local = Register(op.Predicate39);
  193. if (op.InvertP)
  194. {
  195. local = context.BitwiseNot(local);
  196. }
  197. return local;
  198. }
  199. public static Operand SignExtendTo32(EmitterContext context, Operand src, int srcBits)
  200. {
  201. return context.BitfieldExtractS32(src, Const(0), Const(srcBits));
  202. }
  203. public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits)
  204. {
  205. int mask = (int)(0xffffffffu >> (32 - srcBits));
  206. return context.BitwiseAnd(src, Const(mask));
  207. }
  208. }
  209. }