nir: Fix mod analysis of ishl to shift the recursive result

When considering ((x << y) % divisor), we recursed to calculate
mod = (x % (divisor << y)) but incorrectly returned mod directly,
rather than the correct value, (mod << y).

(Note that we require divisor to be a power-of-two.)

As an example of this going wrong, (x << 1) % 4 was returning (x % 2)
which is 0 or 1, but x << 1 is 2x, which is always an even number so
the result mod 4 can only be 0 or 2.

Unit test suggested by Caio Oliveira during review.

Fixes: 2255375c4d ("nir: add nir_mod_analysis & its tests")
Reviewed-by: Caio Oliveira <caio.oliveira@intel.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38918>
This commit is contained in:
Kenneth Graunke 2025-12-08 18:13:39 -08:00 committed by Marge Bot
parent 2b700f6bfd
commit 97857d3224
2 changed files with 22 additions and 1 deletions

View file

@ -132,7 +132,11 @@ nir_mod_analysis(nir_scalar val, nir_alu_type val_type, unsigned div, unsigned *
return true;
}
nir_alu_type type0 = nir_alu_src_type(alu, 0);
return nir_mod_analysis(nir_alu_arg(alu, 0, val.comp), type0, div >> shift, mod);
if (!nir_mod_analysis(nir_alu_arg(alu, 0, val.comp), type0, div >> shift, mod))
return false;
*mod <<= shift;
return true;
}
break;
}

View file

@ -331,3 +331,20 @@ TEST_F(nir_mod_analysis_test, const_shr_const_overflow)
}
}
}
TEST_F(nir_mod_analysis_test, const_shl_const)
{
/* (const << const) % const_mod should always be known */
for (unsigned const_mod = 1; const_mod <= 1024; const_mod *= 2) {
for (unsigned i = 0; i < 50; ++i) {
for (unsigned j = 0; j < 6; ++j) {
nir_def *shl = nir_ishl(b, v[i], v[j]);
unsigned mod = INT32_MAX;
EXPECT_TRUE(nir_mod_analysis_comp0(shl, nir_type_uint, const_mod, &mod));
EXPECT_EQ(mod, (i << j) % const_mod);
}
}
}
}