diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-30 12:02:30 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 11:08:11 -0500 |
| commit | 732f91ded38d52b298cf4ef2c45f2db3c63331c9 (patch) | |
| tree | fda36a3741167cccd698fe15566d3be5a72a20bb /src | |
| parent | b52f29993f4a9b18b153860fb3da8ef7db73eaf2 (diff) | |
nx2: lower LEA with a carry out
LEA/ULEA with a carry-out predicate (the low half of a 64-bit address,
whose high half UIADD3.X/IADD3.X adds the carry to) was rejected; Kirby
Air Riders computes a pointer as ULEA UR4, UP0, UR4, UR6, 2 then
UIADD3.X. Compute the low word in a scratch register and the carry as
"sum < addend" (unsigned), as IADD3's carry out does, through P(6-n) and
R239 for a uniform predicate.
Diffstat (limited to 'src')
| -rw-r--r-- | src/shader_recompiler/frontend/ampere/lower_to_maxwell.h | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h index a7800bdea1..01c789dd9e 100644 --- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h +++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h @@ -2085,13 +2085,32 @@ inline LoweredProgram LowerToMaxwell(std::span<const Instruction> code) { } break; } - if (insn.Bits(72, 1) || insn.Bits(74, 1) || insn.Bits(80, 1) || insn.Bits(81, 3) != 7 || + // A carry out (bits 81-83) is the low half of a 64-bit address; IADD3.X adds it next. + const u32 carry_out = insn.Bits(81, 3); + if (insn.Bits(72, 1) || insn.Bits(74, 1) || insn.Bits(80, 1) || + (carry_out != 7 && (opcode != 0x211 || insn.Bits(63, 1) || (rewritten_uniform && carry_out > 1))) || (opcode == 0x211 && insn.Bits(62, 1)) || (opcode == 0xc11 && (insn.Bits(62, 2) || uniform_register(insn.Bits(32, 8)) == ~0U))) return fail(index, "native LEA carry/high mode"); // 0x211 bit 63 negates Rb (LEA Rd, Ra, -Rb, s), as Maxwell ISCADD's bit 48. u32 b = opcode == 0xc11 ? uniform_register(insn.Bits(32, 8)) : insn.Bits(32, 8); if (opcode == 0x811) { mov_imm(251, insn.words[1]); b = 251; } + if (carry_out != 7) { + // The sum in R250, carry = sum < Rb (unsigned), as IADD3's carry out; a uniform + // predicate goes through P(6-n) into R239. + const u32 target = rewritten_uniform ? 6 - carry_out : carry_out, mask = 1U << target; + emit(0x5c18000000000000ULL | predicate | 250 | (u64{insn.Bits(24, 8)} << 8) | + (u64{b} << 20) | (u64{insn.Bits(75, 5)} << 39)); + if (rewritten_uniform) emit(0x38e8000000070000ULL | 253 | (u64{255} << 8) | (u64{mask} << 20)); + emit(0x5b60000000000000ULL | predicate | 7 | (u64{target} << 3) | (u64{250} << 8) | + (u64{b} << 20) | (u64{7} << 39) | (u64{1} << 49)); + if (rewritten_uniform) { + emit(0x38e8000000070000ULL | 239 | (u64{239} << 8) | (u64{mask} << 20)); + emit(0x38f0000000070000ULL | (u64{253} << 8) | (u64{mask} << 20)); + } + emit(base(0x5c98000000000000ULL) | (u64{15} << 39) | (u64{250} << 20)); + break; + } emit(base(0x5c18000000000000ULL) | (u64{insn.Bits(24, 8)} << 8) | (u64{b} << 20) | (u64{insn.Bits(75, 5)} << 39) | (u64{opcode == 0x211 ? insn.Bits(63, 1) : 0U} << 48)); |
