diff options
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate/impl/load_store_local_shared.cpp | 25 |
1 files changed, 21 insertions, 4 deletions
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 index 20df163f2..d2a1dbf61 100644 --- 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 | |||
| @@ -85,21 +85,28 @@ IR::U32 ByteOffset(IR::IREmitter& ir, const IR::U32& offset) { | |||
| 85 | IR::U32 ShortOffset(IR::IREmitter& ir, const IR::U32& offset) { | 85 | IR::U32 ShortOffset(IR::IREmitter& ir, const IR::U32& offset) { |
| 86 | return ir.BitwiseAnd(ir.ShiftLeftLogical(offset, ir.Imm32(3)), ir.Imm32(16)); | 86 | return ir.BitwiseAnd(ir.ShiftLeftLogical(offset, ir.Imm32(3)), ir.Imm32(16)); |
| 87 | } | 87 | } |
| 88 | |||
| 89 | IR::U32 LoadLocal(TranslatorVisitor& v, const IR::U32& word_offset, const IR::U32& offset) { | ||
| 90 | const IR::U32 local_memory_size{v.ir.Imm32(v.env.LocalMemorySize())}; | ||
| 91 | const IR::U1 in_bounds{v.ir.ILessThan(offset, local_memory_size, false)}; | ||
| 92 | return IR::U32{v.ir.Select(in_bounds, v.ir.LoadLocal(word_offset), v.ir.Imm32(0))}; | ||
| 93 | } | ||
| 88 | } // Anonymous namespace | 94 | } // Anonymous namespace |
| 89 | 95 | ||
| 90 | void TranslatorVisitor::LDL(u64 insn) { | 96 | void TranslatorVisitor::LDL(u64 insn) { |
| 91 | const auto [word_offset, offset]{WordOffset(*this, insn)}; | 97 | const auto [word_offset, offset]{WordOffset(*this, insn)}; |
| 98 | const IR::U32 word{LoadLocal(*this, word_offset, offset)}; | ||
| 92 | const IR::Reg dest{Reg(insn)}; | 99 | const IR::Reg dest{Reg(insn)}; |
| 93 | const auto [bit_size, is_signed]{GetSize(insn)}; | 100 | const auto [bit_size, is_signed]{GetSize(insn)}; |
| 94 | switch (bit_size) { | 101 | switch (bit_size) { |
| 95 | case 8: { | 102 | case 8: { |
| 96 | const IR::U32 bit{ByteOffset(ir, offset)}; | 103 | const IR::U32 bit{ByteOffset(ir, offset)}; |
| 97 | X(dest, ir.BitFieldExtract(ir.LoadLocal(word_offset), bit, ir.Imm32(8), is_signed)); | 104 | X(dest, ir.BitFieldExtract(word, bit, ir.Imm32(8), is_signed)); |
| 98 | break; | 105 | break; |
| 99 | } | 106 | } |
| 100 | case 16: { | 107 | case 16: { |
| 101 | const IR::U32 bit{ShortOffset(ir, offset)}; | 108 | const IR::U32 bit{ShortOffset(ir, offset)}; |
| 102 | X(dest, ir.BitFieldExtract(ir.LoadLocal(word_offset), bit, ir.Imm32(16), is_signed)); | 109 | X(dest, ir.BitFieldExtract(word, bit, ir.Imm32(16), is_signed)); |
| 103 | break; | 110 | break; |
| 104 | } | 111 | } |
| 105 | case 32: | 112 | case 32: |
| @@ -108,9 +115,11 @@ void TranslatorVisitor::LDL(u64 insn) { | |||
| 108 | if (!IR::IsAligned(dest, static_cast<size_t>(bit_size / 32))) { | 115 | if (!IR::IsAligned(dest, static_cast<size_t>(bit_size / 32))) { |
| 109 | throw NotImplementedException("Unaligned destination register {}", dest); | 116 | throw NotImplementedException("Unaligned destination register {}", dest); |
| 110 | } | 117 | } |
| 111 | X(dest, ir.LoadLocal(word_offset)); | 118 | X(dest, word); |
| 112 | for (int i = 1; i < bit_size / 32; ++i) { | 119 | for (int i = 1; i < bit_size / 32; ++i) { |
| 113 | X(dest + i, ir.LoadLocal(ir.IAdd(word_offset, ir.Imm32(i)))); | 120 | const IR::U32 sub_word_offset{ir.IAdd(word_offset, ir.Imm32(i))}; |
| 121 | const IR::U32 sub_offset{ir.IAdd(offset, ir.Imm32(i * 4))}; | ||
| 122 | X(dest + i, LoadLocal(*this, sub_word_offset, sub_offset)); | ||
| 114 | } | 123 | } |
| 115 | break; | 124 | break; |
| 116 | } | 125 | } |
| @@ -141,6 +150,14 @@ void TranslatorVisitor::LDS(u64 insn) { | |||
| 141 | 150 | ||
| 142 | void TranslatorVisitor::STL(u64 insn) { | 151 | void TranslatorVisitor::STL(u64 insn) { |
| 143 | const auto [word_offset, offset]{WordOffset(*this, insn)}; | 152 | const auto [word_offset, offset]{WordOffset(*this, insn)}; |
| 153 | if (offset.IsImmediate()) { | ||
| 154 | // TODO: Support storing out of bounds at runtime | ||
| 155 | if (offset.U32() >= env.LocalMemorySize()) { | ||
| 156 | LOG_WARNING(Shader, "Storing local memory at 0x{:x} with a size of 0x{:x}, dropping", | ||
| 157 | offset.U32(), env.LocalMemorySize()); | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | } | ||
| 144 | const IR::Reg reg{Reg(insn)}; | 161 | const IR::Reg reg{Reg(insn)}; |
| 145 | const IR::U32 src{X(reg)}; | 162 | const IR::U32 src{X(reg)}; |
| 146 | const int bit_size{GetSize(insn).first}; | 163 | const int bit_size{GetSize(insn).first}; |