From 9e2e50aed768b3aff72cfe871ff93de3373886ff Mon Sep 17 00:00:00 2001 From: Takoroka <137927095+Takoroka@users.noreply.github.com> Date: Fri, 30 Oct 2026 14:22:15 -0400 Subject: nx2: lower REDUX.MIN REDUX.MIN (unsigned; Kirby Air Riders reduces a lane value with both .MIN and .MAX) is lowered as REDUX.MAX with IMNMX selecting the minimum, starting from ~0, with inactive lanes contributing ~0. --- src/shader_recompiler/frontend/ampere/lower_to_maxwell.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h index 6974a2e2dc..739f3b10d0 100644 --- a/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h +++ b/src/shader_recompiler/frontend/ampere/lower_to_maxwell.h @@ -902,24 +902,28 @@ inline LoweredProgram LowerToMaxwell(std::span code) { (u64{1} << 15) | (u64{7} << 29) | (u64{7} << 39)); break; } - case 0x3c4: { // REDUX.SUM (modulo 2^32), .MAX (unsigned), .OR or .XOR over the actual active lanes. + case 0x3c4: { // REDUX.SUM (modulo 2^32), .MIN/.MAX (unsigned), .OR or .XOR over the actual active lanes. const u32 source = insn.Bits(24, 8), target = uniform_register(static_cast(dest)); - const bool maximum = insn.words[2] == 0x14000; + const bool maximum = insn.words[2] == 0x14000, minimum = insn.words[2] == 0x10000; // OR and XOR: inactive lanes contribute zero, as for the sum. Maxwell LOP: 1 = OR, 2 = XOR. const u32 logical = insn.words[2] == 0x4000 ? 1U : insn.words[2] == 0x8000 ? 2U : 0U; if (target == ~0U || target == 255 || insn.words[1] || - (insn.words[2] != 0xc000 && !maximum && !logical) || native_predicate != 7) + (insn.words[2] != 0xc000 && !maximum && !minimum && !logical) || native_predicate != 7) return fail(index, "native warp sum mode"); emit(0x50d8000000070000ULL | 250 | (u64{7} << 39) | (u64{7} << 45) | (u64{1} << 48)); - mov_imm(target, 0); + mov_imm(target, minimum ? ~0U : 0U); for (u32 lane = 0; lane < 32; ++lane) { emit(0xef10000000070000ULL | 251 | (u64{source} << 8) | (u64{lane} << 20) | (u64{1} << 28) | (u64{1} << 29) | (u64{31} << 34) | (u64{7} << 48)); emit(0x3828000000070000ULL | 252 | (u64{250} << 8) | (u64{lane} << 20)); emit(0x0400000000070000ULL | 252 | (u64{252} << 8) | (u64{1} << 20)); emit(0x5c10000000070000ULL | 252 | (u64{255} << 8) | (u64{252} << 20) | (u64{1} << 48)); - emit(0x5c40000000070000ULL | 251 | (u64{251} << 8) | (u64{252} << 20) | (u64{7} << 48)); - if (maximum) { + // Inactive lanes: 0, or ~0 for the minimum (OR with the inverted lane mask). + emit(0x5c40000000070000ULL | 251 | (u64{251} << 8) | (u64{252} << 20) | (u64{7} << 48) | + (u64{minimum} << 40) | (u64{minimum} << 41)); + if (minimum) { + emit(0x5c20000000070000ULL | target | (u64{target} << 8) | (u64{251} << 20) | (u64{7} << 39)); + } else if (maximum) { emit(0x5c20000000070000ULL | target | (u64{target} << 8) | (u64{251} << 20) | (u64{15} << 39)); } else if (logical) { emit(0x5c40000000070000ULL | target | (u64{target} << 8) | (u64{251} << 20) | -- cgit v1.2.3