emit_glasm_floating_point.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <string_view>
  5. #include "shader_recompiler/backend/glasm/emit_context.h"
  6. #include "shader_recompiler/backend/glasm/emit_glasm_instructions.h"
  7. #include "shader_recompiler/frontend/ir/value.h"
  8. namespace Shader::Backend::GLASM {
  9. namespace {
  10. template <typename InputType>
  11. void Compare(EmitContext& ctx, IR::Inst& inst, InputType lhs, InputType rhs, std::string_view op,
  12. std::string_view type, bool ordered, bool inequality = false) {
  13. const Register ret{ctx.reg_alloc.Define(inst)};
  14. ctx.Add("{}.{} RC.x,{},{};", op, type, lhs, rhs);
  15. if (ordered && inequality) {
  16. ctx.Add("SEQ.{} RC.y,{},{};"
  17. "SEQ.{} RC.z,{},{};"
  18. "AND.U RC.x,RC.x,RC.y;"
  19. "AND.U RC.x,RC.x,RC.z;"
  20. "SNE.S {}.x,RC.x,0;",
  21. type, lhs, lhs, type, rhs, rhs, ret);
  22. } else if (ordered) {
  23. ctx.Add("SNE.S {}.x,RC.x,0;", ret);
  24. } else {
  25. ctx.Add("SNE.{} RC.y,{},{};"
  26. "SNE.{} RC.z,{},{};"
  27. "OR.U RC.x,RC.x,RC.y;"
  28. "OR.U RC.x,RC.x,RC.z;"
  29. "SNE.S {}.x,RC.x,0;",
  30. type, lhs, lhs, type, rhs, rhs, ret);
  31. }
  32. }
  33. template <typename InputType>
  34. void Clamp(EmitContext& ctx, Register ret, InputType value, InputType min_value,
  35. InputType max_value, std::string_view type) {
  36. // Call MAX first to properly clamp nan to min_value instead
  37. ctx.Add("MAX.{} RC.x,{},{};"
  38. "MIN.{} {}.x,RC.x,{};",
  39. type, min_value, value, type, ret, max_value);
  40. }
  41. } // Anonymous namespace
  42. void EmitFPAbs16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
  43. [[maybe_unused]] Register value) {
  44. throw NotImplementedException("GLASM instruction");
  45. }
  46. void EmitFPAbs32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  47. ctx.Add("MOV.F {}.x,|{}|;", inst, value);
  48. }
  49. void EmitFPAbs64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value) {
  50. ctx.LongAdd("MOV.F64 {}.x,|{}|;", inst, value);
  51. }
  52. void EmitFPAdd16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
  53. [[maybe_unused]] Register a, [[maybe_unused]] Register b) {
  54. throw NotImplementedException("GLASM instruction");
  55. }
  56. void EmitFPAdd32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b) {
  57. ctx.Add("ADD.F {}.x,{},{};", inst, a, b);
  58. }
  59. void EmitFPAdd64(EmitContext& ctx, IR::Inst& inst, ScalarF64 a, ScalarF64 b) {
  60. ctx.LongAdd("ADD.F64 {}.x,{},{};", inst, a, b);
  61. }
  62. void EmitFPFma16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
  63. [[maybe_unused]] Register a, [[maybe_unused]] Register b,
  64. [[maybe_unused]] Register c) {
  65. throw NotImplementedException("GLASM instruction");
  66. }
  67. void EmitFPFma32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b, ScalarF32 c) {
  68. ctx.Add("MAD.F {}.x,{},{},{};", inst, a, b, c);
  69. }
  70. void EmitFPFma64(EmitContext& ctx, IR::Inst& inst, ScalarF64 a, ScalarF64 b, ScalarF64 c) {
  71. ctx.LongAdd("MAD.F64 {}.x,{},{},{};", inst, a, b, c);
  72. }
  73. void EmitFPMax32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b) {
  74. ctx.Add("MAX.F {}.x,{},{};", inst, a, b);
  75. }
  76. void EmitFPMax64(EmitContext& ctx, IR::Inst& inst, ScalarF64 a, ScalarF64 b) {
  77. ctx.LongAdd("MAX.F64 {}.x,{},{};", inst, a, b);
  78. }
  79. void EmitFPMin32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b) {
  80. ctx.Add("MIN.F {}.x,{},{};", inst, a, b);
  81. }
  82. void EmitFPMin64(EmitContext& ctx, IR::Inst& inst, ScalarF64 a, ScalarF64 b) {
  83. ctx.LongAdd("MIN.F64 {}.x,{},{};", inst, a, b);
  84. }
  85. void EmitFPMul16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
  86. [[maybe_unused]] Register a, [[maybe_unused]] Register b) {
  87. throw NotImplementedException("GLASM instruction");
  88. }
  89. void EmitFPMul32(EmitContext& ctx, IR::Inst& inst, ScalarF32 a, ScalarF32 b) {
  90. ctx.Add("MUL.F {}.x,{},{};", inst, a, b);
  91. }
  92. void EmitFPMul64(EmitContext& ctx, IR::Inst& inst, ScalarF64 a, ScalarF64 b) {
  93. ctx.LongAdd("MUL.F64 {}.x,{},{};", inst, a, b);
  94. }
  95. void EmitFPNeg16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  96. throw NotImplementedException("GLASM instruction");
  97. }
  98. void EmitFPNeg32(EmitContext& ctx, IR::Inst& inst, ScalarRegister value) {
  99. ctx.Add("MOV.F {}.x,-{};", inst, value);
  100. }
  101. void EmitFPNeg64(EmitContext& ctx, IR::Inst& inst, Register value) {
  102. ctx.LongAdd("MOV.F64 {}.x,-{};", inst, value);
  103. }
  104. void EmitFPSin(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  105. ctx.Add("SIN {}.x,{};", inst, value);
  106. }
  107. void EmitFPCos(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  108. ctx.Add("COS {}.x,{};", inst, value);
  109. }
  110. void EmitFPExp2(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  111. ctx.Add("EX2 {}.x,{};", inst, value);
  112. }
  113. void EmitFPLog2(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  114. ctx.Add("LG2 {}.x,{};", inst, value);
  115. }
  116. void EmitFPRecip32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  117. ctx.Add("RCP {}.x,{};", inst, value);
  118. }
  119. void EmitFPRecip64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  120. throw NotImplementedException("GLASM instruction");
  121. }
  122. void EmitFPRecipSqrt32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  123. ctx.Add("RSQ {}.x,{};", inst, value);
  124. }
  125. void EmitFPRecipSqrt64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  126. throw NotImplementedException("GLASM instruction");
  127. }
  128. void EmitFPSqrt(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  129. const Register ret{ctx.reg_alloc.Define(inst)};
  130. ctx.Add("RSQ RC.x,{};RCP {}.x,RC.x;", value, ret);
  131. }
  132. void EmitFPSaturate16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  133. throw NotImplementedException("GLASM instruction");
  134. }
  135. void EmitFPSaturate32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  136. ctx.Add("MOV.F.SAT {}.x,{};", inst, value);
  137. }
  138. void EmitFPSaturate64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  139. throw NotImplementedException("GLASM instruction");
  140. }
  141. void EmitFPClamp16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value,
  142. [[maybe_unused]] Register min_value, [[maybe_unused]] Register max_value) {
  143. throw NotImplementedException("GLASM instruction");
  144. }
  145. void EmitFPClamp32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value, ScalarF32 min_value,
  146. ScalarF32 max_value) {
  147. Clamp(ctx, ctx.reg_alloc.Define(inst), value, min_value, max_value, "F");
  148. }
  149. void EmitFPClamp64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value, ScalarF64 min_value,
  150. ScalarF64 max_value) {
  151. Clamp(ctx, ctx.reg_alloc.LongDefine(inst), value, min_value, max_value, "F64");
  152. }
  153. void EmitFPRoundEven16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  154. throw NotImplementedException("GLASM instruction");
  155. }
  156. void EmitFPRoundEven32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  157. ctx.Add("ROUND.F {}.x,{};", inst, value);
  158. }
  159. void EmitFPRoundEven64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value) {
  160. ctx.LongAdd("ROUND.F64 {}.x,{};", inst, value);
  161. }
  162. void EmitFPFloor16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  163. throw NotImplementedException("GLASM instruction");
  164. }
  165. void EmitFPFloor32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  166. ctx.Add("FLR.F {}.x,{};", inst, value);
  167. }
  168. void EmitFPFloor64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value) {
  169. ctx.LongAdd("FLR.F64 {}.x,{};", inst, value);
  170. }
  171. void EmitFPCeil16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  172. throw NotImplementedException("GLASM instruction");
  173. }
  174. void EmitFPCeil32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  175. ctx.Add("CEIL.F {}.x,{};", inst, value);
  176. }
  177. void EmitFPCeil64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value) {
  178. ctx.LongAdd("CEIL.F64 {}.x,{};", inst, value);
  179. }
  180. void EmitFPTrunc16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  181. throw NotImplementedException("GLASM instruction");
  182. }
  183. void EmitFPTrunc32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  184. ctx.Add("TRUNC.F {}.x,{};", inst, value);
  185. }
  186. void EmitFPTrunc64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value) {
  187. ctx.LongAdd("TRUNC.F64 {}.x,{};", inst, value);
  188. }
  189. void EmitFPOrdEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  190. [[maybe_unused]] Register rhs) {
  191. throw NotImplementedException("GLASM instruction");
  192. }
  193. void EmitFPOrdEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  194. Compare(ctx, inst, lhs, rhs, "SEQ", "F", true);
  195. }
  196. void EmitFPOrdEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  197. Compare(ctx, inst, lhs, rhs, "SEQ", "F64", true);
  198. }
  199. void EmitFPUnordEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  200. [[maybe_unused]] Register rhs) {
  201. throw NotImplementedException("GLASM instruction");
  202. }
  203. void EmitFPUnordEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  204. Compare(ctx, inst, lhs, rhs, "SEQ", "F", false);
  205. }
  206. void EmitFPUnordEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  207. Compare(ctx, inst, lhs, rhs, "SEQ", "F64", false);
  208. }
  209. void EmitFPOrdNotEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  210. [[maybe_unused]] Register rhs) {
  211. throw NotImplementedException("GLASM instruction");
  212. }
  213. void EmitFPOrdNotEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  214. Compare(ctx, inst, lhs, rhs, "SNE", "F", true, true);
  215. }
  216. void EmitFPOrdNotEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  217. Compare(ctx, inst, lhs, rhs, "SNE", "F64", true, true);
  218. }
  219. void EmitFPUnordNotEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  220. [[maybe_unused]] Register rhs) {
  221. throw NotImplementedException("GLASM instruction");
  222. }
  223. void EmitFPUnordNotEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  224. Compare(ctx, inst, lhs, rhs, "SNE", "F", false, true);
  225. }
  226. void EmitFPUnordNotEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  227. Compare(ctx, inst, lhs, rhs, "SNE", "F64", false, true);
  228. }
  229. void EmitFPOrdLessThan16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  230. [[maybe_unused]] Register rhs) {
  231. throw NotImplementedException("GLASM instruction");
  232. }
  233. void EmitFPOrdLessThan32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  234. Compare(ctx, inst, lhs, rhs, "SLT", "F", true);
  235. }
  236. void EmitFPOrdLessThan64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  237. Compare(ctx, inst, lhs, rhs, "SLT", "F64", true);
  238. }
  239. void EmitFPUnordLessThan16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  240. [[maybe_unused]] Register rhs) {
  241. throw NotImplementedException("GLASM instruction");
  242. }
  243. void EmitFPUnordLessThan32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  244. Compare(ctx, inst, lhs, rhs, "SLT", "F", false);
  245. }
  246. void EmitFPUnordLessThan64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  247. Compare(ctx, inst, lhs, rhs, "SLT", "F64", false);
  248. }
  249. void EmitFPOrdGreaterThan16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  250. [[maybe_unused]] Register rhs) {
  251. throw NotImplementedException("GLASM instruction");
  252. }
  253. void EmitFPOrdGreaterThan32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  254. Compare(ctx, inst, lhs, rhs, "SGT", "F", true);
  255. }
  256. void EmitFPOrdGreaterThan64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  257. Compare(ctx, inst, lhs, rhs, "SGT", "F64", true);
  258. }
  259. void EmitFPUnordGreaterThan16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  260. [[maybe_unused]] Register rhs) {
  261. throw NotImplementedException("GLASM instruction");
  262. }
  263. void EmitFPUnordGreaterThan32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  264. Compare(ctx, inst, lhs, rhs, "SGT", "F", false);
  265. }
  266. void EmitFPUnordGreaterThan64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  267. Compare(ctx, inst, lhs, rhs, "SGT", "F64", false);
  268. }
  269. void EmitFPOrdLessThanEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  270. [[maybe_unused]] Register rhs) {
  271. throw NotImplementedException("GLASM instruction");
  272. }
  273. void EmitFPOrdLessThanEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  274. Compare(ctx, inst, lhs, rhs, "SLE", "F", true);
  275. }
  276. void EmitFPOrdLessThanEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  277. Compare(ctx, inst, lhs, rhs, "SLE", "F64", true);
  278. }
  279. void EmitFPUnordLessThanEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  280. [[maybe_unused]] Register rhs) {
  281. throw NotImplementedException("GLASM instruction");
  282. }
  283. void EmitFPUnordLessThanEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  284. Compare(ctx, inst, lhs, rhs, "SLE", "F", false);
  285. }
  286. void EmitFPUnordLessThanEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  287. Compare(ctx, inst, lhs, rhs, "SLE", "F64", false);
  288. }
  289. void EmitFPOrdGreaterThanEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  290. [[maybe_unused]] Register rhs) {
  291. throw NotImplementedException("GLASM instruction");
  292. }
  293. void EmitFPOrdGreaterThanEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  294. Compare(ctx, inst, lhs, rhs, "SGE", "F", true);
  295. }
  296. void EmitFPOrdGreaterThanEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  297. Compare(ctx, inst, lhs, rhs, "SGE", "F64", true);
  298. }
  299. void EmitFPUnordGreaterThanEqual16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register lhs,
  300. [[maybe_unused]] Register rhs) {
  301. throw NotImplementedException("GLASM instruction");
  302. }
  303. void EmitFPUnordGreaterThanEqual32(EmitContext& ctx, IR::Inst& inst, ScalarF32 lhs, ScalarF32 rhs) {
  304. Compare(ctx, inst, lhs, rhs, "SGE", "F", false);
  305. }
  306. void EmitFPUnordGreaterThanEqual64(EmitContext& ctx, IR::Inst& inst, ScalarF64 lhs, ScalarF64 rhs) {
  307. Compare(ctx, inst, lhs, rhs, "SGE", "F64", false);
  308. }
  309. void EmitFPIsNan16([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] Register value) {
  310. throw NotImplementedException("GLASM instruction");
  311. }
  312. void EmitFPIsNan32(EmitContext& ctx, IR::Inst& inst, ScalarF32 value) {
  313. Compare(ctx, inst, value, value, "SNE", "F", true, false);
  314. }
  315. void EmitFPIsNan64(EmitContext& ctx, IR::Inst& inst, ScalarF64 value) {
  316. Compare(ctx, inst, value, value, "SNE", "F64", true, false);
  317. }
  318. } // namespace Shader::Backend::GLASM