reg_alloc.h 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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. Register,
  19. U32,
  20. S32,
  21. F32,
  22. U64,
  23. F64,
  24. };
  25. struct Id {
  26. union {
  27. u32 raw;
  28. BitField<0, 29, u32> index;
  29. BitField<29, 1, u32> is_long;
  30. BitField<30, 1, u32> is_spill;
  31. BitField<31, 1, u32> is_condition_code;
  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. s32 imm_s32;
  47. f32 imm_f32;
  48. u64 imm_u64;
  49. f64 imm_f64;
  50. };
  51. bool operator==(const Value& rhs) const noexcept {
  52. if (type != rhs.type) {
  53. return false;
  54. }
  55. switch (type) {
  56. case Type::Register:
  57. return id == rhs.id;
  58. case Type::U32:
  59. return imm_u32 == rhs.imm_u32;
  60. case Type::S32:
  61. return imm_s32 == rhs.imm_s32;
  62. case Type::F32:
  63. return Common::BitCast<u32>(imm_f32) == Common::BitCast<u32>(rhs.imm_f32);
  64. case Type::U64:
  65. return imm_u64 == rhs.imm_u64;
  66. case Type::F64:
  67. return Common::BitCast<u64>(imm_f64) == Common::BitCast<u64>(rhs.imm_f64);
  68. }
  69. return false;
  70. }
  71. bool operator!=(const Value& rhs) const noexcept {
  72. return !operator==(rhs);
  73. }
  74. };
  75. struct Register : Value {};
  76. struct ScalarRegister : Value {};
  77. struct ScalarU32 : Value {};
  78. struct ScalarS32 : Value {};
  79. struct ScalarF32 : Value {};
  80. struct ScalarF64 : Value {};
  81. class RegAlloc {
  82. public:
  83. RegAlloc(EmitContext& ctx_) : ctx{ctx_} {}
  84. Register Define(IR::Inst& inst);
  85. Register LongDefine(IR::Inst& inst);
  86. Value Consume(const IR::Value& value);
  87. [[nodiscard]] Register AllocReg();
  88. [[nodiscard]] Register AllocLongReg();
  89. void FreeReg(Register reg);
  90. void InvalidateConditionCodes() {
  91. // This does nothing for now
  92. }
  93. [[nodiscard]] size_t NumUsedRegisters() const noexcept {
  94. return num_used_registers;
  95. }
  96. [[nodiscard]] size_t NumUsedLongRegisters() const noexcept {
  97. return num_used_long_registers;
  98. }
  99. private:
  100. static constexpr size_t NUM_REGS = 4096;
  101. static constexpr size_t NUM_ELEMENTS = 4;
  102. Register Define(IR::Inst& inst, bool is_long);
  103. Value Consume(IR::Inst& inst);
  104. Id Alloc(bool is_long);
  105. void Free(Id id);
  106. EmitContext& ctx;
  107. size_t num_used_registers{};
  108. size_t num_used_long_registers{};
  109. std::bitset<NUM_REGS> register_use{};
  110. std::bitset<NUM_REGS> long_register_use{};
  111. };
  112. template <bool scalar, typename FormatContext>
  113. auto FormatTo(FormatContext& ctx, Id id) {
  114. if (id.is_condition_code != 0) {
  115. throw NotImplementedException("Condition code emission");
  116. }
  117. if (id.is_spill != 0) {
  118. throw NotImplementedException("Spill emission");
  119. }
  120. if constexpr (scalar) {
  121. if (id.is_long != 0) {
  122. return fmt::format_to(ctx.out(), "D{}.x", id.index.Value());
  123. } else {
  124. return fmt::format_to(ctx.out(), "R{}.x", id.index.Value());
  125. }
  126. } else {
  127. if (id.is_long != 0) {
  128. return fmt::format_to(ctx.out(), "D{}", id.index.Value());
  129. } else {
  130. return fmt::format_to(ctx.out(), "R{}", id.index.Value());
  131. }
  132. }
  133. }
  134. } // namespace Shader::Backend::GLASM
  135. template <>
  136. struct fmt::formatter<Shader::Backend::GLASM::Id> {
  137. constexpr auto parse(format_parse_context& ctx) {
  138. return ctx.begin();
  139. }
  140. template <typename FormatContext>
  141. auto format(Shader::Backend::GLASM::Id id, FormatContext& ctx) {
  142. return Shader::Backend::GLASM::FormatTo<true>(ctx, id);
  143. }
  144. };
  145. template <>
  146. struct fmt::formatter<Shader::Backend::GLASM::Register> {
  147. constexpr auto parse(format_parse_context& ctx) {
  148. return ctx.begin();
  149. }
  150. template <typename FormatContext>
  151. auto format(const Shader::Backend::GLASM::Register& value, FormatContext& ctx) {
  152. if (value.type != Shader::Backend::GLASM::Type::Register) {
  153. throw Shader::InvalidArgument("Register value type is not register");
  154. }
  155. return Shader::Backend::GLASM::FormatTo<false>(ctx, value.id);
  156. }
  157. };
  158. template <>
  159. struct fmt::formatter<Shader::Backend::GLASM::ScalarRegister> {
  160. constexpr auto parse(format_parse_context& ctx) {
  161. return ctx.begin();
  162. }
  163. template <typename FormatContext>
  164. auto format(const Shader::Backend::GLASM::ScalarRegister& value, FormatContext& ctx) {
  165. if (value.type != Shader::Backend::GLASM::Type::Register) {
  166. throw Shader::InvalidArgument("Register value type is not register");
  167. }
  168. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  169. }
  170. };
  171. template <>
  172. struct fmt::formatter<Shader::Backend::GLASM::ScalarU32> {
  173. constexpr auto parse(format_parse_context& ctx) {
  174. return ctx.begin();
  175. }
  176. template <typename FormatContext>
  177. auto format(const Shader::Backend::GLASM::ScalarU32& value, FormatContext& ctx) {
  178. switch (value.type) {
  179. case Shader::Backend::GLASM::Type::Register:
  180. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  181. case Shader::Backend::GLASM::Type::U32:
  182. return fmt::format_to(ctx.out(), "{}", value.imm_u32);
  183. case Shader::Backend::GLASM::Type::S32:
  184. return fmt::format_to(ctx.out(), "{}", static_cast<u32>(value.imm_s32));
  185. case Shader::Backend::GLASM::Type::F32:
  186. return fmt::format_to(ctx.out(), "{}", Common::BitCast<u32>(value.imm_f32));
  187. case Shader::Backend::GLASM::Type::U64:
  188. case Shader::Backend::GLASM::Type::F64:
  189. break;
  190. }
  191. throw Shader::InvalidArgument("Invalid value type {}", value.type);
  192. }
  193. };
  194. template <>
  195. struct fmt::formatter<Shader::Backend::GLASM::ScalarS32> {
  196. constexpr auto parse(format_parse_context& ctx) {
  197. return ctx.begin();
  198. }
  199. template <typename FormatContext>
  200. auto format(const Shader::Backend::GLASM::ScalarS32& value, FormatContext& ctx) {
  201. switch (value.type) {
  202. case Shader::Backend::GLASM::Type::Register:
  203. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  204. case Shader::Backend::GLASM::Type::U32:
  205. return fmt::format_to(ctx.out(), "{}", static_cast<s32>(value.imm_u32));
  206. case Shader::Backend::GLASM::Type::S32:
  207. return fmt::format_to(ctx.out(), "{}", value.imm_s32);
  208. case Shader::Backend::GLASM::Type::F32:
  209. return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_f32));
  210. case Shader::Backend::GLASM::Type::U64:
  211. case Shader::Backend::GLASM::Type::F64:
  212. break;
  213. }
  214. throw Shader::InvalidArgument("Invalid value type {}", value.type);
  215. }
  216. };
  217. template <>
  218. struct fmt::formatter<Shader::Backend::GLASM::ScalarF32> {
  219. constexpr auto parse(format_parse_context& ctx) {
  220. return ctx.begin();
  221. }
  222. template <typename FormatContext>
  223. auto format(const Shader::Backend::GLASM::ScalarF32& value, FormatContext& ctx) {
  224. switch (value.type) {
  225. case Shader::Backend::GLASM::Type::Register:
  226. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  227. case Shader::Backend::GLASM::Type::U32:
  228. return fmt::format_to(ctx.out(), "{}", Common::BitCast<u32>(value.imm_u32));
  229. case Shader::Backend::GLASM::Type::S32:
  230. return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_s32));
  231. case Shader::Backend::GLASM::Type::F32:
  232. return fmt::format_to(ctx.out(), "{}", value.imm_f32);
  233. case Shader::Backend::GLASM::Type::U64:
  234. case Shader::Backend::GLASM::Type::F64:
  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::Register:
  249. return Shader::Backend::GLASM::FormatTo<true>(ctx, value.id);
  250. case Shader::Backend::GLASM::Type::U32:
  251. case Shader::Backend::GLASM::Type::S32:
  252. case Shader::Backend::GLASM::Type::F32:
  253. break;
  254. case Shader::Backend::GLASM::Type::U64:
  255. return fmt::format_to(ctx.out(), "{}", Common::BitCast<f64>(value.imm_u64));
  256. case Shader::Backend::GLASM::Type::F64:
  257. return fmt::format_to(ctx.out(), "{}", value.imm_f64);
  258. }
  259. throw Shader::InvalidArgument("Invalid value type {}", value.type);
  260. }
  261. };