reg_alloc.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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/reg_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 Representation(Id id) {
  13. if (id.is_condition_code != 0) {
  14. throw NotImplementedException("Condition code");
  15. }
  16. if (id.is_spill != 0) {
  17. throw NotImplementedException("Spilling");
  18. }
  19. const u32 index{static_cast<u32>(id.index)};
  20. return fmt::format("R{}", index);
  21. }
  22. std::string FormatFloat(std::string_view value, IR::Type type) {
  23. // TODO: Confirm FP64 nan/inf
  24. if (type == IR::Type::F32) {
  25. if (value == "nan") {
  26. return "uintBitsToFloat(0x7fc00000)";
  27. }
  28. if (value == "inf") {
  29. return "uintBitsToFloat(0x7f800000)";
  30. }
  31. if (value == "-inf") {
  32. return "uintBitsToFloat(0xff800000)";
  33. }
  34. }
  35. const bool needs_dot = value.find_first_of('.') == std::string_view::npos;
  36. const bool needs_suffix = !value.ends_with('f');
  37. const auto suffix = type == IR::Type::F32 ? "f" : "lf";
  38. return fmt::format("{}{}{}", value, needs_dot ? "." : "", needs_suffix ? suffix : "");
  39. }
  40. std::string MakeImm(const IR::Value& value) {
  41. switch (value.Type()) {
  42. case IR::Type::U1:
  43. return fmt::format("{}", value.U1() ? "true" : "false");
  44. case IR::Type::U32:
  45. return fmt::format("{}u", value.U32());
  46. case IR::Type::F32:
  47. return FormatFloat(fmt::format("{}", value.F32()), IR::Type::F32);
  48. case IR::Type::U64:
  49. return fmt::format("{}ul", value.U64());
  50. case IR::Type::F64:
  51. return FormatFloat(fmt::format("{}", value.F64()), IR::Type::F64);
  52. case IR::Type::Void:
  53. return "";
  54. default:
  55. throw NotImplementedException("Immediate type {}", value.Type());
  56. }
  57. }
  58. } // Anonymous namespace
  59. std::string RegAlloc::Define(IR::Inst& inst) {
  60. const Id id{Alloc()};
  61. inst.SetDefinition<Id>(id);
  62. return Representation(id);
  63. }
  64. std::string RegAlloc::Define(IR::Inst& inst, Type type) {
  65. const Id id{Alloc()};
  66. std::string type_str = "";
  67. if (!register_defined[id.index]) {
  68. register_defined[id.index] = true;
  69. // type_str = GetGlslType(type);
  70. reg_types.push_back(GetGlslType(type));
  71. ++num_used_registers;
  72. }
  73. inst.SetDefinition<Id>(id);
  74. return type_str + Representation(id);
  75. }
  76. std::string RegAlloc::Define(IR::Inst& inst, IR::Type type) {
  77. return Define(inst, RegType(type));
  78. }
  79. std::string RegAlloc::Consume(const IR::Value& value) {
  80. return value.IsImmediate() ? MakeImm(value) : Consume(*value.InstRecursive());
  81. }
  82. std::string RegAlloc::Consume(IR::Inst& inst) {
  83. const Id id{inst.Definition<Id>()};
  84. inst.DestructiveRemoveUsage();
  85. // TODO: reuse variables of same type if possible
  86. // if (!inst.HasUses()) {
  87. // Free(id);
  88. // }
  89. return Representation(inst.Definition<Id>());
  90. }
  91. Type RegAlloc::RegType(IR::Type type) {
  92. switch (type) {
  93. case IR::Type::U1:
  94. return Type::U1;
  95. case IR::Type::U32:
  96. return Type::U32;
  97. case IR::Type::F32:
  98. return Type::F32;
  99. case IR::Type::U64:
  100. return Type::U64;
  101. case IR::Type::F64:
  102. return Type::F64;
  103. default:
  104. throw NotImplementedException("IR type {}", type);
  105. }
  106. }
  107. std::string RegAlloc::GetGlslType(Type type) {
  108. switch (type) {
  109. case Type::U1:
  110. return "bool ";
  111. case Type::F16x2:
  112. return "f16vec2 ";
  113. case Type::U32:
  114. return "uint ";
  115. case Type::S32:
  116. return "int ";
  117. case Type::F32:
  118. return "float ";
  119. case Type::S64:
  120. return "int64_t ";
  121. case Type::U64:
  122. return "uint64_t ";
  123. case Type::F64:
  124. return "double ";
  125. case Type::U32x2:
  126. return "uvec2 ";
  127. case Type::F32x2:
  128. return "vec2 ";
  129. case Type::U32x3:
  130. return "uvec3 ";
  131. case Type::F32x3:
  132. return "vec3 ";
  133. case Type::U32x4:
  134. return "uvec4 ";
  135. case Type::F32x4:
  136. return "vec4 ";
  137. case Type::Void:
  138. return "";
  139. default:
  140. throw NotImplementedException("Type {}", type);
  141. }
  142. }
  143. std::string RegAlloc::GetGlslType(IR::Type type) {
  144. return GetGlslType(RegType(type));
  145. }
  146. Id RegAlloc::Alloc() {
  147. if (num_used_registers < NUM_REGS) {
  148. for (size_t reg = 0; reg < NUM_REGS; ++reg) {
  149. if (register_use[reg]) {
  150. continue;
  151. }
  152. register_use[reg] = true;
  153. Id ret{};
  154. ret.is_valid.Assign(1);
  155. ret.is_long.Assign(0);
  156. ret.is_spill.Assign(0);
  157. ret.is_condition_code.Assign(0);
  158. ret.index.Assign(static_cast<u32>(reg));
  159. return ret;
  160. }
  161. }
  162. throw NotImplementedException("Register spilling");
  163. }
  164. void RegAlloc::Free(Id id) {
  165. if (id.is_spill != 0) {
  166. throw NotImplementedException("Free spill");
  167. }
  168. register_use[id.index] = false;
  169. }
  170. } // namespace Shader::Backend::GLSL