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