reg_alloc.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <bitset>
  6. #include <fmt/format.h>
  7. #include "common/bit_cast.h"
  8. #include "common/bit_field.h"
  9. #include "common/common_types.h"
  10. #include "shader_recompiler/exception.h"
  11. namespace Shader::IR {
  12. class Inst;
  13. class Value;
  14. } // namespace Shader::IR
  15. namespace Shader::Backend::GLASM {
  16. class EmitContext;
  17. enum class Type : u32 {
  18. Void,
  19. Register,
  20. U32,
  21. U64,
  22. };
  23. struct Id {
  24. union {
  25. u32 raw;
  26. BitField<0, 1, u32> is_valid;
  27. BitField<1, 1, u32> is_long;
  28. BitField<2, 1, u32> is_spill;
  29. BitField<3, 1, u32> is_condition_code;
  30. BitField<4, 1, u32> is_null;
  31. BitField<5, 27, u32> index;
  32. };
  33. bool operator==(Id rhs) const noexcept {
  34. return raw == rhs.raw;
  35. }
  36. bool operator!=(Id rhs) const noexcept {
  37. return !operator==(rhs);
  38. }
  39. };
  40. static_assert(sizeof(Id) == sizeof(u32));
  41. struct Value {
  42. Type type;
  43. union {
  44. Id id;
  45. u32 imm_u32;
  46. u64 imm_u64;
  47. };
  48. bool operator==(const Value& rhs) const noexcept {
  49. if (type != rhs.type) {
  50. return false;
  51. }
  52. switch (type) {
  53. case Type::Void:
  54. return true;
  55. case Type::Register:
  56. return id == rhs.id;
  57. case Type::U32:
  58. return imm_u32 == rhs.imm_u32;
  59. case Type::U64:
  60. return imm_u64 == rhs.imm_u64;
  61. }
  62. return false;
  63. }
  64. bool operator!=(const Value& rhs) const noexcept {
  65. return !operator==(rhs);
  66. }
  67. };
  68. struct Register : Value {};
  69. struct ScalarRegister : Value {};
  70. struct ScalarU32 : Value {};
  71. struct ScalarS32 : Value {};
  72. struct ScalarF32 : Value {};
  73. struct ScalarF64 : Value {};
  74. class RegAlloc {
  75. public:
  76. RegAlloc() = default;
  77. Register Define(IR::Inst& inst);
  78. Register LongDefine(IR::Inst& inst);
  79. [[nodiscard]] Value Peek(const IR::Value& value);
  80. Value Consume(const IR::Value& value);
  81. void Unref(IR::Inst& inst);
  82. [[nodiscard]] Register AllocReg();
  83. [[nodiscard]] Register AllocLongReg();
  84. void FreeReg(Register reg);
  85. void InvalidateConditionCodes() {
  86. // This does nothing for now
  87. }
  88. [[nodiscard]] size_t NumUsedRegisters() const noexcept {
  89. return num_used_registers;
  90. }
  91. [[nodiscard]] size_t NumUsedLongRegisters() const noexcept {
  92. return num_used_long_registers;
  93. }
  94. [[nodiscard]] bool IsEmpty() const noexcept {
  95. return register_use.none() && long_register_use.none();
  96. }
  97. /// Returns true if the instruction is expected to be aliased to another
  98. static bool IsAliased(const IR::Inst& inst);
  99. /// Returns the underlying value out of an alias sequence
  100. static IR::Inst& AliasInst(IR::Inst& inst);
  101. private:
  102. static constexpr size_t NUM_REGS = 4096;
  103. static constexpr size_t NUM_ELEMENTS = 4;
  104. Value MakeImm(const IR::Value& value);
  105. Register Define(IR::Inst& inst, bool is_long);
  106. Value PeekInst(IR::Inst& inst);
  107. Value ConsumeInst(IR::Inst& inst);
  108. Id Alloc(bool is_long);
  109. void Free(Id id);
  110. size_t num_used_registers{};
  111. size_t num_used_long_registers{};
  112. std::bitset<NUM_REGS> register_use{};
  113. std::bitset<NUM_REGS> long_register_use{};
  114. };
  115. template <bool scalar, typename FormatContext>
  116. auto FormatTo(FormatContext& ctx, Id id) {
  117. if (id.is_condition_code != 0) {
  118. throw NotImplementedException("Condition code emission");
  119. }
  120. if (id.is_spill != 0) {
  121. throw NotImplementedException("Spill emission");
  122. }
  123. if constexpr (scalar) {
  124. if (id.is_null != 0) {
  125. return fmt::format_to(ctx.out(), "{}", id.is_long != 0 ? "DC.x" : "RC.x");
  126. }
  127. if (id.is_long != 0) {
  128. return fmt::format_to(ctx.out(), "D{}.x", id.index.Value());
  129. } else {
  130. return fmt::format_to(ctx.out(), "R{}.x", id.index.Value());
  131. }
  132. } else {
  133. if (id.is_null != 0) {
  134. return fmt::format_to(ctx.out(), "{}", id.is_long != 0 ? "DC" : "RC");
  135. }
  136. if (id.is_long != 0) {
  137. return fmt::format_to(ctx.out(), "D{}", id.index.Value());
  138. } else {
  139. return fmt::format_to(ctx.out(), "R{}", id.index.Value());
  140. }
  141. }
  142. }
  143. } // namespace Shader::Backend::GLASM
  144. template <>
  145. struct fmt::formatter<Shader::Backend::GLASM::Id> {
  146. constexpr auto parse(format_parse_context& ctx) {
  147. return ctx.begin();
  148. }
  149. template <typename FormatContext>
  150. auto format(Shader::Backend::GLASM::Id id, FormatContext& ctx) {
  151. return Shader::Backend::GLASM::FormatTo<true>(ctx, id);
  152. }
  153. };
  154. template <>
  155. struct fmt::formatter<Shader::Backend::GLASM::Register> {
  156. constexpr auto parse(format_parse_context& ctx) {
  157. return ctx.begin();
  158. }
  159. template <typename FormatContext>
  160. auto format(const Shader::Backend::GLASM::Register& value, FormatContext& ctx) {
  161. if (value.type != Shader::Backend::GLASM::Type::Register) {
  162. throw Shader::InvalidArgument("Register value type is not register");
  163. }
  164. return Shader::Backend::GLASM::FormatTo<false>(ctx, value.id);
  165. }
  166. };
  167. template <>
  168. struct fmt::formatter<Shader::Backend::GLASM::ScalarRegister> {
  169. constexpr auto parse(format_parse_context& ctx) {
  170. return ctx.begin();
  171. }
  172. template <typename FormatContext>
  173. auto format(const Shader::Backend::GLASM::ScalarRegister& value, FormatContext& ctx) {
  174. if (value.type != Shader::Backend::GLASM::Type::Register) {
  175. throw Shader::InvalidArgument("Register value type is not register");
  176. }
  177. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  178. }
  179. };
  180. template <>
  181. struct fmt::formatter<Shader::Backend::GLASM::ScalarU32> {
  182. constexpr auto parse(format_parse_context& ctx) {
  183. return ctx.begin();
  184. }
  185. template <typename FormatContext>
  186. auto format(const Shader::Backend::GLASM::ScalarU32& value, FormatContext& ctx) {
  187. switch (value.type) {
  188. case Shader::Backend::GLASM::Type::Void:
  189. break;
  190. case Shader::Backend::GLASM::Type::Register:
  191. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  192. case Shader::Backend::GLASM::Type::U32:
  193. return fmt::format_to(ctx.out(), "{}", value.imm_u32);
  194. case Shader::Backend::GLASM::Type::U64:
  195. break;
  196. }
  197. throw Shader::InvalidArgument("Invalid value type {}", value.type);
  198. }
  199. };
  200. template <>
  201. struct fmt::formatter<Shader::Backend::GLASM::ScalarS32> {
  202. constexpr auto parse(format_parse_context& ctx) {
  203. return ctx.begin();
  204. }
  205. template <typename FormatContext>
  206. auto format(const Shader::Backend::GLASM::ScalarS32& value, FormatContext& ctx) {
  207. switch (value.type) {
  208. case Shader::Backend::GLASM::Type::Void:
  209. break;
  210. case Shader::Backend::GLASM::Type::Register:
  211. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  212. case Shader::Backend::GLASM::Type::U32:
  213. return fmt::format_to(ctx.out(), "{}", static_cast<s32>(value.imm_u32));
  214. case Shader::Backend::GLASM::Type::U64:
  215. break;
  216. }
  217. throw Shader::InvalidArgument("Invalid value type {}", value.type);
  218. }
  219. };
  220. template <>
  221. struct fmt::formatter<Shader::Backend::GLASM::ScalarF32> {
  222. constexpr auto parse(format_parse_context& ctx) {
  223. return ctx.begin();
  224. }
  225. template <typename FormatContext>
  226. auto format(const Shader::Backend::GLASM::ScalarF32& value, FormatContext& ctx) {
  227. switch (value.type) {
  228. case Shader::Backend::GLASM::Type::Void:
  229. break;
  230. case Shader::Backend::GLASM::Type::Register:
  231. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  232. case Shader::Backend::GLASM::Type::U32:
  233. return fmt::format_to(ctx.out(), "{}", Common::BitCast<f32>(value.imm_u32));
  234. case Shader::Backend::GLASM::Type::U64:
  235. break;
  236. }
  237. throw Shader::InvalidArgument("Invalid value type {}", value.type);
  238. }
  239. };
  240. template <>
  241. struct fmt::formatter<Shader::Backend::GLASM::ScalarF64> {
  242. constexpr auto parse(format_parse_context& ctx) {
  243. return ctx.begin();
  244. }
  245. template <typename FormatContext>
  246. auto format(const Shader::Backend::GLASM::ScalarF64& value, FormatContext& ctx) {
  247. switch (value.type) {
  248. case Shader::Backend::GLASM::Type::Void:
  249. break;
  250. case Shader::Backend::GLASM::Type::Register:
  251. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  252. case Shader::Backend::GLASM::Type::U32:
  253. break;
  254. case Shader::Backend::GLASM::Type::U64:
  255. return fmt::format_to(ctx.out(), "{}", Common::BitCast<f64>(value.imm_u64));
  256. }
  257. throw Shader::InvalidArgument("Invalid value type {}", value.type);
  258. }
  259. };