summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/glasm/reg_alloc.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/backend/glasm/reg_alloc.h')
-rw-r--r--src/shader_recompiler/backend/glasm/reg_alloc.h184
1 files changed, 179 insertions, 5 deletions
diff --git a/src/shader_recompiler/backend/glasm/reg_alloc.h b/src/shader_recompiler/backend/glasm/reg_alloc.h
index f73aa3348..ef0b6697f 100644
--- a/src/shader_recompiler/backend/glasm/reg_alloc.h
+++ b/src/shader_recompiler/backend/glasm/reg_alloc.h
@@ -6,8 +6,12 @@
6 6
7#include <bitset> 7#include <bitset>
8 8
9#include <fmt/format.h>
10
11#include "common/bit_cast.h"
9#include "common/bit_field.h" 12#include "common/bit_field.h"
10#include "common/common_types.h" 13#include "common/common_types.h"
14#include "shader_recompiler/exception.h"
11 15
12namespace Shader::IR { 16namespace Shader::IR {
13class Inst; 17class Inst;
@@ -18,6 +22,13 @@ namespace Shader::Backend::GLASM {
18 22
19class EmitContext; 23class EmitContext;
20 24
25enum class Type : u32 {
26 Register,
27 U32,
28 S32,
29 F32,
30};
31
21struct Id { 32struct Id {
22 union { 33 union {
23 u32 raw; 34 u32 raw;
@@ -25,15 +36,62 @@ struct Id {
25 BitField<30, 1, u32> is_spill; 36 BitField<30, 1, u32> is_spill;
26 BitField<31, 1, u32> is_condition_code; 37 BitField<31, 1, u32> is_condition_code;
27 }; 38 };
39
40 bool operator==(Id rhs) const noexcept {
41 return raw == rhs.raw;
42 }
43 bool operator!=(Id rhs) const noexcept {
44 return !operator==(rhs);
45 }
28}; 46};
47static_assert(sizeof(Id) == sizeof(u32));
48
49struct Value {
50 Type type;
51 union {
52 Id id;
53 u32 imm_u32;
54 s32 imm_s32;
55 f32 imm_f32;
56 };
57
58 bool operator==(const Value& rhs) const noexcept {
59 if (type != rhs.type) {
60 return false;
61 }
62 switch (type) {
63 case Type::Register:
64 return id == rhs.id;
65 case Type::U32:
66 return imm_u32 == rhs.imm_u32;
67 case Type::S32:
68 return imm_s32 == rhs.imm_s32;
69 case Type::F32:
70 return Common::BitCast<u32>(imm_f32) == Common::BitCast<u32>(rhs.imm_f32);
71 }
72 return false;
73 }
74 bool operator!=(const Value& rhs) const noexcept {
75 return !operator==(rhs);
76 }
77};
78struct Register : Value {};
79struct ScalarRegister : Value {};
80struct ScalarU32 : Value {};
81struct ScalarS32 : Value {};
82struct ScalarF32 : Value {};
29 83
30class RegAlloc { 84class RegAlloc {
31public: 85public:
32 RegAlloc(EmitContext& ctx_) : ctx{ctx_} {} 86 RegAlloc(EmitContext& ctx_) : ctx{ctx_} {}
33 87
34 std::string Define(IR::Inst& inst); 88 Register Define(IR::Inst& inst);
89
90 Value Consume(const IR::Value& value);
91
92 Register AllocReg();
35 93
36 std::string Consume(const IR::Value& value); 94 void FreeReg(Register reg);
37 95
38 [[nodiscard]] size_t NumUsedRegisters() const noexcept { 96 [[nodiscard]] size_t NumUsedRegisters() const noexcept {
39 return num_used_registers; 97 return num_used_registers;
@@ -43,16 +101,132 @@ private:
43 static constexpr size_t NUM_REGS = 4096; 101 static constexpr size_t NUM_REGS = 4096;
44 static constexpr size_t NUM_ELEMENTS = 4; 102 static constexpr size_t NUM_ELEMENTS = 4;
45 103
46 EmitContext& ctx; 104 Value Consume(IR::Inst& inst);
47
48 std::string Consume(IR::Inst& inst);
49 105
50 Id Alloc(); 106 Id Alloc();
51 107
52 void Free(Id id); 108 void Free(Id id);
53 109
110 EmitContext& ctx;
54 size_t num_used_registers{}; 111 size_t num_used_registers{};
55 std::bitset<NUM_REGS> register_use{}; 112 std::bitset<NUM_REGS> register_use{};
56}; 113};
57 114
115template <bool scalar, typename FormatContext>
116auto 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 return fmt::format_to(ctx.out(), "R{}.x", id.index.Value());
125 } else {
126 return fmt::format_to(ctx.out(), "R{}", id.index.Value());
127 }
128}
129
58} // namespace Shader::Backend::GLASM 130} // namespace Shader::Backend::GLASM
131
132template <>
133struct fmt::formatter<Shader::Backend::GLASM::Id> {
134 constexpr auto parse(format_parse_context& ctx) {
135 return ctx.begin();
136 }
137 template <typename FormatContext>
138 auto format(Shader::Backend::GLASM::Id id, FormatContext& ctx) {
139 return FormatTo<true>(ctx, id);
140 }
141};
142
143template <>
144struct fmt::formatter<Shader::Backend::GLASM::Register> {
145 constexpr auto parse(format_parse_context& ctx) {
146 return ctx.begin();
147 }
148 template <typename FormatContext>
149 auto format(const Shader::Backend::GLASM::Register& value, FormatContext& ctx) {
150 if (value.type != Shader::Backend::GLASM::Type::Register) {
151 throw Shader::InvalidArgument("Register value type is not register");
152 }
153 return FormatTo<false>(ctx, value.id);
154 }
155};
156
157template <>
158struct fmt::formatter<Shader::Backend::GLASM::ScalarRegister> {
159 constexpr auto parse(format_parse_context& ctx) {
160 return ctx.begin();
161 }
162 template <typename FormatContext>
163 auto format(const Shader::Backend::GLASM::ScalarRegister& value, FormatContext& ctx) {
164 if (value.type != Shader::Backend::GLASM::Type::Register) {
165 throw Shader::InvalidArgument("Register value type is not register");
166 }
167 return FormatTo<true>(ctx, value.id);
168 }
169};
170
171template <>
172struct 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 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 }
188 throw Shader::InvalidArgument("Invalid value type {}", value.type);
189 }
190};
191
192template <>
193struct fmt::formatter<Shader::Backend::GLASM::ScalarS32> {
194 constexpr auto parse(format_parse_context& ctx) {
195 return ctx.begin();
196 }
197 template <typename FormatContext>
198 auto format(const Shader::Backend::GLASM::ScalarS32& value, FormatContext& ctx) {
199 switch (value.type) {
200 case Shader::Backend::GLASM::Type::Register:
201 return FormatTo<true>(ctx, value.id);
202 case Shader::Backend::GLASM::Type::U32:
203 return fmt::format_to(ctx.out(), "{}", static_cast<s32>(value.imm_u32));
204 case Shader::Backend::GLASM::Type::S32:
205 return fmt::format_to(ctx.out(), "{}", value.imm_s32);
206 case Shader::Backend::GLASM::Type::F32:
207 return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_f32));
208 }
209 throw Shader::InvalidArgument("Invalid value type {}", value.type);
210 }
211};
212
213template <>
214struct fmt::formatter<Shader::Backend::GLASM::ScalarF32> {
215 constexpr auto parse(format_parse_context& ctx) {
216 return ctx.begin();
217 }
218 template <typename FormatContext>
219 auto format(const Shader::Backend::GLASM::ScalarF32& value, FormatContext& ctx) {
220 switch (value.type) {
221 case Shader::Backend::GLASM::Type::Register:
222 return FormatTo<true>(ctx, value.id);
223 case Shader::Backend::GLASM::Type::U32:
224 return fmt::format_to(ctx.out(), "{}", Common::BitCast<u32>(value.imm_u32));
225 case Shader::Backend::GLASM::Type::S32:
226 return fmt::format_to(ctx.out(), "{}", Common::BitCast<s32>(value.imm_s32));
227 case Shader::Backend::GLASM::Type::F32:
228 return fmt::format_to(ctx.out(), "{}", value.imm_f32);
229 }
230 throw Shader::InvalidArgument("Invalid value type {}", value.type);
231 }
232};