reg_alloc.h 10 KB

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