From 3e6fc923c585e3501cc14ca4f2dda529fecbb330 Mon Sep 17 00:00:00 2001 From: Jason Han Date: Tue, 17 Mar 2026 14:17:05 -0400 Subject: [PATCH 1/2] feat: added bits function to standardlib --- src/kirin/__init__.py | 11 +++- src/kirin/stdlib/__init__.py | 3 ++ src/kirin/stdlib/bits.py | 35 +++++++++++++ test/stdlib/test_bits.py | 99 ++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 src/kirin/stdlib/__init__.py create mode 100644 src/kirin/stdlib/bits.py create mode 100644 test/stdlib/test_bits.py diff --git a/src/kirin/__init__.py b/src/kirin/__init__.py index 57dc85bdff..ea2e4826a4 100644 --- a/src/kirin/__init__.py +++ b/src/kirin/__init__.py @@ -1,5 +1,12 @@ # re-exports the public API of the kirin package -from . import ir as ir, types as types, lowering as lowering +from . import ir as ir, types as types, stdlib as stdlib, lowering as lowering from .exception import enable_stracetrace, disable_stracetrace -__all__ = ["ir", "types", "lowering", "enable_stracetrace", "disable_stracetrace"] +__all__ = [ + "ir", + "types", + "stdlib", + "lowering", + "enable_stracetrace", + "disable_stracetrace", +] diff --git a/src/kirin/stdlib/__init__.py b/src/kirin/stdlib/__init__.py new file mode 100644 index 0000000000..2392f8387b --- /dev/null +++ b/src/kirin/stdlib/__init__.py @@ -0,0 +1,3 @@ +from . import bits as bits + +__all__ = ["bits"] diff --git a/src/kirin/stdlib/bits.py b/src/kirin/stdlib/bits.py new file mode 100644 index 0000000000..cdd8465c3d --- /dev/null +++ b/src/kirin/stdlib/bits.py @@ -0,0 +1,35 @@ +"""Bit-oriented helpers implemented as reusable Kirin kernels.""" + +from kirin.prelude import basic +from kirin.dialects import ilist + + +@basic +def _bit_length_rec(x: int, i: int) -> int: + y = x >> i + if y: + return _bit_length_rec(x, i + 1) + else: + return i + + +@basic +def bit_length(x: int) -> int: + """Return the number of bits required to represent ``x``.""" + x = abs(x) + if x == 0: + return 0 + return _bit_length_rec(x, 1) + + +@basic +def convert_bits(x: int, length: int): + """Return the low ``length`` bits of ``x`` in least-significant-bit order. Note that the return type puts the least-significant-bit in the earliest index.""" + + def _shift(i: int): + return (x >> i) & 1 + + return ilist.map(_shift, ilist.range(length)) + + +__all__ = ["bit_length", "convert_bits"] diff --git a/test/stdlib/test_bits.py b/test/stdlib/test_bits.py new file mode 100644 index 0000000000..a93f6542f0 --- /dev/null +++ b/test/stdlib/test_bits.py @@ -0,0 +1,99 @@ +from kirin.dialects import ilist +from kirin.stdlib.bits import bit_length, convert_bits + + +def test_bit_length_negative(): + assert bit_length(-13) == 4 + + +def test_bit_length_zero(): + assert bit_length(0) == 0 + + +def test_bit_length_positive(): + assert bit_length(7) == 3 + + +def test_bit_length_large(): + x = (1 << 80) + 12345 + assert bit_length(x) == x.bit_length() + + +def test_bit_length_large_power_of_two(): + x = 1 << 80 + assert bit_length(x) == 81 + + +def test_bit_length_small(): + assert bit_length(3) == 2 + + +def test_bit_length_small_single_bit(): + assert bit_length(1) == 1 + + +def test_convert_bits_length_greater_than_bit_length(): + out = convert_bits(5, 5) + assert isinstance(out, ilist.IList) + assert out.data == [1, 0, 1, 0, 0] + + +def test_convert_bits_length_equal_to_bit_length(): + out = convert_bits(5, 3) + assert isinstance(out, ilist.IList) + assert out.data == [1, 0, 1] + + +def test_convert_bits_length_less_than_bit_length(): + out = convert_bits(13, 2) + assert isinstance(out, ilist.IList) + assert out.data == [1, 0] + + +def test_convert_bits_negative_x(): + out = convert_bits(-1, 4) + assert isinstance(out, ilist.IList) + assert out.data == [1, 1, 1, 1] + + +def test_convert_bits_negative_length(): + out = convert_bits(5, -3) + assert isinstance(out, ilist.IList) + assert out.data == [] + + +def test_convert_bits_zero_x(): + out = convert_bits(0, 4) + assert isinstance(out, ilist.IList) + assert out.data == [0, 0, 0, 0] + + +def test_convert_bits_zero_length(): + out = convert_bits(7, 0) + assert isinstance(out, ilist.IList) + assert out.data == [] + + +def test_convert_bits_small_x(): + out = convert_bits(2, 3) + assert isinstance(out, ilist.IList) + assert out.data == [0, 1, 0] + + +def test_convert_bits_small_length(): + out = convert_bits(7, 1) + assert isinstance(out, ilist.IList) + assert out.data == [1] + + +def test_convert_bits_large_x(): + x = (1 << 12) + (1 << 5) + 1 + out = convert_bits(x, 13) + assert isinstance(out, ilist.IList) + assert out.data == [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1] + + +def test_convert_bits_large_length(): + out = convert_bits(3, 10) + assert isinstance(out, ilist.IList) + assert out.data == [1, 1, 0, 0, 0, 0, 0, 0, 0, 0] From 0bbacee9b6cfe6fa00d084fa5f010486fdc4905e Mon Sep 17 00:00:00 2001 From: Jason Han Date: Wed, 18 Mar 2026 14:08:26 -0400 Subject: [PATCH 2/2] removed __all__ statements --- src/kirin/__init__.py | 9 +-------- src/kirin/stdlib/__init__.py | 2 -- src/kirin/stdlib/bits.py | 3 --- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/kirin/__init__.py b/src/kirin/__init__.py index ea2e4826a4..bc01bee243 100644 --- a/src/kirin/__init__.py +++ b/src/kirin/__init__.py @@ -2,11 +2,4 @@ from . import ir as ir, types as types, stdlib as stdlib, lowering as lowering from .exception import enable_stracetrace, disable_stracetrace -__all__ = [ - "ir", - "types", - "stdlib", - "lowering", - "enable_stracetrace", - "disable_stracetrace", -] +__all__ = ["ir", "types", "lowering", "enable_stracetrace", "disable_stracetrace"] diff --git a/src/kirin/stdlib/__init__.py b/src/kirin/stdlib/__init__.py index 2392f8387b..e4505864f5 100644 --- a/src/kirin/stdlib/__init__.py +++ b/src/kirin/stdlib/__init__.py @@ -1,3 +1 @@ from . import bits as bits - -__all__ = ["bits"] diff --git a/src/kirin/stdlib/bits.py b/src/kirin/stdlib/bits.py index cdd8465c3d..69fc6634b5 100644 --- a/src/kirin/stdlib/bits.py +++ b/src/kirin/stdlib/bits.py @@ -30,6 +30,3 @@ def _shift(i: int): return (x >> i) & 1 return ilist.map(_shift, ilist.range(length)) - - -__all__ = ["bit_length", "convert_bits"]