reg_alloc.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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. const bool needs_dot = value.find_first_of('.') == std::string_view::npos;
  24. const bool needs_suffix = !value.ends_with('f');
  25. const auto suffix = type == IR::Type::F32 ? "f" : "lf";
  26. return fmt::format("{}{}{}", value, needs_dot ? "." : "", needs_suffix ? suffix : "");
  27. }
  28. std::string MakeImm(const IR::Value& value) {
  29. switch (value.Type()) {
  30. case IR::Type::U1:
  31. return fmt::format("{}", value.U1() ? "true" : "false");
  32. case IR::Type::U32:
  33. return fmt::format("{}u", value.U32());
  34. case IR::Type::F32:
  35. return FormatFloat(fmt::format("{}", value.F32()), IR::Type::F32);
  36. case IR::Type::U64:
  37. return fmt::format("{}ul", value.U64());
  38. case IR::Type::F64:
  39. return FormatFloat(fmt::format("{}", value.F64()), IR::Type::F64);
  40. default:
  41. throw NotImplementedException("Immediate type {}", value.Type());
  42. }
  43. }
  44. } // Anonymous namespace
  45. std::string RegAlloc::Define(IR::Inst& inst, Type type) {
  46. const Id id{Alloc()};
  47. const auto type_str{GetType(type, id.index)};
  48. inst.SetDefinition<Id>(id);
  49. return type_str + Representation(id);
  50. }
  51. std::string RegAlloc::Consume(const IR::Value& value) {
  52. return value.IsImmediate() ? MakeImm(value) : Consume(*value.InstRecursive());
  53. }
  54. std::string RegAlloc::Consume(IR::Inst& inst) {
  55. const Id id{inst.Definition<Id>()};
  56. inst.DestructiveRemoveUsage();
  57. // TODO: reuse variables of same type if possible
  58. // if (!inst.HasUses()) {
  59. // Free(id);
  60. // }
  61. return Representation(inst.Definition<Id>());
  62. }
  63. std::string RegAlloc::GetType(Type type, u32 index) {
  64. if (register_defined[index]) {
  65. return "";
  66. }
  67. register_defined[index] = true;
  68. switch (type) {
  69. case Type::U1:
  70. return "bool ";
  71. case Type::U32:
  72. return "uint ";
  73. case Type::S32:
  74. return "int ";
  75. case Type::F32:
  76. return "float ";
  77. case Type::S64:
  78. return "int64_t ";
  79. case Type::U64:
  80. return "uint64_t ";
  81. case Type::F64:
  82. return "double ";
  83. case Type::U32x2:
  84. return "uvec2 ";
  85. case Type::F32x2:
  86. return "vec2 ";
  87. case Type::Void:
  88. return "";
  89. default:
  90. throw NotImplementedException("Type {}", type);
  91. }
  92. }
  93. Id RegAlloc::Alloc() {
  94. if (num_used_registers < NUM_REGS) {
  95. for (size_t reg = 0; reg < NUM_REGS; ++reg) {
  96. if (register_use[reg]) {
  97. continue;
  98. }
  99. register_use[reg] = true;
  100. Id ret{};
  101. ret.index.Assign(static_cast<u32>(reg));
  102. ret.is_long.Assign(0);
  103. ret.is_spill.Assign(0);
  104. ret.is_condition_code.Assign(0);
  105. return ret;
  106. }
  107. }
  108. throw NotImplementedException("Register spilling");
  109. }
  110. void RegAlloc::Free(Id id) {
  111. if (id.is_spill != 0) {
  112. throw NotImplementedException("Free spill");
  113. }
  114. register_use[id.index] = false;
  115. }
  116. /*static*/ bool RegAlloc::IsAliased(const IR::Inst& inst) {
  117. switch (inst.GetOpcode()) {
  118. case IR::Opcode::Identity:
  119. case IR::Opcode::BitCastU16F16:
  120. case IR::Opcode::BitCastU32F32:
  121. case IR::Opcode::BitCastU64F64:
  122. case IR::Opcode::BitCastF16U16:
  123. case IR::Opcode::BitCastF32U32:
  124. case IR::Opcode::BitCastF64U64:
  125. return true;
  126. default:
  127. return false;
  128. }
  129. }
  130. /*static*/ IR::Inst& RegAlloc::AliasInst(IR::Inst& inst) {
  131. IR::Inst* it{&inst};
  132. while (IsAliased(*it)) {
  133. const IR::Value arg{it->Arg(0)};
  134. if (arg.IsImmediate()) {
  135. break;
  136. }
  137. it = arg.InstRecursive();
  138. }
  139. return *it;
  140. }
  141. } // namespace Shader::Backend::GLSL