From 0ab87c47ed185c444220e81a3e0638fd5e419da6 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Sun, 29 Mar 2026 23:58:47 -0700 Subject: [PATCH 1/3] Fix TypeInferenceMapper.map_floor_div with integral dtypes. --- loopy/type_inference.py | 35 +++++++++++++++++++++++++++++++++++ test/test_loopy.py | 14 ++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/loopy/type_inference.py b/loopy/type_inference.py index 258717472..208d48e78 100644 --- a/loopy/type_inference.py +++ b/loopy/type_inference.py @@ -429,6 +429,41 @@ def map_quotient(self, expr: p.Quotient): else: return self.combine([n_dtype_set, d_dtype_set]) + def _map_int_div_modulo(self, expr: p.FloorDiv | p.Remainder): + n_dtype_set = self.rec(expr.numerator) + d_dtype_set = self.rec(expr.denominator) + + if not (n_dtype_set and d_dtype_set): + return cast("list[NumpyType]", []) + + n_dtype = cast("NumpyType", n_dtype_set[0]).dtype + d_dtype = cast("NumpyType", d_dtype_set[0]).dtype + num = ( + np.empty(0, dtype=n_dtype) + if not is_integer(expr.numerator) + else expr.numerator + ) + denom = ( + np.empty(0, dtype=d_dtype) + if not is_integer(expr.denominator) + else expr.denominator + ) + if is_integer(num) and is_integer(denom): + return self.rec(num // denom) + + floor_div_np = num // denom + assert isinstance(floor_div_np, np.ndarray) + + return [NumpyType(floor_div_np.dtype)] + + @override + def map_floor_div(self, expr: p.FloorDiv): + return self._map_int_div_modulo(expr) + + @override + def map_remainder(self, expr: p.Remainder): + return self._map_int_div_modulo(expr) + @override def map_constant(self, expr: object): if isinstance(expr, np.generic): diff --git a/test/test_loopy.py b/test/test_loopy.py index 8badf6016..2f3995d55 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -3733,6 +3733,20 @@ def test_type_cast_parse_stringify_roundtrip(): assert expr == parsed +def test_floor_div_modulo_with_uint_index(): + # See + knl = lp.make_kernel( + "{[i]: 0<=i<10}", + "a[map[i] // 2, map[i] % 35] = i", + [ + lp.GlobalArg("map", dtype=np.uint64, shape=lp.auto), + lp.GlobalArg("a", dtype=np.float64, shape=(10, 4)), + ], + ) + # check the codegen is successful + lp.generate_code_v2(knl).device_code() + + if __name__ == "__main__": import sys if len(sys.argv) > 1: From 3cdca1439d3edba4cb5f7058e0ebcffc1bdcda46 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Tue, 31 Mar 2026 10:09:46 -0700 Subject: [PATCH 2/3] Avoid div by 0 in TypeInferenceMapper.map_floor_div --- loopy/type_inference.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/loopy/type_inference.py b/loopy/type_inference.py index 208d48e78..d826bb514 100644 --- a/loopy/type_inference.py +++ b/loopy/type_inference.py @@ -448,6 +448,10 @@ def _map_int_div_modulo(self, expr: p.FloorDiv | p.Remainder): if not is_integer(expr.denominator) else expr.denominator ) + denom = ( + denom + 1 if is_integer(denom) and denom == 0 else denom + ) # avoid divide by zero. + if is_integer(num) and is_integer(denom): return self.rec(num // denom) From 3b71b0c6d7683de6150d7768aadb94ee4d8ed8a7 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Tue, 31 Mar 2026 10:15:36 -0700 Subject: [PATCH 3/3] basedpyright: add a cast. --- loopy/type_inference.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/loopy/type_inference.py b/loopy/type_inference.py index d826bb514..f1d17230a 100644 --- a/loopy/type_inference.py +++ b/loopy/type_inference.py @@ -449,7 +449,9 @@ def _map_int_div_modulo(self, expr: p.FloorDiv | p.Remainder): else expr.denominator ) denom = ( - denom + 1 if is_integer(denom) and denom == 0 else denom + cast("int | np.integer", denom + 1) + if is_integer(denom) and denom == 0 + else denom ) # avoid divide by zero. if is_integer(num) and is_integer(denom):