summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp46
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h6
-rw-r--r--src/shader_recompiler/frontend/ir/microinstruction.cpp6
-rw-r--r--src/shader_recompiler/frontend/ir/opcodes.inc18
-rw-r--r--src/shader_recompiler/frontend/ir/program.h2
-rw-r--r--src/shader_recompiler/frontend/maxwell/program.cpp2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/load_store_local_shared.cpp197
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp16
8 files changed, 277 insertions, 16 deletions
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index 6d41442ee..d6a1d8ec2 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -355,6 +355,52 @@ void IREmitter::WriteGlobal128(const U64& address, const IR::Value& vector) {
355 Inst(Opcode::WriteGlobal128, address, vector); 355 Inst(Opcode::WriteGlobal128, address, vector);
356} 356}
357 357
358U32 IREmitter::LoadLocal(const IR::U32& word_offset) {
359 return Inst<U32>(Opcode::LoadLocal, word_offset);
360}
361
362void IREmitter::WriteLocal(const IR::U32& word_offset, const IR::U32& value) {
363 Inst(Opcode::WriteLocal, word_offset, value);
364}
365
366Value IREmitter::LoadShared(int bit_size, bool is_signed, const IR::U32& offset) {
367 switch (bit_size) {
368 case 8:
369 return Inst(is_signed ? Opcode::LoadSharedS8 : Opcode::LoadSharedU8, offset);
370 case 16:
371 return Inst(is_signed ? Opcode::LoadSharedS16 : Opcode::LoadSharedU16, offset);
372 case 32:
373 return Inst(Opcode::LoadSharedU32, offset);
374 case 64:
375 return Inst(Opcode::LoadSharedU64, offset);
376 case 128:
377 return Inst(Opcode::LoadSharedU128, offset);
378 }
379 throw InvalidArgument("Invalid bit size {}", bit_size);
380}
381
382void IREmitter::WriteShared(int bit_size, const IR::U32& offset, const IR::Value& value) {
383 switch (bit_size) {
384 case 8:
385 Inst(Opcode::WriteSharedU8, offset, value);
386 break;
387 case 16:
388 Inst(Opcode::WriteSharedU16, offset, value);
389 break;
390 case 32:
391 Inst(Opcode::WriteSharedU32, offset, value);
392 break;
393 case 64:
394 Inst(Opcode::WriteSharedU64, offset, value);
395 break;
396 case 128:
397 Inst(Opcode::WriteSharedU128, offset, value);
398 break;
399 default:
400 throw InvalidArgument("Invalid bit size {}", bit_size);
401 }
402}
403
358U1 IREmitter::GetZeroFromOp(const Value& op) { 404U1 IREmitter::GetZeroFromOp(const Value& op) {
359 return Inst<U1>(Opcode::GetZeroFromOp, op); 405 return Inst<U1>(Opcode::GetZeroFromOp, op);
360} 406}
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 8d50aa607..842c2bdaf 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -99,6 +99,12 @@ public:
99 void WriteGlobal64(const U64& address, const IR::Value& vector); 99 void WriteGlobal64(const U64& address, const IR::Value& vector);
100 void WriteGlobal128(const U64& address, const IR::Value& vector); 100 void WriteGlobal128(const U64& address, const IR::Value& vector);
101 101
102 [[nodiscard]] U32 LoadLocal(const U32& word_offset);
103 void WriteLocal(const U32& word_offset, const U32& value);
104
105 [[nodiscard]] Value LoadShared(int bit_size, bool is_signed, const U32& offset);
106 void WriteShared(int bit_size, const U32& offset, const Value& value);
107
102 [[nodiscard]] U1 GetZeroFromOp(const Value& op); 108 [[nodiscard]] U1 GetZeroFromOp(const Value& op);
103 [[nodiscard]] U1 GetSignFromOp(const Value& op); 109 [[nodiscard]] U1 GetSignFromOp(const Value& op);
104 [[nodiscard]] U1 GetCarryFromOp(const Value& op); 110 [[nodiscard]] U1 GetCarryFromOp(const Value& op);
diff --git a/src/shader_recompiler/frontend/ir/microinstruction.cpp b/src/shader_recompiler/frontend/ir/microinstruction.cpp
index be8eb4d4c..52a5e5034 100644
--- a/src/shader_recompiler/frontend/ir/microinstruction.cpp
+++ b/src/shader_recompiler/frontend/ir/microinstruction.cpp
@@ -76,6 +76,12 @@ bool Inst::MayHaveSideEffects() const noexcept {
76 case Opcode::WriteStorage32: 76 case Opcode::WriteStorage32:
77 case Opcode::WriteStorage64: 77 case Opcode::WriteStorage64:
78 case Opcode::WriteStorage128: 78 case Opcode::WriteStorage128:
79 case Opcode::WriteLocal:
80 case Opcode::WriteSharedU8:
81 case Opcode::WriteSharedU16:
82 case Opcode::WriteSharedU32:
83 case Opcode::WriteSharedU64:
84 case Opcode::WriteSharedU128:
79 return true; 85 return true;
80 default: 86 default:
81 return false; 87 return false;
diff --git a/src/shader_recompiler/frontend/ir/opcodes.inc b/src/shader_recompiler/frontend/ir/opcodes.inc
index 5d7462d76..c75658328 100644
--- a/src/shader_recompiler/frontend/ir/opcodes.inc
+++ b/src/shader_recompiler/frontend/ir/opcodes.inc
@@ -89,6 +89,24 @@ OPCODE(WriteStorage32, Void, U32,
89OPCODE(WriteStorage64, Void, U32, U32, U32x2, ) 89OPCODE(WriteStorage64, Void, U32, U32, U32x2, )
90OPCODE(WriteStorage128, Void, U32, U32, U32x4, ) 90OPCODE(WriteStorage128, Void, U32, U32, U32x4, )
91 91
92// Local memory operations
93OPCODE(LoadLocal, U32, U32, )
94OPCODE(WriteLocal, Void, U32, U32, )
95
96// Shared memory operations
97OPCODE(LoadSharedU8, U32, U32, )
98OPCODE(LoadSharedS8, U32, U32, )
99OPCODE(LoadSharedU16, U32, U32, )
100OPCODE(LoadSharedS16, U32, U32, )
101OPCODE(LoadSharedU32, U32, U32, )
102OPCODE(LoadSharedU64, U32x2, U32, )
103OPCODE(LoadSharedU128, U32x4, U32, )
104OPCODE(WriteSharedU8, Void, U32, U32, )
105OPCODE(WriteSharedU16, Void, U32, U32, )
106OPCODE(WriteSharedU32, Void, U32, U32, )
107OPCODE(WriteSharedU64, Void, U32, U32x2, )
108OPCODE(WriteSharedU128, Void, U32, U32x4, )
109
92// Vector utility 110// Vector utility
93OPCODE(CompositeConstructU32x2, U32x2, U32, U32, ) 111OPCODE(CompositeConstructU32x2, U32x2, U32, U32, )
94OPCODE(CompositeConstructU32x3, U32x3, U32, U32, U32, ) 112OPCODE(CompositeConstructU32x3, U32x3, U32, U32, U32, )
diff --git a/src/shader_recompiler/frontend/ir/program.h b/src/shader_recompiler/frontend/ir/program.h
index 0162e919c..3a37b3ab9 100644
--- a/src/shader_recompiler/frontend/ir/program.h
+++ b/src/shader_recompiler/frontend/ir/program.h
@@ -21,6 +21,8 @@ struct Program {
21 Info info; 21 Info info;
22 Stage stage{}; 22 Stage stage{};
23 std::array<u32, 3> workgroup_size{}; 23 std::array<u32, 3> workgroup_size{};
24 u32 local_memory_size{};
25 u32 shared_memory_size{};
24}; 26};
25 27
26[[nodiscard]] std::string DumpProgram(const Program& program); 28[[nodiscard]] std::string DumpProgram(const Program& program);
diff --git a/src/shader_recompiler/frontend/maxwell/program.cpp b/src/shader_recompiler/frontend/maxwell/program.cpp
index a914a91f4..7b08f11b0 100644
--- a/src/shader_recompiler/frontend/maxwell/program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/program.cpp
@@ -67,8 +67,10 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
67 program.blocks = VisitAST(inst_pool, block_pool, env, cfg); 67 program.blocks = VisitAST(inst_pool, block_pool, env, cfg);
68 program.post_order_blocks = PostOrder(program.blocks); 68 program.post_order_blocks = PostOrder(program.blocks);
69 program.stage = env.ShaderStage(); 69 program.stage = env.ShaderStage();
70 program.local_memory_size = env.LocalMemorySize();
70 if (program.stage == Stage::Compute) { 71 if (program.stage == Stage::Compute) {
71 program.workgroup_size = env.WorkgroupSize(); 72 program.workgroup_size = env.WorkgroupSize();
73 program.shared_memory_size = env.SharedMemorySize();
72 } 74 }
73 RemoveUnreachableBlocks(program); 75 RemoveUnreachableBlocks(program);
74 76
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_local_shared.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_local_shared.cpp
new file mode 100644
index 000000000..68963c8ea
--- /dev/null
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/load_store_local_shared.cpp
@@ -0,0 +1,197 @@
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 "common/bit_field.h"
6#include "common/common_types.h"
7#include "shader_recompiler/frontend/maxwell/translate/impl/impl.h"
8
9namespace Shader::Maxwell {
10namespace {
11enum class Size : u64 {
12 U8,
13 S8,
14 U16,
15 S16,
16 B32,
17 B64,
18 B128,
19};
20
21IR::U32 Offset(TranslatorVisitor& v, u64 insn) {
22 union {
23 u64 raw;
24 BitField<8, 8, IR::Reg> offset_reg;
25 BitField<20, 24, u64> absolute_offset;
26 BitField<20, 24, s64> relative_offset;
27 } const encoding{insn};
28
29 if (encoding.offset_reg == IR::Reg::RZ) {
30 return v.ir.Imm32(static_cast<u32>(encoding.absolute_offset));
31 } else {
32 const s32 relative{static_cast<s32>(encoding.relative_offset.Value())};
33 return v.ir.IAdd(v.X(encoding.offset_reg), v.ir.Imm32(relative));
34 }
35}
36
37std::pair<int, bool> GetSize(u64 insn) {
38 union {
39 u64 raw;
40 BitField<48, 3, Size> size;
41 } const encoding{insn};
42
43 const Size nnn = encoding.size;
44 switch (encoding.size) {
45 case Size::U8:
46 return {8, false};
47 case Size::S8:
48 return {8, true};
49 case Size::U16:
50 return {16, false};
51 case Size::S16:
52 return {16, true};
53 case Size::B32:
54 return {32, false};
55 case Size::B64:
56 return {64, false};
57 case Size::B128:
58 return {128, false};
59 default:
60 throw NotImplementedException("Invalid size {}", encoding.size.Value());
61 }
62}
63
64IR::Reg Reg(u64 insn) {
65 union {
66 u64 raw;
67 BitField<0, 8, IR::Reg> reg;
68 } const encoding{insn};
69
70 return encoding.reg;
71}
72
73IR::U32 ByteOffset(IR::IREmitter& ir, const IR::U32& offset) {
74 return ir.BitwiseAnd(ir.ShiftLeftLogical(offset, ir.Imm32(3)), ir.Imm32(24));
75}
76
77IR::U32 ShortOffset(IR::IREmitter& ir, const IR::U32& offset) {
78 return ir.BitwiseAnd(ir.ShiftLeftLogical(offset, ir.Imm32(3)), ir.Imm32(16));
79}
80} // Anonymous namespace
81
82void TranslatorVisitor::LDL(u64 insn) {
83 const IR::U32 offset{Offset(*this, insn)};
84 const IR::U32 word_offset{ir.ShiftRightArithmetic(offset, ir.Imm32(2))};
85
86 const IR::Reg dest{Reg(insn)};
87 const auto [bit_size, is_signed]{GetSize(insn)};
88 switch (bit_size) {
89 case 8: {
90 const IR::U32 bit{ByteOffset(ir, offset)};
91 X(dest, ir.BitFieldExtract(ir.LoadLocal(word_offset), bit, ir.Imm32(8), is_signed));
92 break;
93 }
94 case 16: {
95 const IR::U32 bit{ShortOffset(ir, offset)};
96 X(dest, ir.BitFieldExtract(ir.LoadLocal(word_offset), bit, ir.Imm32(16), is_signed));
97 break;
98 }
99 case 32:
100 case 64:
101 case 128:
102 if (!IR::IsAligned(dest, bit_size / 32)) {
103 throw NotImplementedException("Unaligned destination register {}", dest);
104 }
105 X(dest, ir.LoadLocal(word_offset));
106 for (int i = 1; i < bit_size / 32; ++i) {
107 X(dest + i, ir.LoadLocal(ir.IAdd(word_offset, ir.Imm32(i))));
108 }
109 break;
110 }
111}
112
113void TranslatorVisitor::LDS(u64 insn) {
114 const IR::U32 offset{Offset(*this, insn)};
115 const IR::Reg dest{Reg(insn)};
116 const auto [bit_size, is_signed]{GetSize(insn)};
117 const IR::Value value{ir.LoadShared(bit_size, is_signed, offset)};
118 switch (bit_size) {
119 case 8:
120 case 16:
121 case 32:
122 X(dest, IR::U32{value});
123 break;
124 case 64:
125 case 128:
126 if (!IR::IsAligned(dest, bit_size / 32)) {
127 throw NotImplementedException("Unaligned destination register {}", dest);
128 }
129 for (int element = 0; element < bit_size / 32; ++element) {
130 X(dest + element, IR::U32{ir.CompositeExtract(value, element)});
131 }
132 break;
133 }
134}
135
136void TranslatorVisitor::STL(u64 insn) {
137 const IR::U32 offset{Offset(*this, insn)};
138 const IR::U32 word_offset{ir.ShiftRightArithmetic(offset, ir.Imm32(2))};
139
140 const IR::Reg reg{Reg(insn)};
141 const IR::U32 src{X(reg)};
142 const int bit_size{GetSize(insn).first};
143 switch (bit_size) {
144 case 8: {
145 const IR::U32 bit{ByteOffset(ir, offset)};
146 const IR::U32 value{ir.BitFieldInsert(ir.LoadLocal(word_offset), src, bit, ir.Imm32(8))};
147 ir.WriteLocal(word_offset, value);
148 break;
149 }
150 case 16: {
151 const IR::U32 bit{ShortOffset(ir, offset)};
152 const IR::U32 value{ir.BitFieldInsert(ir.LoadLocal(word_offset), src, bit, ir.Imm32(16))};
153 ir.WriteLocal(word_offset, value);
154 break;
155 }
156 case 32:
157 case 64:
158 case 128:
159 if (!IR::IsAligned(reg, bit_size / 32)) {
160 throw NotImplementedException("Unaligned source register");
161 }
162 ir.WriteLocal(word_offset, src);
163 for (int i = 1; i < bit_size / 32; ++i) {
164 ir.WriteLocal(ir.IAdd(word_offset, ir.Imm32(i)), X(reg + i));
165 }
166 break;
167 }
168}
169
170void TranslatorVisitor::STS(u64 insn) {
171 const IR::U32 offset{Offset(*this, insn)};
172 const IR::Reg reg{Reg(insn)};
173 const int bit_size{GetSize(insn).first};
174 switch (bit_size) {
175 case 8:
176 case 16:
177 case 32:
178 ir.WriteShared(bit_size, offset, X(reg));
179 break;
180 case 64:
181 if (!IR::IsAligned(reg, 2)) {
182 throw NotImplementedException("Unaligned source register {}", reg);
183 }
184 ir.WriteShared(64, offset, ir.CompositeConstruct(X(reg), X(reg + 1)));
185 break;
186 case 128: {
187 if (!IR::IsAligned(reg, 2)) {
188 throw NotImplementedException("Unaligned source register {}", reg);
189 }
190 const IR::Value vector{ir.CompositeConstruct(X(reg), X(reg + 1), X(reg + 2), X(reg + 3))};
191 ir.WriteShared(128, offset, vector);
192 break;
193 }
194 }
195}
196
197} // namespace Shader::Maxwell
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
index 409216640..b62d8ee2a 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
@@ -193,14 +193,6 @@ void TranslatorVisitor::LD(u64) {
193 ThrowNotImplemented(Opcode::LD); 193 ThrowNotImplemented(Opcode::LD);
194} 194}
195 195
196void TranslatorVisitor::LDL(u64) {
197 ThrowNotImplemented(Opcode::LDL);
198}
199
200void TranslatorVisitor::LDS(u64) {
201 ThrowNotImplemented(Opcode::LDS);
202}
203
204void TranslatorVisitor::LEPC(u64) { 196void TranslatorVisitor::LEPC(u64) {
205 ThrowNotImplemented(Opcode::LEPC); 197 ThrowNotImplemented(Opcode::LEPC);
206} 198}
@@ -309,18 +301,10 @@ void TranslatorVisitor::ST(u64) {
309 ThrowNotImplemented(Opcode::ST); 301 ThrowNotImplemented(Opcode::ST);
310} 302}
311 303
312void TranslatorVisitor::STL(u64) {
313 ThrowNotImplemented(Opcode::STL);
314}
315
316void TranslatorVisitor::STP(u64) { 304void TranslatorVisitor::STP(u64) {
317 ThrowNotImplemented(Opcode::STP); 305 ThrowNotImplemented(Opcode::STP);
318} 306}
319 307
320void TranslatorVisitor::STS(u64) {
321 ThrowNotImplemented(Opcode::STS);
322}
323
324void TranslatorVisitor::SUATOM_cas(u64) { 308void TranslatorVisitor::SUATOM_cas(u64) {
325 ThrowNotImplemented(Opcode::SUATOM_cas); 309 ThrowNotImplemented(Opcode::SUATOM_cas);
326} 310}