aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 11:57:48 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-11-01 11:05:53 -0500
commitb2dd8f113441b03c46386dffb1f188af770dc2bf (patch)
treeb2a5cea9cdf492145428ebdbfe11225fd07e7a5c /src
parent6e38b4c8fbb653eef82864a76127f04f4da4c394 (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')
-rw-r--r--src/shader_recompiler/frontend/ampere/lower_to_maxwell.h22
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)