summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h404
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp55
2 files changed, 249 insertions, 210 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index e6c2fd367..5a006aee5 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -4,10 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <bitset>
7#include <cstring> 8#include <cstring>
8#include <map> 9#include <map>
9#include <string> 10#include <string>
11#include <vector>
12
13#include <boost/optional.hpp>
14
10#include "common/bit_field.h" 15#include "common/bit_field.h"
16#include "common/common_types.h"
11 17
12namespace Tegra { 18namespace Tegra {
13namespace Shader { 19namespace Shader {
@@ -89,188 +95,12 @@ union Uniform {
89 BitField<34, 5, u64> index; 95 BitField<34, 5, u64> index;
90}; 96};
91 97
92union OpCode {
93 enum class Id : u64 {
94 TEXS = 0x6C,
95 IPA = 0xE0,
96 FMUL32_IMM = 0x1E,
97 FFMA_IMM = 0x65,
98 FFMA_CR = 0x93,
99 FFMA_RC = 0xA3,
100 FFMA_RR = 0xB3,
101
102 FADD_C = 0x98B,
103 FMUL_C = 0x98D,
104 MUFU = 0xA10,
105 FADD_R = 0xB8B,
106 FMUL_R = 0xB8D,
107 LD_A = 0x1DFB,
108 ST_A = 0x1DFE,
109
110 FSETP_R = 0x5BB,
111 FSETP_C = 0x4BB,
112 FSETP_IMM = 0x36B,
113 FSETP_NEG_IMM = 0x37B,
114 EXIT = 0xE30,
115 KIL = 0xE33,
116
117 FMUL_IMM = 0x70D,
118 FMUL_IMM_x = 0x72D,
119 FADD_IMM = 0x70B,
120 FADD_IMM_x = 0x72B,
121 };
122
123 enum class Type {
124 Trivial,
125 Arithmetic,
126 Ffma,
127 Flow,
128 Memory,
129 FloatPredicate,
130 Unknown,
131 };
132
133 struct Info {
134 Type type;
135 std::string name;
136 };
137
138 OpCode() = default;
139
140 constexpr OpCode(Id value) : value(static_cast<u64>(value)) {}
141
142 constexpr OpCode(u64 value) : value{value} {}
143
144 constexpr Id EffectiveOpCode() const {
145 switch (op1) {
146 case Id::TEXS:
147 return op1;
148 }
149
150 switch (op2) {
151 case Id::IPA:
152 case Id::FMUL32_IMM:
153 return op2;
154 }
155
156 switch (op3) {
157 case Id::FFMA_IMM:
158 case Id::FFMA_CR:
159 case Id::FFMA_RC:
160 case Id::FFMA_RR:
161 return op3;
162 }
163
164 switch (op4) {
165 case Id::EXIT:
166 case Id::FSETP_R:
167 case Id::FSETP_C:
168 case Id::KIL:
169 return op4;
170 case Id::FSETP_IMM:
171 case Id::FSETP_NEG_IMM:
172 return Id::FSETP_IMM;
173 }
174
175 switch (op5) {
176 case Id::MUFU:
177 case Id::LD_A:
178 case Id::ST_A:
179 case Id::FADD_R:
180 case Id::FADD_C:
181 case Id::FMUL_R:
182 case Id::FMUL_C:
183 return op5;
184
185 case Id::FMUL_IMM:
186 case Id::FMUL_IMM_x:
187 return Id::FMUL_IMM;
188
189 case Id::FADD_IMM:
190 case Id::FADD_IMM_x:
191 return Id::FADD_IMM;
192 }
193
194 return static_cast<Id>(value);
195 }
196
197 static const Info& GetInfo(const OpCode& opcode) {
198 static const std::map<Id, Info> info_table{BuildInfoTable()};
199 const auto& search{info_table.find(opcode.EffectiveOpCode())};
200 if (search != info_table.end()) {
201 return search->second;
202 }
203
204 static const Info unknown{Type::Unknown, "UNK"};
205 return unknown;
206 }
207
208 constexpr operator Id() const {
209 return static_cast<Id>(value);
210 }
211
212 constexpr OpCode operator<<(size_t bits) const {
213 return value << bits;
214 }
215
216 constexpr OpCode operator>>(size_t bits) const {
217 return value >> bits;
218 }
219
220 template <typename T>
221 constexpr u64 operator-(const T& oth) const {
222 return value - oth;
223 }
224
225 constexpr u64 operator&(const OpCode& oth) const {
226 return value & oth.value;
227 }
228
229 constexpr u64 operator~() const {
230 return ~value;
231 }
232
233 static std::map<Id, Info> BuildInfoTable() {
234 std::map<Id, Info> info_table;
235 info_table[Id::TEXS] = {Type::Memory, "texs"};
236 info_table[Id::LD_A] = {Type::Memory, "ld_a"};
237 info_table[Id::ST_A] = {Type::Memory, "st_a"};
238 info_table[Id::MUFU] = {Type::Arithmetic, "mufu"};
239 info_table[Id::FFMA_IMM] = {Type::Ffma, "ffma_imm"};
240 info_table[Id::FFMA_CR] = {Type::Ffma, "ffma_cr"};
241 info_table[Id::FFMA_RC] = {Type::Ffma, "ffma_rc"};
242 info_table[Id::FFMA_RR] = {Type::Ffma, "ffma_rr"};
243 info_table[Id::FADD_R] = {Type::Arithmetic, "fadd_r"};
244 info_table[Id::FADD_C] = {Type::Arithmetic, "fadd_c"};
245 info_table[Id::FADD_IMM] = {Type::Arithmetic, "fadd_imm"};
246 info_table[Id::FMUL_R] = {Type::Arithmetic, "fmul_r"};
247 info_table[Id::FMUL_C] = {Type::Arithmetic, "fmul_c"};
248 info_table[Id::FMUL_IMM] = {Type::Arithmetic, "fmul_imm"};
249 info_table[Id::FMUL32_IMM] = {Type::Arithmetic, "fmul32_imm"};
250 info_table[Id::FSETP_C] = {Type::FloatPredicate, "fsetp_c"};
251 info_table[Id::FSETP_R] = {Type::FloatPredicate, "fsetp_r"};
252 info_table[Id::FSETP_IMM] = {Type::FloatPredicate, "fsetp_imm"};
253 info_table[Id::EXIT] = {Type::Trivial, "exit"};
254 info_table[Id::IPA] = {Type::Trivial, "ipa"};
255 info_table[Id::KIL] = {Type::Flow, "kil"};
256 return info_table;
257 }
258
259 BitField<57, 7, Id> op1;
260 BitField<56, 8, Id> op2;
261 BitField<55, 9, Id> op3;
262 BitField<52, 12, Id> op4;
263 BitField<51, 13, Id> op5;
264 u64 value{};
265};
266static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size");
267
268} // namespace Shader 98} // namespace Shader
269} // namespace Tegra 99} // namespace Tegra
270 100
271namespace std { 101namespace std {
272 102
273// TODO(bunne): The below is forbidden by the C++ standard, but works fine. See #330. 103// TODO(bunnei): The below is forbidden by the C++ standard, but works fine. See #330.
274template <> 104template <>
275struct make_unsigned<Tegra::Shader::Attribute> { 105struct make_unsigned<Tegra::Shader::Attribute> {
276 using type = Tegra::Shader::Attribute; 106 using type = Tegra::Shader::Attribute;
@@ -281,11 +111,6 @@ struct make_unsigned<Tegra::Shader::Register> {
281 using type = Tegra::Shader::Register; 111 using type = Tegra::Shader::Register;
282}; 112};
283 113
284template <>
285struct make_unsigned<Tegra::Shader::OpCode> {
286 using type = Tegra::Shader::OpCode;
287};
288
289} // namespace std 114} // namespace std
290 115
291namespace Tegra { 116namespace Tegra {
@@ -324,11 +149,12 @@ enum class SubOp : u64 {
324 149
325union Instruction { 150union Instruction {
326 Instruction& operator=(const Instruction& instr) { 151 Instruction& operator=(const Instruction& instr) {
327 hex = instr.hex; 152 value = instr.value;
328 return *this; 153 return *this;
329 } 154 }
330 155
331 OpCode opcode; 156 constexpr Instruction(u64 value) : value{value} {}
157
332 BitField<0, 8, Register> gpr0; 158 BitField<0, 8, Register> gpr0;
333 BitField<8, 8, Register> gpr8; 159 BitField<8, 8, Register> gpr8;
334 union { 160 union {
@@ -340,6 +166,7 @@ union Instruction {
340 BitField<20, 7, SubOp> sub_op; 166 BitField<20, 7, SubOp> sub_op;
341 BitField<28, 8, Register> gpr28; 167 BitField<28, 8, Register> gpr28;
342 BitField<39, 8, Register> gpr39; 168 BitField<39, 8, Register> gpr39;
169 BitField<48, 16, u64> opcode;
343 170
344 union { 171 union {
345 BitField<20, 19, u64> imm20_19; 172 BitField<20, 19, u64> imm20_19;
@@ -395,11 +222,218 @@ union Instruction {
395 Uniform uniform; 222 Uniform uniform;
396 Sampler sampler; 223 Sampler sampler;
397 224
398 u64 hex; 225 u64 value;
399}; 226};
400static_assert(sizeof(Instruction) == 0x8, "Incorrect structure size"); 227static_assert(sizeof(Instruction) == 0x8, "Incorrect structure size");
401static_assert(std::is_standard_layout<Instruction>::value, 228static_assert(std::is_standard_layout<Instruction>::value,
402 "Structure does not have standard layout"); 229 "Structure does not have standard layout");
403 230
231class OpCode {
232public:
233 enum class Id {
234 KIL,
235 LD_A,
236 ST_A,
237 TEXQ, // Texture Query
238 TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
239 TLDS, // Texture Load with scalar/non-vec4 source/destinations
240 EXIT,
241 IPA,
242 FFMA_IMM, // Fused Multiply and Add
243 FFMA_CR,
244 FFMA_RC,
245 FFMA_RR,
246 FADD_C,
247 FADD_R,
248 FADD_IMM,
249 FMUL_C,
250 FMUL_R,
251 FMUL_IMM,
252 FMUL32_IMM,
253 MUFU, // Multi-Function Operator
254 RRO, // Range Reduction Operator
255 F2F_C,
256 F2F_R,
257 F2F_IMM,
258 F2I_C,
259 F2I_R,
260 F2I_IMM,
261 I2F_C,
262 I2F_R,
263 I2F_IMM,
264 LOP32I,
265 MOV_C,
266 MOV_R,
267 MOV_IMM,
268 MOV32I,
269 SHR_C,
270 SHR_R,
271 SHR_IMM,
272 FSETP_C, // Set Predicate
273 FSETP_R,
274 FSETP_IMM,
275 ISETP_C,
276 ISETP_IMM,
277 ISETP_R,
278 };
279
280 enum class Type {
281 Trivial,
282 Arithmetic,
283 Ffma,
284 Flow,
285 Memory,
286 FloatPredicate,
287 IntegerPredicate,
288 Unknown,
289 };
290
291 class Matcher {
292 public:
293 Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
294 : name{name}, mask{mask}, expected{expected}, id{id}, type{type} {}
295
296 const char* GetName() const {
297 return name;
298 }
299
300 u16 GetMask() const {
301 return mask;
302 }
303
304 Id GetId() const {
305 return id;
306 }
307
308 Type GetType() const {
309 return type;
310 }
311
312 /**
313 * Tests to see if the given instruction is the instruction this matcher represents.
314 * @param instruction The instruction to test
315 * @returns true if the given instruction matches.
316 */
317 bool Matches(u16 instruction) const {
318 return (instruction & mask) == expected;
319 }
320
321 private:
322 const char* name;
323 u16 mask;
324 u16 expected;
325 Id id;
326 Type type;
327 };
328
329 static boost::optional<const Matcher&> Decode(Instruction instr) {
330 static const auto table{GetDecodeTable()};
331
332 const auto matches_instruction = [instr](const auto& matcher) {
333 return matcher.Matches(static_cast<u16>(instr.opcode));
334 };
335
336 auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
337 return iter != table.end() ? boost::optional<const Matcher&>(*iter) : boost::none;
338 }
339
340private:
341 struct Detail {
342 private:
343 static constexpr size_t opcode_bitsize = 16;
344
345 /**
346 * Generates the mask and the expected value after masking from a given bitstring.
347 * A '0' in a bitstring indicates that a zero must be present at that bit position.
348 * A '1' in a bitstring indicates that a one must be present at that bit position.
349 */
350 static auto GetMaskAndExpect(const char* const bitstring) {
351 u16 mask = 0, expect = 0;
352 for (size_t i = 0; i < opcode_bitsize; i++) {
353 const size_t bit_position = opcode_bitsize - i - 1;
354 switch (bitstring[i]) {
355 case '0':
356 mask |= 1 << bit_position;
357 break;
358 case '1':
359 expect |= 1 << bit_position;
360 mask |= 1 << bit_position;
361 break;
362 default:
363 // Ignore
364 break;
365 }
366 }
367 return std::make_tuple(mask, expect);
368 }
369
370 public:
371 /// Creates a matcher that can match and parse instructions based on bitstring.
372 static auto GetMatcher(const char* const bitstring, OpCode::Id op, OpCode::Type type,
373 const char* const name) {
374 const auto mask_expect = GetMaskAndExpect(bitstring);
375 return Matcher(name, std::get<0>(mask_expect), std::get<1>(mask_expect), op, type);
376 }
377 };
378
379 static std::vector<Matcher> GetDecodeTable() {
380 std::vector<Matcher> table = {
381#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
382 INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
383 INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
384 INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
385 INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"),
386 INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"),
387 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
388 INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"),
389 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
390 INST("001100101-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
391 INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"),
392 INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"),
393 INST("010110011-------", Id::FFMA_RR, Type::Ffma, "FFMA_RR"),
394 INST("0100110001011---", Id::FADD_C, Type::Arithmetic, "FADD_C"),
395 INST("0101110001011---", Id::FADD_R, Type::Arithmetic, "FADD_R"),
396 INST("0011100-01011---", Id::FADD_IMM, Type::Arithmetic, "FADD_IMM"),
397 INST("0100110001101---", Id::FMUL_C, Type::Arithmetic, "FMUL_C"),
398 INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"),
399 INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"),
400 INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"),
401 INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
402 INST("0101110010010---", Id::RRO, Type::Arithmetic, "RRO"),
403 INST("0100110010101---", Id::F2F_C, Type::Arithmetic, "F2F_C"),
404 INST("0101110010101---", Id::F2F_R, Type::Arithmetic, "F2F_R"),
405 INST("0011100-10101---", Id::F2F_IMM, Type::Arithmetic, "F2F_IMM"),
406 INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
407 INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
408 INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
409 INST("0100110010111---", Id::I2F_C, Type::Arithmetic, "I2F_C"),
410 INST("0101110010111---", Id::I2F_R, Type::Arithmetic, "I2F_R"),
411 INST("0011100-10111---", Id::I2F_IMM, Type::Arithmetic, "I2F_IMM"),
412 INST("000001----------", Id::LOP32I, Type::Arithmetic, "LOP32I"),
413 INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
414 INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
415 INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
416 INST("000000010000----", Id::MOV32I, Type::Arithmetic, "MOV32I"),
417 INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"),
418 INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"),
419 INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"),
420 INST("010010111011----", Id::FSETP_C, Type::FloatPredicate, "FSETP_C"),
421 INST("010110111011----", Id::FSETP_R, Type::FloatPredicate, "FSETP_R"),
422 INST("0011011-1011----", Id::FSETP_IMM, Type::FloatPredicate, "FSETP_IMM"),
423 INST("010010110110----", Id::ISETP_C, Type::IntegerPredicate, "ISETP_C"),
424 INST("010110110110----", Id::ISETP_R, Type::IntegerPredicate, "ISETP_R"),
425 INST("0011011-0110----", Id::ISETP_IMM, Type::IntegerPredicate, "ISETP_IMM"),
426 };
427#undef INST
428 std::stable_sort(table.begin(), table.end(), [](const auto& a, const auto& b) {
429 // If a matcher has more bits in its mask it is more specific, so it
430 // should come first.
431 return std::bitset<16>(a.GetMask()).count() > std::bitset<16>(b.GetMask()).count();
432 });
433
434 return table;
435 }
436};
437
404} // namespace Shader 438} // namespace Shader
405} // namespace Tegra 439} // namespace Tegra
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 2395945c3..086424395 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -97,11 +97,12 @@ private:
97 return exit_method; 97 return exit_method;
98 98
99 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { 99 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
100 const Instruction instr = {program_code[offset]}; 100 if (const auto opcode = OpCode::Decode({program_code[offset]})) {
101 switch (instr.opcode.EffectiveOpCode()) { 101 switch (opcode->GetId()) {
102 case OpCode::Id::EXIT: { 102 case OpCode::Id::EXIT: {
103 return exit_method = ExitMethod::AlwaysEnd; 103 return exit_method = ExitMethod::AlwaysEnd;
104 } 104 }
105 }
105 } 106 }
106 } 107 }
107 return exit_method = ExitMethod::AlwaysReturn; 108 return exit_method = ExitMethod::AlwaysReturn;
@@ -332,12 +333,20 @@ private:
332 */ 333 */
333 u32 CompileInstr(u32 offset) { 334 u32 CompileInstr(u32 offset) {
334 // Ignore sched instructions when generating code. 335 // Ignore sched instructions when generating code.
335 if (IsSchedInstruction(offset)) 336 if (IsSchedInstruction(offset)) {
336 return offset + 1; 337 return offset + 1;
338 }
337 339
338 const Instruction instr = {program_code[offset]}; 340 const Instruction instr = {program_code[offset]};
341 const auto opcode = OpCode::Decode(instr);
339 342
340 shader.AddLine("// " + std::to_string(offset) + ": " + OpCode::GetInfo(instr.opcode).name); 343 // Decoding failure
344 if (!opcode) {
345 NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {0:x}", instr.value);
346 UNREACHABLE();
347 }
348
349 shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName());
341 350
342 using Tegra::Shader::Pred; 351 using Tegra::Shader::Pred;
343 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute, 352 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
@@ -349,7 +358,7 @@ private:
349 ++shader.scope; 358 ++shader.scope;
350 } 359 }
351 360
352 switch (OpCode::GetInfo(instr.opcode).type) { 361 switch (opcode->GetType()) {
353 case OpCode::Type::Arithmetic: { 362 case OpCode::Type::Arithmetic: {
354 std::string dest = GetRegister(instr.gpr0); 363 std::string dest = GetRegister(instr.gpr0);
355 std::string op_a = instr.alu.negate_a ? "-" : ""; 364 std::string op_a = instr.alu.negate_a ? "-" : "";
@@ -374,7 +383,7 @@ private:
374 op_b = "abs(" + op_b + ")"; 383 op_b = "abs(" + op_b + ")";
375 } 384 }
376 385
377 switch (instr.opcode.EffectiveOpCode()) { 386 switch (opcode->GetId()) {
378 case OpCode::Id::FMUL_C: 387 case OpCode::Id::FMUL_C:
379 case OpCode::Id::FMUL_R: 388 case OpCode::Id::FMUL_R:
380 case OpCode::Id::FMUL_IMM: { 389 case OpCode::Id::FMUL_IMM: {
@@ -416,16 +425,18 @@ private:
416 SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d); 425 SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d);
417 break; 426 break;
418 default: 427 default:
419 NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {}", 428 NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}",
420 static_cast<unsigned>(instr.sub_op.Value())); 429 static_cast<unsigned>(instr.sub_op.Value()));
421 UNREACHABLE(); 430 UNREACHABLE();
422 } 431 }
423 break; 432 break;
424 } 433 }
434 case OpCode::Id::RRO: {
435 NGLOG_DEBUG(HW_GPU, "Skipping RRO instruction");
436 break;
437 }
425 default: { 438 default: {
426 NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}", 439 NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", opcode->GetName());
427 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
428 OpCode::GetInfo(instr.opcode).name, instr.hex);
429 UNREACHABLE(); 440 UNREACHABLE();
430 } 441 }
431 } 442 }
@@ -437,7 +448,7 @@ private:
437 std::string op_b = instr.ffma.negate_b ? "-" : ""; 448 std::string op_b = instr.ffma.negate_b ? "-" : "";
438 std::string op_c = instr.ffma.negate_c ? "-" : ""; 449 std::string op_c = instr.ffma.negate_c ? "-" : "";
439 450
440 switch (instr.opcode.EffectiveOpCode()) { 451 switch (opcode->GetId()) {
441 case OpCode::Id::FFMA_CR: { 452 case OpCode::Id::FFMA_CR: {
442 op_b += GetUniform(instr.uniform); 453 op_b += GetUniform(instr.uniform);
443 op_c += GetRegister(instr.gpr39); 454 op_c += GetRegister(instr.gpr39);
@@ -459,9 +470,7 @@ private:
459 break; 470 break;
460 } 471 }
461 default: { 472 default: {
462 NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {} ({}): {}", 473 NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->GetName());
463 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
464 OpCode::GetInfo(instr.opcode).name, instr.hex);
465 UNREACHABLE(); 474 UNREACHABLE();
466 } 475 }
467 } 476 }
@@ -473,7 +482,7 @@ private:
473 std::string gpr0 = GetRegister(instr.gpr0); 482 std::string gpr0 = GetRegister(instr.gpr0);
474 const Attribute::Index attribute = instr.attribute.fmt20.index; 483 const Attribute::Index attribute = instr.attribute.fmt20.index;
475 484
476 switch (instr.opcode.EffectiveOpCode()) { 485 switch (opcode->GetId()) {
477 case OpCode::Id::LD_A: { 486 case OpCode::Id::LD_A: {
478 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); 487 ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
479 SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4); 488 SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4);
@@ -504,9 +513,7 @@ private:
504 break; 513 break;
505 } 514 }
506 default: { 515 default: {
507 NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {} ({}): {}", 516 NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName());
508 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
509 OpCode::GetInfo(instr.opcode).name, instr.hex);
510 UNREACHABLE(); 517 UNREACHABLE();
511 } 518 }
512 } 519 }
@@ -564,7 +571,7 @@ private:
564 break; 571 break;
565 } 572 }
566 default: { 573 default: {
567 switch (instr.opcode.EffectiveOpCode()) { 574 switch (opcode->GetId()) {
568 case OpCode::Id::EXIT: { 575 case OpCode::Id::EXIT: {
569 ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex), 576 ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex),
570 "Predicated exits not implemented"); 577 "Predicated exits not implemented");
@@ -583,9 +590,7 @@ private:
583 break; 590 break;
584 } 591 }
585 default: { 592 default: {
586 NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}", 593 NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName());
587 static_cast<unsigned>(instr.opcode.EffectiveOpCode()),
588 OpCode::GetInfo(instr.opcode).name, instr.hex);
589 UNREACHABLE(); 594 UNREACHABLE();
590 } 595 }
591 } 596 }