var_alloc.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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>
  5. #include <string_view>
  6. #include <fmt/format.h>
  7. #include "shader_recompiler/backend/glsl/var_alloc.h"
  8. #include "shader_recompiler/exception.h"
  9. #include "shader_recompiler/frontend/ir/value.h"
  10. namespace Shader::Backend::GLSL {
  11. namespace {
  12. std::string TypePrefix(GlslVarType type) {
  13. switch (type) {
  14. case GlslVarType::U1:
  15. return "b_";
  16. case GlslVarType::F16x2:
  17. return "f16x2_";
  18. case GlslVarType::U32:
  19. return "u_";
  20. case GlslVarType::F32:
  21. return "f_";
  22. case GlslVarType::U64:
  23. return "u64_";
  24. case GlslVarType::F64:
  25. return "d_";
  26. case GlslVarType::U32x2:
  27. return "u2_";
  28. case GlslVarType::F32x2:
  29. return "f2_";
  30. case GlslVarType::U32x3:
  31. return "u3_";
  32. case GlslVarType::F32x3:
  33. return "f3_";
  34. case GlslVarType::U32x4:
  35. return "u4_";
  36. case GlslVarType::F32x4:
  37. return "f4_";
  38. case GlslVarType::PrecF32:
  39. return "pf_";
  40. case GlslVarType::PrecF64:
  41. return "pd_";
  42. case GlslVarType::Void:
  43. return "";
  44. default:
  45. throw NotImplementedException("Type {}", type);
  46. }
  47. }
  48. std::string FormatFloat(std::string_view value, IR::Type type) {
  49. // TODO: Confirm FP64 nan/inf
  50. if (type == IR::Type::F32) {
  51. if (value == "nan") {
  52. return "utof(0x7fc00000)";
  53. }
  54. if (value == "inf") {
  55. return "utof(0x7f800000)";
  56. }
  57. if (value == "-inf") {
  58. return "utof(0xff800000)";
  59. }
  60. }
  61. if (value.find_first_of('e') != std::string_view::npos) {
  62. // scientific notation
  63. const auto cast{type == IR::Type::F32 ? "float" : "double"};
  64. return fmt::format("{}({})", cast, value);
  65. }
  66. const bool needs_dot{value.find_first_of('.') == std::string_view::npos};
  67. const bool needs_suffix{!value.ends_with('f')};
  68. const auto suffix{type == IR::Type::F32 ? "f" : "lf"};
  69. return fmt::format("{}{}{}", value, needs_dot ? "." : "", needs_suffix ? suffix : "");
  70. }
  71. std::string MakeImm(const IR::Value& value) {
  72. switch (value.Type()) {
  73. case IR::Type::U1:
  74. return fmt::format("{}", value.U1() ? "true" : "false");
  75. case IR::Type::U32:
  76. return fmt::format("{}u", value.U32());
  77. case IR::Type::F32:
  78. return FormatFloat(fmt::format("{}", value.F32()), IR::Type::F32);
  79. case IR::Type::U64:
  80. return fmt::format("{}ul", value.U64());
  81. case IR::Type::F64:
  82. return FormatFloat(fmt::format("{}", value.F64()), IR::Type::F64);
  83. case IR::Type::Void:
  84. return "";
  85. default:
  86. throw NotImplementedException("Immediate type {}", value.Type());
  87. }
  88. }
  89. } // Anonymous namespace
  90. std::string VarAlloc::Representation(u32 index, GlslVarType type) const {
  91. const auto prefix{TypePrefix(type)};
  92. return fmt::format("{}{}", prefix, index);
  93. }
  94. std::string VarAlloc::Representation(Id id) const {
  95. return Representation(id.index, id.type);
  96. }
  97. std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) {
  98. if (inst.HasUses()) {
  99. inst.SetDefinition<Id>(Alloc(type));
  100. return Representation(inst.Definition<Id>());
  101. } else {
  102. Id id{};
  103. id.type.Assign(type);
  104. GetUseTracker(type).uses_temp = true;
  105. inst.SetDefinition<Id>(id);
  106. return 't' + Representation(inst.Definition<Id>());
  107. }
  108. }
  109. std::string VarAlloc::Define(IR::Inst& inst, IR::Type type) {
  110. return Define(inst, RegType(type));
  111. }
  112. std::string VarAlloc::PhiDefine(IR::Inst& inst, IR::Type type) {
  113. return AddDefine(inst, RegType(type));
  114. }
  115. std::string VarAlloc::AddDefine(IR::Inst& inst, GlslVarType type) {
  116. if (inst.HasUses()) {
  117. inst.SetDefinition<Id>(Alloc(type));
  118. return Representation(inst.Definition<Id>());
  119. } else {
  120. return "";
  121. }
  122. return Representation(inst.Definition<Id>());
  123. }
  124. std::string VarAlloc::Consume(const IR::Value& value) {
  125. return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive());
  126. }
  127. std::string VarAlloc::ConsumeInst(IR::Inst& inst) {
  128. inst.DestructiveRemoveUsage();
  129. if (!inst.HasUses()) {
  130. Free(inst.Definition<Id>());
  131. }
  132. return Representation(inst.Definition<Id>());
  133. }
  134. std::string VarAlloc::GetGlslType(IR::Type type) const {
  135. return GetGlslType(RegType(type));
  136. }
  137. Id VarAlloc::Alloc(GlslVarType type) {
  138. auto& use_tracker{GetUseTracker(type)};
  139. const auto num_vars{use_tracker.var_use.size()};
  140. for (size_t var = 0; var < num_vars; ++var) {
  141. if (use_tracker.var_use[var]) {
  142. continue;
  143. }
  144. use_tracker.num_used = std::max(use_tracker.num_used, var + 1);
  145. use_tracker.var_use[var] = true;
  146. Id ret{};
  147. ret.is_valid.Assign(1);
  148. ret.type.Assign(type);
  149. ret.index.Assign(static_cast<u32>(var));
  150. return ret;
  151. }
  152. // Allocate a new variable
  153. use_tracker.var_use.push_back(true);
  154. Id ret{};
  155. ret.is_valid.Assign(1);
  156. ret.type.Assign(type);
  157. ret.index.Assign(static_cast<u32>(use_tracker.num_used));
  158. ++use_tracker.num_used;
  159. return ret;
  160. }
  161. void VarAlloc::Free(Id id) {
  162. if (id.is_valid == 0) {
  163. throw LogicError("Freeing invalid variable");
  164. }
  165. auto& use_tracker{GetUseTracker(id.type)};
  166. use_tracker.var_use[id.index] = false;
  167. }
  168. GlslVarType VarAlloc::RegType(IR::Type type) const {
  169. switch (type) {
  170. case IR::Type::U1:
  171. return GlslVarType::U1;
  172. case IR::Type::U32:
  173. return GlslVarType::U32;
  174. case IR::Type::F32:
  175. return GlslVarType::F32;
  176. case IR::Type::U64:
  177. return GlslVarType::U64;
  178. case IR::Type::F64:
  179. return GlslVarType::F64;
  180. default:
  181. throw NotImplementedException("IR type {}", type);
  182. }
  183. }
  184. std::string VarAlloc::GetGlslType(GlslVarType type) const {
  185. switch (type) {
  186. case GlslVarType::U1:
  187. return "bool";
  188. case GlslVarType::F16x2:
  189. return "f16vec2";
  190. case GlslVarType::U32:
  191. return "uint";
  192. case GlslVarType::F32:
  193. case GlslVarType::PrecF32:
  194. return "float";
  195. case GlslVarType::U64:
  196. return "uint64_t";
  197. case GlslVarType::F64:
  198. case GlslVarType::PrecF64:
  199. return "double";
  200. case GlslVarType::U32x2:
  201. return "uvec2";
  202. case GlslVarType::F32x2:
  203. return "vec2";
  204. case GlslVarType::U32x3:
  205. return "uvec3";
  206. case GlslVarType::F32x3:
  207. return "vec3";
  208. case GlslVarType::U32x4:
  209. return "uvec4";
  210. case GlslVarType::F32x4:
  211. return "vec4";
  212. case GlslVarType::Void:
  213. return "";
  214. default:
  215. throw NotImplementedException("Type {}", type);
  216. }
  217. }
  218. VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) {
  219. switch (type) {
  220. case GlslVarType::U1:
  221. return var_bool;
  222. case GlslVarType::F16x2:
  223. return var_f16x2;
  224. case GlslVarType::U32:
  225. return var_u32;
  226. case GlslVarType::F32:
  227. return var_f32;
  228. case GlslVarType::U64:
  229. return var_u64;
  230. case GlslVarType::F64:
  231. return var_f64;
  232. case GlslVarType::U32x2:
  233. return var_u32x2;
  234. case GlslVarType::F32x2:
  235. return var_f32x2;
  236. case GlslVarType::U32x3:
  237. return var_u32x3;
  238. case GlslVarType::F32x3:
  239. return var_f32x3;
  240. case GlslVarType::U32x4:
  241. return var_u32x4;
  242. case GlslVarType::F32x4:
  243. return var_f32x4;
  244. case GlslVarType::PrecF32:
  245. return var_precf32;
  246. case GlslVarType::PrecF64:
  247. return var_precf64;
  248. default:
  249. throw NotImplementedException("Type {}", type);
  250. }
  251. }
  252. const VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) const {
  253. switch (type) {
  254. case GlslVarType::U1:
  255. return var_bool;
  256. case GlslVarType::F16x2:
  257. return var_f16x2;
  258. case GlslVarType::U32:
  259. return var_u32;
  260. case GlslVarType::F32:
  261. return var_f32;
  262. case GlslVarType::U64:
  263. return var_u64;
  264. case GlslVarType::F64:
  265. return var_f64;
  266. case GlslVarType::U32x2:
  267. return var_u32x2;
  268. case GlslVarType::F32x2:
  269. return var_f32x2;
  270. case GlslVarType::U32x3:
  271. return var_u32x3;
  272. case GlslVarType::F32x3:
  273. return var_f32x3;
  274. case GlslVarType::U32x4:
  275. return var_u32x4;
  276. case GlslVarType::F32x4:
  277. return var_f32x4;
  278. case GlslVarType::PrecF32:
  279. return var_precf32;
  280. case GlslVarType::PrecF64:
  281. return var_precf64;
  282. default:
  283. throw NotImplementedException("Type {}", type);
  284. }
  285. }
  286. } // namespace Shader::Backend::GLSL