summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/glsl/var_alloc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/backend/glsl/var_alloc.cpp')
-rw-r--r--src/shader_recompiler/backend/glsl/var_alloc.cpp308
1 files changed, 308 insertions, 0 deletions
diff --git a/src/shader_recompiler/backend/glsl/var_alloc.cpp b/src/shader_recompiler/backend/glsl/var_alloc.cpp
new file mode 100644
index 000000000..194f926ca
--- /dev/null
+++ b/src/shader_recompiler/backend/glsl/var_alloc.cpp
@@ -0,0 +1,308 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6#include <string_view>
7
8#include <fmt/format.h>
9
10#include "shader_recompiler/backend/glsl/var_alloc.h"
11#include "shader_recompiler/exception.h"
12#include "shader_recompiler/frontend/ir/value.h"
13
14namespace Shader::Backend::GLSL {
15namespace {
16std::string TypePrefix(GlslVarType type) {
17 switch (type) {
18 case GlslVarType::U1:
19 return "b_";
20 case GlslVarType::F16x2:
21 return "f16x2_";
22 case GlslVarType::U32:
23 return "u_";
24 case GlslVarType::F32:
25 return "f_";
26 case GlslVarType::U64:
27 return "u64_";
28 case GlslVarType::F64:
29 return "d_";
30 case GlslVarType::U32x2:
31 return "u2_";
32 case GlslVarType::F32x2:
33 return "f2_";
34 case GlslVarType::U32x3:
35 return "u3_";
36 case GlslVarType::F32x3:
37 return "f3_";
38 case GlslVarType::U32x4:
39 return "u4_";
40 case GlslVarType::F32x4:
41 return "f4_";
42 case GlslVarType::PrecF32:
43 return "pf_";
44 case GlslVarType::PrecF64:
45 return "pd_";
46 case GlslVarType::Void:
47 return "";
48 default:
49 throw NotImplementedException("Type {}", type);
50 }
51}
52
53std::string FormatFloat(std::string_view value, IR::Type type) {
54 // TODO: Confirm FP64 nan/inf
55 if (type == IR::Type::F32) {
56 if (value == "nan") {
57 return "utof(0x7fc00000)";
58 }
59 if (value == "inf") {
60 return "utof(0x7f800000)";
61 }
62 if (value == "-inf") {
63 return "utof(0xff800000)";
64 }
65 }
66 if (value.find_first_of('e') != std::string_view::npos) {
67 // scientific notation
68 const auto cast{type == IR::Type::F32 ? "float" : "double"};
69 return fmt::format("{}({})", cast, value);
70 }
71 const bool needs_dot{value.find_first_of('.') == std::string_view::npos};
72 const bool needs_suffix{!value.ends_with('f')};
73 const auto suffix{type == IR::Type::F32 ? "f" : "lf"};
74 return fmt::format("{}{}{}", value, needs_dot ? "." : "", needs_suffix ? suffix : "");
75}
76
77std::string MakeImm(const IR::Value& value) {
78 switch (value.Type()) {
79 case IR::Type::U1:
80 return fmt::format("{}", value.U1() ? "true" : "false");
81 case IR::Type::U32:
82 return fmt::format("{}u", value.U32());
83 case IR::Type::F32:
84 return FormatFloat(fmt::format("{}", value.F32()), IR::Type::F32);
85 case IR::Type::U64:
86 return fmt::format("{}ul", value.U64());
87 case IR::Type::F64:
88 return FormatFloat(fmt::format("{}", value.F64()), IR::Type::F64);
89 case IR::Type::Void:
90 return "";
91 default:
92 throw NotImplementedException("Immediate type {}", value.Type());
93 }
94}
95} // Anonymous namespace
96
97std::string VarAlloc::Representation(u32 index, GlslVarType type) const {
98 const auto prefix{TypePrefix(type)};
99 return fmt::format("{}{}", prefix, index);
100}
101
102std::string VarAlloc::Representation(Id id) const {
103 return Representation(id.index, id.type);
104}
105
106std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) {
107 if (inst.HasUses()) {
108 inst.SetDefinition<Id>(Alloc(type));
109 return Representation(inst.Definition<Id>());
110 } else {
111 Id id{};
112 id.type.Assign(type);
113 GetUseTracker(type).uses_temp = true;
114 inst.SetDefinition<Id>(id);
115 return 't' + Representation(inst.Definition<Id>());
116 }
117}
118
119std::string VarAlloc::Define(IR::Inst& inst, IR::Type type) {
120 return Define(inst, RegType(type));
121}
122
123std::string VarAlloc::PhiDefine(IR::Inst& inst, IR::Type type) {
124 return AddDefine(inst, RegType(type));
125}
126
127std::string VarAlloc::AddDefine(IR::Inst& inst, GlslVarType type) {
128 if (inst.HasUses()) {
129 inst.SetDefinition<Id>(Alloc(type));
130 return Representation(inst.Definition<Id>());
131 } else {
132 return "";
133 }
134 return Representation(inst.Definition<Id>());
135}
136
137std::string VarAlloc::Consume(const IR::Value& value) {
138 return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive());
139}
140
141std::string VarAlloc::ConsumeInst(IR::Inst& inst) {
142 inst.DestructiveRemoveUsage();
143 if (!inst.HasUses()) {
144 Free(inst.Definition<Id>());
145 }
146 return Representation(inst.Definition<Id>());
147}
148
149std::string VarAlloc::GetGlslType(IR::Type type) const {
150 return GetGlslType(RegType(type));
151}
152
153Id VarAlloc::Alloc(GlslVarType type) {
154 auto& use_tracker{GetUseTracker(type)};
155 const auto num_vars{use_tracker.var_use.size()};
156 for (size_t var = 0; var < num_vars; ++var) {
157 if (use_tracker.var_use[var]) {
158 continue;
159 }
160 use_tracker.num_used = std::max(use_tracker.num_used, var + 1);
161 use_tracker.var_use[var] = true;
162 Id ret{};
163 ret.is_valid.Assign(1);
164 ret.type.Assign(type);
165 ret.index.Assign(static_cast<u32>(var));
166 return ret;
167 }
168 // Allocate a new variable
169 use_tracker.var_use.push_back(true);
170 Id ret{};
171 ret.is_valid.Assign(1);
172 ret.type.Assign(type);
173 ret.index.Assign(static_cast<u32>(use_tracker.num_used));
174 ++use_tracker.num_used;
175 return ret;
176}
177
178void VarAlloc::Free(Id id) {
179 if (id.is_valid == 0) {
180 throw LogicError("Freeing invalid variable");
181 }
182 auto& use_tracker{GetUseTracker(id.type)};
183 use_tracker.var_use[id.index] = false;
184}
185
186GlslVarType VarAlloc::RegType(IR::Type type) const {
187 switch (type) {
188 case IR::Type::U1:
189 return GlslVarType::U1;
190 case IR::Type::U32:
191 return GlslVarType::U32;
192 case IR::Type::F32:
193 return GlslVarType::F32;
194 case IR::Type::U64:
195 return GlslVarType::U64;
196 case IR::Type::F64:
197 return GlslVarType::F64;
198 default:
199 throw NotImplementedException("IR type {}", type);
200 }
201}
202
203std::string VarAlloc::GetGlslType(GlslVarType type) const {
204 switch (type) {
205 case GlslVarType::U1:
206 return "bool";
207 case GlslVarType::F16x2:
208 return "f16vec2";
209 case GlslVarType::U32:
210 return "uint";
211 case GlslVarType::F32:
212 case GlslVarType::PrecF32:
213 return "float";
214 case GlslVarType::U64:
215 return "uint64_t";
216 case GlslVarType::F64:
217 case GlslVarType::PrecF64:
218 return "double";
219 case GlslVarType::U32x2:
220 return "uvec2";
221 case GlslVarType::F32x2:
222 return "vec2";
223 case GlslVarType::U32x3:
224 return "uvec3";
225 case GlslVarType::F32x3:
226 return "vec3";
227 case GlslVarType::U32x4:
228 return "uvec4";
229 case GlslVarType::F32x4:
230 return "vec4";
231 case GlslVarType::Void:
232 return "";
233 default:
234 throw NotImplementedException("Type {}", type);
235 }
236}
237
238VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) {
239 switch (type) {
240 case GlslVarType::U1:
241 return var_bool;
242 case GlslVarType::F16x2:
243 return var_f16x2;
244 case GlslVarType::U32:
245 return var_u32;
246 case GlslVarType::F32:
247 return var_f32;
248 case GlslVarType::U64:
249 return var_u64;
250 case GlslVarType::F64:
251 return var_f64;
252 case GlslVarType::U32x2:
253 return var_u32x2;
254 case GlslVarType::F32x2:
255 return var_f32x2;
256 case GlslVarType::U32x3:
257 return var_u32x3;
258 case GlslVarType::F32x3:
259 return var_f32x3;
260 case GlslVarType::U32x4:
261 return var_u32x4;
262 case GlslVarType::F32x4:
263 return var_f32x4;
264 case GlslVarType::PrecF32:
265 return var_precf32;
266 case GlslVarType::PrecF64:
267 return var_precf64;
268 default:
269 throw NotImplementedException("Type {}", type);
270 }
271}
272
273const VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) const {
274 switch (type) {
275 case GlslVarType::U1:
276 return var_bool;
277 case GlslVarType::F16x2:
278 return var_f16x2;
279 case GlslVarType::U32:
280 return var_u32;
281 case GlslVarType::F32:
282 return var_f32;
283 case GlslVarType::U64:
284 return var_u64;
285 case GlslVarType::F64:
286 return var_f64;
287 case GlslVarType::U32x2:
288 return var_u32x2;
289 case GlslVarType::F32x2:
290 return var_f32x2;
291 case GlslVarType::U32x3:
292 return var_u32x3;
293 case GlslVarType::F32x3:
294 return var_f32x3;
295 case GlslVarType::U32x4:
296 return var_u32x4;
297 case GlslVarType::F32x4:
298 return var_f32x4;
299 case GlslVarType::PrecF32:
300 return var_precf32;
301 case GlslVarType::PrecF64:
302 return var_precf64;
303 default:
304 throw NotImplementedException("Type {}", type);
305 }
306}
307
308} // namespace Shader::Backend::GLSL