reg_alloc.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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. default:
  53. throw NotImplementedException("Immediate type {}", value.Type());
  54. }
  55. }
  56. } // Anonymous namespace
  57. std::string RegAlloc::Define(IR::Inst& inst, Type type) {
  58. const Id id{Alloc()};
  59. const auto type_str{GetType(type, id.index)};
  60. inst.SetDefinition<Id>(id);
  61. return type_str + Representation(id);
  62. }
  63. std::string RegAlloc::Consume(const IR::Value& value) {
  64. return value.IsImmediate() ? MakeImm(value) : Consume(*value.InstRecursive());
  65. }
  66. std::string RegAlloc::Consume(IR::Inst& inst) {
  67. const Id id{inst.Definition<Id>()};
  68. inst.DestructiveRemoveUsage();
  69. // TODO: reuse variables of same type if possible
  70. // if (!inst.HasUses()) {
  71. // Free(id);
  72. // }
  73. return Representation(inst.Definition<Id>());
  74. }
  75. std::string RegAlloc::GetType(Type type, u32 index) {
  76. if (register_defined[index]) {
  77. return "";
  78. }
  79. register_defined[index] = true;
  80. switch (type) {
  81. case Type::U1:
  82. return "bool ";
  83. case Type::U32:
  84. return "uint ";
  85. case Type::S32:
  86. return "int ";
  87. case Type::F32:
  88. return "float ";
  89. case Type::S64:
  90. return "int64_t ";
  91. case Type::U64:
  92. return "uint64_t ";
  93. case Type::F64:
  94. return "double ";
  95. case Type::U32x2:
  96. return "uvec2 ";
  97. case Type::F32x2:
  98. return "vec2 ";
  99. case Type::Void:
  100. return "";
  101. default:
  102. throw NotImplementedException("Type {}", type);
  103. }
  104. }
  105. Id RegAlloc::Alloc() {
  106. if (num_used_registers < NUM_REGS) {
  107. for (size_t reg = 0; reg < NUM_REGS; ++reg) {
  108. if (register_use[reg]) {
  109. continue;
  110. }
  111. register_use[reg] = true;
  112. Id ret{};
  113. ret.index.Assign(static_cast<u32>(reg));
  114. ret.is_long.Assign(0);
  115. ret.is_spill.Assign(0);
  116. ret.is_condition_code.Assign(0);
  117. return ret;
  118. }
  119. }
  120. throw NotImplementedException("Register spilling");
  121. }
  122. void RegAlloc::Free(Id id) {
  123. if (id.is_spill != 0) {
  124. throw NotImplementedException("Free spill");
  125. }
  126. register_use[id.index] = false;
  127. }
  128. /*static*/ bool RegAlloc::IsAliased(const IR::Inst& inst) {
  129. switch (inst.GetOpcode()) {
  130. case IR::Opcode::Identity:
  131. case IR::Opcode::BitCastU16F16:
  132. case IR::Opcode::BitCastU32F32:
  133. case IR::Opcode::BitCastU64F64:
  134. case IR::Opcode::BitCastF16U16:
  135. case IR::Opcode::BitCastF32U32:
  136. case IR::Opcode::BitCastF64U64:
  137. return true;
  138. default:
  139. return false;
  140. }
  141. }
  142. /*static*/ IR::Inst& RegAlloc::AliasInst(IR::Inst& inst) {
  143. IR::Inst* it{&inst};
  144. while (IsAliased(*it)) {
  145. const IR::Value arg{it->Arg(0)};
  146. if (arg.IsImmediate()) {
  147. break;
  148. }
  149. it = arg.InstRecursive();
  150. }
  151. return *it;
  152. }
  153. } // namespace Shader::Backend::GLSL