InstEmitHelper.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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()
  11. {
  12. return Register(0, RegisterType.Flag);
  13. }
  14. public static Operand GetNF()
  15. {
  16. return Register(1, RegisterType.Flag);
  17. }
  18. public static Operand GetCF()
  19. {
  20. return Register(2, RegisterType.Flag);
  21. }
  22. public static Operand GetVF()
  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 GetDest2(EmitterContext context)
  31. {
  32. Register rd = ((IOpCodeRd)context.CurrOp).Rd;
  33. return Register(rd.Index | 1, rd.Type);
  34. }
  35. public static Operand GetSrcA(EmitterContext context, bool isFP64 = false)
  36. {
  37. IOpCodeRa op = (IOpCodeRa)context.CurrOp;
  38. if (isFP64)
  39. {
  40. return context.PackDouble2x32(Register(op.Ra.Index, op.Ra.Type), Register(op.Ra.Index | 1, op.Ra.Type));
  41. }
  42. else
  43. {
  44. return Register(op.Ra);
  45. }
  46. }
  47. public static Operand GetSrcB(EmitterContext context, FPType floatType)
  48. {
  49. if (floatType == FPType.FP32)
  50. {
  51. return GetSrcB(context);
  52. }
  53. else if (floatType == FPType.FP16)
  54. {
  55. int h = context.CurrOp.RawOpCode.Extract(41, 1);
  56. return GetHalfUnpacked(context, GetSrcB(context), FPHalfSwizzle.FP16)[h];
  57. }
  58. else if (floatType == FPType.FP64)
  59. {
  60. return GetSrcB(context, true);
  61. }
  62. throw new ArgumentException($"Invalid floating point type \"{floatType}\".");
  63. }
  64. public static Operand GetSrcB(EmitterContext context, bool isFP64 = false)
  65. {
  66. if (isFP64)
  67. {
  68. switch (context.CurrOp)
  69. {
  70. case IOpCodeCbuf op:
  71. return context.PackDouble2x32(
  72. context.Config.CreateCbuf(op.Slot, op.Offset),
  73. context.Config.CreateCbuf(op.Slot, op.Offset + 1));
  74. case IOpCodeImmF op:
  75. return context.FP32ConvertToFP64(ConstF(op.Immediate));
  76. case IOpCodeReg op:
  77. return context.PackDouble2x32(Register(op.Rb.Index, op.Rb.Type), Register(op.Rb.Index | 1, op.Rb.Type));
  78. case IOpCodeRegCbuf op:
  79. return context.PackDouble2x32(Register(op.Rc.Index, op.Rc.Type), Register(op.Rc.Index | 1, op.Rc.Type));
  80. }
  81. }
  82. else
  83. {
  84. switch (context.CurrOp)
  85. {
  86. case IOpCodeCbuf op:
  87. return context.Config.CreateCbuf(op.Slot, op.Offset);
  88. case IOpCodeImm op:
  89. return Const(op.Immediate);
  90. case IOpCodeImmF op:
  91. return ConstF(op.Immediate);
  92. case IOpCodeReg op:
  93. return Register(op.Rb);
  94. case IOpCodeRegCbuf op:
  95. return Register(op.Rc);
  96. }
  97. }
  98. throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\".");
  99. }
  100. public static Operand GetSrcC(EmitterContext context, bool isFP64 = false)
  101. {
  102. if (isFP64)
  103. {
  104. switch (context.CurrOp)
  105. {
  106. case IOpCodeRegCbuf op:
  107. return context.PackDouble2x32(
  108. context.Config.CreateCbuf(op.Slot, op.Offset),
  109. context.Config.CreateCbuf(op.Slot, op.Offset + 1));
  110. case IOpCodeRc op:
  111. return context.PackDouble2x32(Register(op.Rc.Index, op.Rc.Type), Register(op.Rc.Index | 1, op.Rc.Type));
  112. }
  113. }
  114. else
  115. {
  116. switch (context.CurrOp)
  117. {
  118. case IOpCodeRegCbuf op:
  119. return context.Config.CreateCbuf(op.Slot, op.Offset);
  120. case IOpCodeRc op:
  121. return Register(op.Rc);
  122. }
  123. }
  124. throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\".");
  125. }
  126. public static Operand[] GetHalfSrcA(EmitterContext context, bool isAdd = false)
  127. {
  128. OpCode op = context.CurrOp;
  129. bool absoluteA = false, negateA = false;
  130. if (op is OpCodeAluImm32 && isAdd)
  131. {
  132. negateA = op.RawOpCode.Extract(56);
  133. }
  134. else if (isAdd || op is IOpCodeCbuf || op is IOpCodeImm)
  135. {
  136. negateA = op.RawOpCode.Extract(43);
  137. absoluteA = op.RawOpCode.Extract(44);
  138. }
  139. else if (op is IOpCodeReg)
  140. {
  141. absoluteA = op.RawOpCode.Extract(44);
  142. }
  143. FPHalfSwizzle swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(47, 2);
  144. Operand[] operands = GetHalfUnpacked(context, GetSrcA(context), swizzle);
  145. return FPAbsNeg(context, operands, absoluteA, negateA);
  146. }
  147. public static Operand[] GetHalfSrcB(EmitterContext context, bool isMul = false)
  148. {
  149. OpCode op = context.CurrOp;
  150. FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
  151. bool absoluteB = false, negateB = false;
  152. if (op is IOpCodeReg)
  153. {
  154. swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(28, 2);
  155. absoluteB = op.RawOpCode.Extract(30);
  156. negateB = op.RawOpCode.Extract(31);
  157. }
  158. else if (op is IOpCodeCbuf)
  159. {
  160. swizzle = FPHalfSwizzle.FP32;
  161. absoluteB = op.RawOpCode.Extract(54);
  162. if (!isMul)
  163. {
  164. negateB = op.RawOpCode.Extract(56);
  165. }
  166. }
  167. Operand[] operands = GetHalfUnpacked(context, GetSrcB(context), swizzle);
  168. return FPAbsNeg(context, operands, absoluteB, negateB);
  169. }
  170. public static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg)
  171. {
  172. for (int index = 0; index < operands.Length; index++)
  173. {
  174. operands[index] = context.FPAbsNeg(operands[index], abs, neg);
  175. }
  176. return operands;
  177. }
  178. public static Operand[] GetHalfUnpacked(EmitterContext context, Operand src, FPHalfSwizzle swizzle)
  179. {
  180. switch (swizzle)
  181. {
  182. case FPHalfSwizzle.FP16:
  183. return new Operand[]
  184. {
  185. context.UnpackHalf2x16Low (src),
  186. context.UnpackHalf2x16High(src)
  187. };
  188. case FPHalfSwizzle.FP32: return new Operand[] { src, src };
  189. case FPHalfSwizzle.DupH0:
  190. return new Operand[]
  191. {
  192. context.UnpackHalf2x16Low(src),
  193. context.UnpackHalf2x16Low(src)
  194. };
  195. case FPHalfSwizzle.DupH1:
  196. return new Operand[]
  197. {
  198. context.UnpackHalf2x16High(src),
  199. context.UnpackHalf2x16High(src)
  200. };
  201. }
  202. throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
  203. }
  204. public static Operand GetHalfPacked(EmitterContext context, Operand[] results)
  205. {
  206. OpCode op = context.CurrOp;
  207. FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
  208. if (!(op is OpCodeAluImm32))
  209. {
  210. swizzle = (FPHalfSwizzle)context.CurrOp.RawOpCode.Extract(49, 2);
  211. }
  212. switch (swizzle)
  213. {
  214. case FPHalfSwizzle.FP16: return context.PackHalf2x16(results[0], results[1]);
  215. case FPHalfSwizzle.FP32: return results[0];
  216. case FPHalfSwizzle.DupH0:
  217. {
  218. Operand h1 = GetHalfDest(context, isHigh: true);
  219. return context.PackHalf2x16(results[0], h1);
  220. }
  221. case FPHalfSwizzle.DupH1:
  222. {
  223. Operand h0 = GetHalfDest(context, isHigh: false);
  224. return context.PackHalf2x16(h0, results[1]);
  225. }
  226. }
  227. throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
  228. }
  229. public static Operand GetHalfDest(EmitterContext context, bool isHigh)
  230. {
  231. if (isHigh)
  232. {
  233. return context.UnpackHalf2x16High(GetDest(context));
  234. }
  235. else
  236. {
  237. return context.UnpackHalf2x16Low(GetDest(context));
  238. }
  239. }
  240. public static Operand GetPredicate39(EmitterContext context)
  241. {
  242. IOpCodePredicate39 op = (IOpCodePredicate39)context.CurrOp;
  243. Operand local = Register(op.Predicate39);
  244. if (op.InvertP)
  245. {
  246. local = context.BitwiseNot(local);
  247. }
  248. return local;
  249. }
  250. public static Operand SignExtendTo32(EmitterContext context, Operand src, int srcBits)
  251. {
  252. return context.BitfieldExtractS32(src, Const(0), Const(srcBits));
  253. }
  254. public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits)
  255. {
  256. int mask = (int)(0xffffffffu >> (32 - srcBits));
  257. return context.BitwiseAnd(src, Const(mask));
  258. }
  259. }
  260. }