diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 11:57:48 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 11:05:53 -0500 |
| commit | b2dd8f113441b03c46386dffb1f188af770dc2bf (patch) | |
| tree | b2a5cea9cdf492145428ebdbfe11225fd07e7a5c /src/shader_recompiler | |
| parent | 6e38b4c8fbb653eef82864a76127f04f4da4c394 (diff) | |
nx2: lower 128-bit and register-addressed local spills
Local loads and stores were lowered only as 32-bit accesses at an
immediate offset with no cache hint. Kirby Air Riders zero-fills and
reloads a local array with STL.128/LDL.128 and loads through a register
address (LDL R16, [R18]). Take the address register, accept the .LU hint
on loads, and split 128-bit accesses into four 32-bit ones.
Diffstat (limited to 'src/shader_recompiler')
| -rw-r--r-- | src/shader_recompiler/frontend/ampere/lower_to_maxwell.h | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h index d81f6742b1..b13b94be9d 100644 --- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h +++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h @@ -1722,15 +1722,21 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) { result.instructions.push_back(translated); break; } - case 0x387: case 0x983: { // Captured scalar local spill at an immediate byte offset. - const bool store = opcode == 0x387; - const u32 data = insn.Bits(32, 8), offset = insn.Bits(40, 24); - if (insn.Bits(24, 8) != 255 || (store && (insn.Bits(16, 8) || data > 247)) || - (!store && (data || dest >= 248)) || (offset & 3) || offset > 0x7fffff || - insn.words[2] != (store ? 0x00100800U : 0x00300800U)) + case 0x387: case 0x983: { // Local spill: 32 or 128 bits at [Ra + immediate byte offset]. + // 128-bit accesses (bits 72-74 = 6) become four 32-bit ones; a load's bit 85 (.LU) is a + // cache hint. + const bool store = opcode == 0x387, wide = insn.Bits(72, 3) == 6; + const u32 data = insn.Bits(32, 8), offset = insn.Bits(40, 24), address = insn.Bits(24, 8); + const u32 words = wide ? 4 : 1, value = store ? data : static_cast<u32>(dest); + if ((address != 255 && address >= 246) || (store && insn.Bits(16, 8)) || (!store && data) || + (value != 255 && (value + words > 248 || (wide && (value & 3)))) || (!store && value == 255) || + (offset & 3) || offset + 4 * words > 0x800000 || + (insn.words[2] & ~(store ? 0x400U : 0x200400U)) != 0x00100800U) return fail(index, "native local scalar spill mode"); - emit((store ? 0xef50000000000000ULL : 0xef40000000000000ULL) | predicate | - (store ? data : dest) | (u64{255} << 8) | (u64{offset} << 20) | (u64{4} << 48)); + for (u32 word = 0; word < words; ++word) + emit((store ? 0xef50000000000000ULL : 0xef40000000000000ULL) | predicate | + (value == 255 ? 255U : value + word) | (u64{address} << 8) | + (u64{offset + 4 * word} << 20) | (u64{4} << 48)); break; } case 0x803: { // P2R PR, register merge source, immediate mask, byte select (76-77) |
