aboutsummaryrefslogtreecommitdiff
path: root/src/shader_recompiler
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-30 14:22:15 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-11-01 11:09:34 -0500
commit9e2e50aed768b3aff72cfe871ff93de3373886ff (patch)
tree6e76d295b75cddc1e1ff33521ff743fd53248dfa /src/shader_recompiler
parentf4d79570e995c62aca41becf9d1cfa8c6cbec9ce (diff)
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.
Diffstat (limited to 'src/shader_recompiler')
-rw-r--r--src/shader_recompiler/frontend/ampere/lower_to_maxwell.h16
1 files changed, 10 insertions, 6 deletions
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<const Instruction> 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<u32>(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) |