InstEmitFloatArithmetic.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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.InstEmitAluHelper;
  5. using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
  6. using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
  7. namespace Ryujinx.Graphics.Shader.Instructions
  8. {
  9. static partial class InstEmit
  10. {
  11. public static void DaddR(EmitterContext context)
  12. {
  13. InstDaddR op = context.GetOp<InstDaddR>();
  14. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  15. var srcB = GetSrcReg(context, op.SrcB, isFP64: true);
  16. EmitFadd(context, Instruction.FP64, srcA, srcB, op.Dest, op.NegA, op.NegB, op.AbsA, op.AbsB, false, op.WriteCC);
  17. }
  18. public static void DaddI(EmitterContext context)
  19. {
  20. InstDaddI op = context.GetOp<InstDaddI>();
  21. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  22. var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20), isFP64: true);
  23. EmitFadd(context, Instruction.FP64, srcA, srcB, op.Dest, op.NegA, op.NegB, op.AbsA, op.AbsB, false, op.WriteCC);
  24. }
  25. public static void DaddC(EmitterContext context)
  26. {
  27. InstDaddC op = context.GetOp<InstDaddC>();
  28. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  29. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset, isFP64: true);
  30. EmitFadd(context, Instruction.FP64, srcA, srcB, op.Dest, op.NegA, op.NegB, op.AbsA, op.AbsB, false, op.WriteCC);
  31. }
  32. public static void DfmaR(EmitterContext context)
  33. {
  34. InstDfmaR op = context.GetOp<InstDfmaR>();
  35. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  36. var srcB = GetSrcReg(context, op.SrcB, isFP64: true);
  37. var srcC = GetSrcReg(context, op.SrcC, isFP64: true);
  38. EmitFfma(context, Instruction.FP64, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, false, op.WriteCC);
  39. }
  40. public static void DfmaI(EmitterContext context)
  41. {
  42. InstDfmaI op = context.GetOp<InstDfmaI>();
  43. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  44. var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20), isFP64: true);
  45. var srcC = GetSrcReg(context, op.SrcC, isFP64: true);
  46. EmitFfma(context, Instruction.FP64, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, false, op.WriteCC);
  47. }
  48. public static void DfmaC(EmitterContext context)
  49. {
  50. InstDfmaC op = context.GetOp<InstDfmaC>();
  51. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  52. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset, isFP64: true);
  53. var srcC = GetSrcReg(context, op.SrcC, isFP64: true);
  54. EmitFfma(context, Instruction.FP64, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, false, op.WriteCC);
  55. }
  56. public static void DfmaRc(EmitterContext context)
  57. {
  58. InstDfmaRc op = context.GetOp<InstDfmaRc>();
  59. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  60. var srcB = GetSrcReg(context, op.SrcC, isFP64: true);
  61. var srcC = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset, isFP64: true);
  62. EmitFfma(context, Instruction.FP64, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, false, op.WriteCC);
  63. }
  64. public static void DmulR(EmitterContext context)
  65. {
  66. InstDmulR op = context.GetOp<InstDmulR>();
  67. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  68. var srcB = GetSrcReg(context, op.SrcB, isFP64: true);
  69. EmitFmul(context, Instruction.FP64, MultiplyScale.NoScale, srcA, srcB, op.Dest, op.NegA, false, op.WriteCC);
  70. }
  71. public static void DmulI(EmitterContext context)
  72. {
  73. InstDmulI op = context.GetOp<InstDmulI>();
  74. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  75. var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20), isFP64: true);
  76. EmitFmul(context, Instruction.FP64, MultiplyScale.NoScale, srcA, srcB, op.Dest, op.NegA, false, op.WriteCC);
  77. }
  78. public static void DmulC(EmitterContext context)
  79. {
  80. InstDmulC op = context.GetOp<InstDmulC>();
  81. var srcA = GetSrcReg(context, op.SrcA, isFP64: true);
  82. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset, isFP64: true);
  83. EmitFmul(context, Instruction.FP64, MultiplyScale.NoScale, srcA, srcB, op.Dest, op.NegA, false, op.WriteCC);
  84. }
  85. public static void FaddR(EmitterContext context)
  86. {
  87. InstFaddR op = context.GetOp<InstFaddR>();
  88. var srcA = GetSrcReg(context, op.SrcA);
  89. var srcB = GetSrcReg(context, op.SrcB);
  90. EmitFadd(context, Instruction.FP32, srcA, srcB, op.Dest, op.NegA, op.NegB, op.AbsA, op.AbsB, op.Sat, op.WriteCC);
  91. }
  92. public static void FaddI(EmitterContext context)
  93. {
  94. InstFaddI op = context.GetOp<InstFaddI>();
  95. var srcA = GetSrcReg(context, op.SrcA);
  96. var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20));
  97. EmitFadd(context, Instruction.FP32, srcA, srcB, op.Dest, op.NegA, op.NegB, op.AbsA, op.AbsB, op.Sat, op.WriteCC);
  98. }
  99. public static void FaddC(EmitterContext context)
  100. {
  101. InstFaddC op = context.GetOp<InstFaddC>();
  102. var srcA = GetSrcReg(context, op.SrcA);
  103. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  104. EmitFadd(context, Instruction.FP32, srcA, srcB, op.Dest, op.NegA, op.NegB, op.AbsA, op.AbsB, op.Sat, op.WriteCC);
  105. }
  106. public static void Fadd32i(EmitterContext context)
  107. {
  108. InstFadd32i op = context.GetOp<InstFadd32i>();
  109. var srcA = GetSrcReg(context, op.SrcA);
  110. var srcB = GetSrcImm(context, op.Imm32);
  111. EmitFadd(context, Instruction.FP32, srcA, srcB, op.Dest, op.NegA, op.NegB, op.AbsA, op.AbsB, false, op.WriteCC);
  112. }
  113. public static void FfmaR(EmitterContext context)
  114. {
  115. InstFfmaR op = context.GetOp<InstFfmaR>();
  116. var srcA = GetSrcReg(context, op.SrcA);
  117. var srcB = GetSrcReg(context, op.SrcB);
  118. var srcC = GetSrcReg(context, op.SrcC);
  119. EmitFfma(context, Instruction.FP32, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, op.Sat, op.WriteCC);
  120. }
  121. public static void FfmaI(EmitterContext context)
  122. {
  123. InstFfmaI op = context.GetOp<InstFfmaI>();
  124. var srcA = GetSrcReg(context, op.SrcA);
  125. var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20));
  126. var srcC = GetSrcReg(context, op.SrcC);
  127. EmitFfma(context, Instruction.FP32, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, op.Sat, op.WriteCC);
  128. }
  129. public static void FfmaC(EmitterContext context)
  130. {
  131. InstFfmaC op = context.GetOp<InstFfmaC>();
  132. var srcA = GetSrcReg(context, op.SrcA);
  133. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  134. var srcC = GetSrcReg(context, op.SrcC);
  135. EmitFfma(context, Instruction.FP32, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, op.Sat, op.WriteCC);
  136. }
  137. public static void FfmaRc(EmitterContext context)
  138. {
  139. InstFfmaRc op = context.GetOp<InstFfmaRc>();
  140. var srcA = GetSrcReg(context, op.SrcA);
  141. var srcB = GetSrcReg(context, op.SrcC);
  142. var srcC = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  143. EmitFfma(context, Instruction.FP32, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, op.Sat, op.WriteCC);
  144. }
  145. public static void Ffma32i(EmitterContext context)
  146. {
  147. InstFfma32i op = context.GetOp<InstFfma32i>();
  148. var srcA = GetSrcReg(context, op.SrcA);
  149. var srcB = GetSrcImm(context, op.Imm32);
  150. var srcC = GetSrcReg(context, op.Dest);
  151. EmitFfma(context, Instruction.FP32, srcA, srcB, srcC, op.Dest, op.NegA, op.NegC, op.Sat, op.WriteCC);
  152. }
  153. public static void FmulR(EmitterContext context)
  154. {
  155. InstFmulR op = context.GetOp<InstFmulR>();
  156. var srcA = GetSrcReg(context, op.SrcA);
  157. var srcB = GetSrcReg(context, op.SrcB);
  158. EmitFmul(context, Instruction.FP32, op.Scale, srcA, srcB, op.Dest, op.NegA, op.Sat, op.WriteCC);
  159. }
  160. public static void FmulI(EmitterContext context)
  161. {
  162. InstFmulI op = context.GetOp<InstFmulI>();
  163. var srcA = GetSrcReg(context, op.SrcA);
  164. var srcB = GetSrcImm(context, Imm20ToFloat(op.Imm20));
  165. EmitFmul(context, Instruction.FP32, op.Scale, srcA, srcB, op.Dest, op.NegA, op.Sat, op.WriteCC);
  166. }
  167. public static void FmulC(EmitterContext context)
  168. {
  169. InstFmulC op = context.GetOp<InstFmulC>();
  170. var srcA = GetSrcReg(context, op.SrcA);
  171. var srcB = GetSrcCbuf(context, op.CbufSlot, op.CbufOffset);
  172. EmitFmul(context, Instruction.FP32, op.Scale, srcA, srcB, op.Dest, op.NegA, op.Sat, op.WriteCC);
  173. }
  174. public static void Fmul32i(EmitterContext context)
  175. {
  176. InstFmul32i op = context.GetOp<InstFmul32i>();
  177. var srcA = GetSrcReg(context, op.SrcA);
  178. var srcB = GetSrcImm(context, op.Imm32);
  179. EmitFmul(context, Instruction.FP32, MultiplyScale.NoScale, srcA, srcB, op.Dest, false, op.Sat, op.WriteCC);
  180. }
  181. public static void Hadd2R(EmitterContext context)
  182. {
  183. InstHadd2R op = context.GetOp<InstHadd2R>();
  184. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, op.NegA, op.AbsA);
  185. var srcB = GetHalfSrc(context, op.BSwizzle, op.SrcB, op.NegB, op.AbsB);
  186. EmitHadd2Hmul2(context, op.OFmt, srcA, srcB, isAdd: true, op.Dest, op.Sat);
  187. }
  188. public static void Hadd2I(EmitterContext context)
  189. {
  190. InstHadd2I op = context.GetOp<InstHadd2I>();
  191. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, op.NegA, op.AbsA);
  192. var srcB = GetHalfSrc(context, op.BimmH0, op.BimmH1);
  193. EmitHadd2Hmul2(context, op.OFmt, srcA, srcB, isAdd: true, op.Dest, op.Sat);
  194. }
  195. public static void Hadd2C(EmitterContext context)
  196. {
  197. InstHadd2C op = context.GetOp<InstHadd2C>();
  198. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, op.NegA, op.AbsA);
  199. var srcB = GetHalfSrc(context, HalfSwizzle.F32, op.CbufSlot, op.CbufOffset, op.NegB, op.AbsB);
  200. EmitHadd2Hmul2(context, op.OFmt, srcA, srcB, isAdd: true, op.Dest, op.Sat);
  201. }
  202. public static void Hadd232i(EmitterContext context)
  203. {
  204. InstHadd232i op = context.GetOp<InstHadd232i>();
  205. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, op.NegA, false);
  206. var srcB = GetHalfSrc(context, op.Imm);
  207. EmitHadd2Hmul2(context, OFmt.F16, srcA, srcB, isAdd: true, op.Dest, op.Sat);
  208. }
  209. public static void Hfma2R(EmitterContext context)
  210. {
  211. InstHfma2R op = context.GetOp<InstHfma2R>();
  212. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, false);
  213. var srcB = GetHalfSrc(context, op.BSwizzle, op.SrcB, op.NegA, false);
  214. var srcC = GetHalfSrc(context, op.CSwizzle, op.SrcC, op.NegC, false);
  215. EmitHfma2(context, op.OFmt, srcA, srcB, srcC, op.Dest, op.Sat);
  216. }
  217. public static void Hfma2I(EmitterContext context)
  218. {
  219. InstHfma2I op = context.GetOp<InstHfma2I>();
  220. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, false);
  221. var srcB = GetHalfSrc(context, op.BimmH0, op.BimmH1);
  222. var srcC = GetHalfSrc(context, op.CSwizzle, op.SrcC, op.NegC, false);
  223. EmitHfma2(context, op.OFmt, srcA, srcB, srcC, op.Dest, op.Sat);
  224. }
  225. public static void Hfma2C(EmitterContext context)
  226. {
  227. InstHfma2C op = context.GetOp<InstHfma2C>();
  228. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, false);
  229. var srcB = GetHalfSrc(context, HalfSwizzle.F32, op.CbufSlot, op.CbufOffset, op.NegA, false);
  230. var srcC = GetHalfSrc(context, op.CSwizzle, op.SrcC, op.NegC, false);
  231. EmitHfma2(context, op.OFmt, srcA, srcB, srcC, op.Dest, op.Sat);
  232. }
  233. public static void Hfma2Rc(EmitterContext context)
  234. {
  235. InstHfma2Rc op = context.GetOp<InstHfma2Rc>();
  236. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, false);
  237. var srcB = GetHalfSrc(context, op.CSwizzle, op.SrcC, op.NegA, false);
  238. var srcC = GetHalfSrc(context, HalfSwizzle.F32, op.CbufSlot, op.CbufOffset, op.NegC, false);
  239. EmitHfma2(context, op.OFmt, srcA, srcB, srcC, op.Dest, op.Sat);
  240. }
  241. public static void Hfma232i(EmitterContext context)
  242. {
  243. InstHfma232i op = context.GetOp<InstHfma232i>();
  244. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, false);
  245. var srcB = GetHalfSrc(context, op.Imm);
  246. var srcC = GetHalfSrc(context, HalfSwizzle.F16, op.Dest, op.NegC, false);
  247. EmitHfma2(context, OFmt.F16, srcA, srcB, srcC, op.Dest, saturate: false);
  248. }
  249. public static void Hmul2R(EmitterContext context)
  250. {
  251. InstHmul2R op = context.GetOp<InstHmul2R>();
  252. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, op.AbsA);
  253. var srcB = GetHalfSrc(context, op.BSwizzle, op.SrcB, op.NegA, op.AbsB);
  254. EmitHadd2Hmul2(context, op.OFmt, srcA, srcB, isAdd: false, op.Dest, op.Sat);
  255. }
  256. public static void Hmul2I(EmitterContext context)
  257. {
  258. InstHmul2I op = context.GetOp<InstHmul2I>();
  259. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, op.NegA, op.AbsA);
  260. var srcB = GetHalfSrc(context, op.BimmH0, op.BimmH1);
  261. EmitHadd2Hmul2(context, op.OFmt, srcA, srcB, isAdd: false, op.Dest, op.Sat);
  262. }
  263. public static void Hmul2C(EmitterContext context)
  264. {
  265. InstHmul2C op = context.GetOp<InstHmul2C>();
  266. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, op.AbsA);
  267. var srcB = GetHalfSrc(context, HalfSwizzle.F32, op.CbufSlot, op.CbufOffset, op.NegA, op.AbsB);
  268. EmitHadd2Hmul2(context, op.OFmt, srcA, srcB, isAdd: false, op.Dest, op.Sat);
  269. }
  270. public static void Hmul232i(EmitterContext context)
  271. {
  272. InstHmul232i op = context.GetOp<InstHmul232i>();
  273. var srcA = GetHalfSrc(context, op.ASwizzle, op.SrcA, false, false);
  274. var srcB = GetHalfSrc(context, op.Imm32);
  275. EmitHadd2Hmul2(context, OFmt.F16, srcA, srcB, isAdd: false, op.Dest, op.Sat);
  276. }
  277. private static void EmitFadd(
  278. EmitterContext context,
  279. Instruction fpType,
  280. Operand srcA,
  281. Operand srcB,
  282. int rd,
  283. bool negateA,
  284. bool negateB,
  285. bool absoluteA,
  286. bool absoluteB,
  287. bool saturate,
  288. bool writeCC)
  289. {
  290. bool isFP64 = fpType == Instruction.FP64;
  291. srcA = context.FPAbsNeg(srcA, absoluteA, negateA, fpType);
  292. srcB = context.FPAbsNeg(srcB, absoluteB, negateB, fpType);
  293. Operand res = context.FPSaturate(context.FPAdd(srcA, srcB, fpType), saturate, fpType);
  294. SetDest(context, res, rd, isFP64);
  295. SetFPZnFlags(context, res, writeCC, fpType);
  296. }
  297. private static void EmitFfma(
  298. EmitterContext context,
  299. Instruction fpType,
  300. Operand srcA,
  301. Operand srcB,
  302. Operand srcC,
  303. int rd,
  304. bool negateB,
  305. bool negateC,
  306. bool saturate,
  307. bool writeCC)
  308. {
  309. bool isFP64 = fpType == Instruction.FP64;
  310. srcB = context.FPNegate(srcB, negateB, fpType);
  311. srcC = context.FPNegate(srcC, negateC, fpType);
  312. Operand res = context.FPSaturate(context.FPFusedMultiplyAdd(srcA, srcB, srcC, fpType), saturate, fpType);
  313. SetDest(context, res, rd, isFP64);
  314. SetFPZnFlags(context, res, writeCC, fpType);
  315. }
  316. private static void EmitFmul(
  317. EmitterContext context,
  318. Instruction fpType,
  319. MultiplyScale scale,
  320. Operand srcA,
  321. Operand srcB,
  322. int rd,
  323. bool negateB,
  324. bool saturate,
  325. bool writeCC)
  326. {
  327. bool isFP64 = fpType == Instruction.FP64;
  328. srcB = context.FPNegate(srcB, negateB, fpType);
  329. if (scale != MultiplyScale.NoScale)
  330. {
  331. Operand scaleConst = scale switch
  332. {
  333. MultiplyScale.D2 => ConstF(0.5f),
  334. MultiplyScale.D4 => ConstF(0.25f),
  335. MultiplyScale.D8 => ConstF(0.125f),
  336. MultiplyScale.M2 => ConstF(2f),
  337. MultiplyScale.M4 => ConstF(4f),
  338. MultiplyScale.M8 => ConstF(8f),
  339. _ => ConstF(1f) // Invalid, behave as if it had no scale.
  340. };
  341. if (scaleConst.AsFloat() == 1f)
  342. {
  343. context.Config.GpuAccessor.Log($"Invalid FP multiply scale \"{scale}\".");
  344. }
  345. if (isFP64)
  346. {
  347. scaleConst = context.FP32ConvertToFP64(scaleConst);
  348. }
  349. srcA = context.FPMultiply(srcA, scaleConst, fpType);
  350. }
  351. Operand res = context.FPSaturate(context.FPMultiply(srcA, srcB, fpType), saturate, fpType);
  352. SetDest(context, res, rd, isFP64);
  353. SetFPZnFlags(context, res, writeCC, fpType);
  354. }
  355. private static void EmitHadd2Hmul2(
  356. EmitterContext context,
  357. OFmt swizzle,
  358. Operand[] srcA,
  359. Operand[] srcB,
  360. bool isAdd,
  361. int rd,
  362. bool saturate)
  363. {
  364. Operand[] res = new Operand[2];
  365. for (int index = 0; index < res.Length; index++)
  366. {
  367. if (isAdd)
  368. {
  369. res[index] = context.FPAdd(srcA[index], srcB[index]);
  370. }
  371. else
  372. {
  373. res[index] = context.FPMultiply(srcA[index], srcB[index]);
  374. }
  375. res[index] = context.FPSaturate(res[index], saturate);
  376. }
  377. context.Copy(GetDest(rd), GetHalfPacked(context, swizzle, res, rd));
  378. }
  379. public static void EmitHfma2(
  380. EmitterContext context,
  381. OFmt swizzle,
  382. Operand[] srcA,
  383. Operand[] srcB,
  384. Operand[] srcC,
  385. int rd,
  386. bool saturate)
  387. {
  388. Operand[] res = new Operand[2];
  389. for (int index = 0; index < res.Length; index++)
  390. {
  391. res[index] = context.FPFusedMultiplyAdd(srcA[index], srcB[index], srcC[index]);
  392. res[index] = context.FPSaturate(res[index], saturate);
  393. }
  394. context.Copy(GetDest(rd), GetHalfPacked(context, swizzle, res, rd));
  395. }
  396. }
  397. }