[PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`

Alexandre Courbot posted 6 patches 2 weeks, 5 days ago
[PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`
Posted by Alexandre Courbot 2 weeks, 5 days ago
Shifting a `Bounded` left or right changes the number of bits required
to represent the value. Add methods that perform the shift and return a
`Bounded` with the appropriately adjusted bit width.

These methods are particularly useful for bitfield extraction.

Suggested-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
 rust/kernel/num/bounded.rs | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
index 5ef8361cf5d5..6e3f4a7a5262 100644
--- a/rust/kernel/num/bounded.rs
+++ b/rust/kernel/num/bounded.rs
@@ -475,6 +475,46 @@ pub fn cast<U>(self) -> Bounded<U, N>
         // `N` bits, and with the same signedness.
         unsafe { Bounded::__new(value) }
     }
+
+    /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N - SHIFT }>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use kernel::num::Bounded;
+    ///
+    /// let v = Bounded::<u32, 16>::new::<0xff00>();
+    /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>();
+    ///
+    /// assert_eq!(v_shifted.get(), 0xff);
+    /// ```
+    pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
+        const { assert!(RES == N - SHIFT) }
+
+        // SAFETY: we shift the value right by `SHIFT`, reducing the number of bits needed to
+        // represent the shifted value by as much, and just asserted that `RES == N - SHIFT`.
+        unsafe { Bounded::__new(self.0 >> SHIFT) }
+    }
+
+    /// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N + SHIFT }>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use kernel::num::Bounded;
+    ///
+    /// let v = Bounded::<u32, 8>::new::<0xff>();
+    /// let v_shifted: Bounded::<u32, 16> = v.shl::<8, _>();
+    ///
+    /// assert_eq!(v_shifted.get(), 0xff00);
+    /// ```
+    pub fn shl<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
+        const { assert!(RES == N + SHIFT) }
+
+        // SAFETY: we shift the value left by `SHIFT`, augmenting the number of bits needed to
+        // represent the shifted value by as much, and just asserted that `RES == N + SHIFT`.
+        unsafe { Bounded::__new(self.0 << SHIFT) }
+    }
 }
 
 impl<T, const N: u32> Deref for Bounded<T, N>

-- 
2.52.0
Re: [PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`
Posted by Yury Norov 2 weeks, 4 days ago
On Tue, Jan 20, 2026 at 03:17:54PM +0900, Alexandre Courbot wrote:
> Shifting a `Bounded` left or right changes the number of bits required
> to represent the value. Add methods that perform the shift and return a
> `Bounded` with the appropriately adjusted bit width.
> 
> These methods are particularly useful for bitfield extraction.
> 
> Suggested-by: Alice Ryhl <aliceryhl@google.com>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> ---
>  rust/kernel/num/bounded.rs | 40 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
> index 5ef8361cf5d5..6e3f4a7a5262 100644
> --- a/rust/kernel/num/bounded.rs
> +++ b/rust/kernel/num/bounded.rs
> @@ -475,6 +475,46 @@ pub fn cast<U>(self) -> Bounded<U, N>
>          // `N` bits, and with the same signedness.
>          unsafe { Bounded::__new(value) }
>      }
> +
> +    /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N - SHIFT }>`.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// use kernel::num::Bounded;
> +    ///
> +    /// let v = Bounded::<u32, 16>::new::<0xff00>();
> +    /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>();

This syntax is really confusing. Does it work for runtime shifts?
Is there any chance to make it just v.shr(8)?

> +    ///
> +    /// assert_eq!(v_shifted.get(), 0xff);
> +    /// ```
> +    pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
> +        const { assert!(RES == N - SHIFT) }
> +
> +        // SAFETY: we shift the value right by `SHIFT`, reducing the number of bits needed to
> +        // represent the shifted value by as much, and just asserted that `RES == N - SHIFT`.
> +        unsafe { Bounded::__new(self.0 >> SHIFT) }

Assuming you relax it to RES >= N - SHIFT, as suggested by Alice,
you'd also check for SHIFT < N.

> +    }
> +
> +    /// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N + SHIFT }>`.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// use kernel::num::Bounded;
> +    ///
> +    /// let v = Bounded::<u32, 8>::new::<0xff>();
> +    /// let v_shifted: Bounded::<u32, 16> = v.shl::<8, _>();
> +    ///
> +    /// assert_eq!(v_shifted.get(), 0xff00);
> +    /// ```
> +    pub fn shl<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
> +        const { assert!(RES == N + SHIFT) }
> +
> +        // SAFETY: we shift the value left by `SHIFT`, augmenting the number of bits needed to
> +        // represent the shifted value by as much, and just asserted that `RES == N + SHIFT`.
> +        unsafe { Bounded::__new(self.0 << SHIFT) }
> +    }

So, it protects most significant bits when shifting left, but doesn't
protect least significant bits when shifting right.

It also makes impossible to left-shift Bounded::<u32, 32> at all, or
shift Bounded::<u32, 31> for 2 or more bits. This doesn't look nice.

At this layer, there's seemingly nothing wrong to loose bits during
regular shift, just like non-bounded integers do. (Lets consider them
naturally bounded.) At higher layers, people may add any extra checks
as desired.

Even more, you mention you're going to use .shl and .shr for bitfield
extraction, which means you want to loose some bits intentionally.

Let's design shifts like this. Plain .shl() and .shr() will operate on
bounded integers just like '<<' and '>>' operate on non-bounded ones,
i.e. they may loose bits and the result has the same bit capacity. (But
shifting over the capacity should be be forbidden as undef).

If I want to adjust the capacity, I just do it explicitly:

    let x = Bounded::<u32, 12>::new::<0x123>();
    let a = x.shl(4); // 12-bit 0x230
    let b = x.extend::<12+4>().shl(4) // 16-bit 0x1230
    let c = x.shr(4); // 12-bit 0x012
    let d = if x & 0xf { None } else { x.shr(4).try_shrink::<12-4>() }

For b and d you can invent handy helpers, of course, and for a and c
you can add 'safe' versions that will check shifted-out parts for
emptiness at runtime, in case you need it.
Re: [PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`
Posted by Alice Ryhl 2 weeks, 4 days ago
On Wed, Jan 21, 2026 at 03:15:49AM -0500, Yury Norov wrote:
> On Tue, Jan 20, 2026 at 03:17:54PM +0900, Alexandre Courbot wrote:
> > Shifting a `Bounded` left or right changes the number of bits required
> > to represent the value. Add methods that perform the shift and return a
> > `Bounded` with the appropriately adjusted bit width.
> > 
> > These methods are particularly useful for bitfield extraction.
> > 
> > Suggested-by: Alice Ryhl <aliceryhl@google.com>
> > Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
> > ---
> >  rust/kernel/num/bounded.rs | 40 ++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 40 insertions(+)
> > 
> > diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
> > index 5ef8361cf5d5..6e3f4a7a5262 100644
> > --- a/rust/kernel/num/bounded.rs
> > +++ b/rust/kernel/num/bounded.rs
> > @@ -475,6 +475,46 @@ pub fn cast<U>(self) -> Bounded<U, N>
> >          // `N` bits, and with the same signedness.
> >          unsafe { Bounded::__new(value) }
> >      }
> > +
> > +    /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N - SHIFT }>`.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// use kernel::num::Bounded;
> > +    ///
> > +    /// let v = Bounded::<u32, 16>::new::<0xff00>();
> > +    /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>();
> 
> This syntax is really confusing. Does it work for runtime shifts?
> Is there any chance to make it just v.shr(8)?

The ::<NUM> syntax is how you pass a build-time constant value in Rust.
The syntax 'v.shr(8)' implies that 8 is a runtime value, and not a
build-time constant. I agree it's ugly, but that's how it is.

For runtime shifts, we can make it 'v.shr(8)' or even 'v >> 8' using
operator overloading, but see my further reply below:

> > +    }
> > +
> > +    /// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N + SHIFT }>`.
> > +    ///
> > +    /// # Examples
> > +    ///
> > +    /// ```
> > +    /// use kernel::num::Bounded;
> > +    ///
> > +    /// let v = Bounded::<u32, 8>::new::<0xff>();
> > +    /// let v_shifted: Bounded::<u32, 16> = v.shl::<8, _>();
> > +    ///
> > +    /// assert_eq!(v_shifted.get(), 0xff00);
> > +    /// ```
> > +    pub fn shl<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
> > +        const { assert!(RES == N + SHIFT) }
> > +
> > +        // SAFETY: we shift the value left by `SHIFT`, augmenting the number of bits needed to
> > +        // represent the shifted value by as much, and just asserted that `RES == N + SHIFT`.
> > +        unsafe { Bounded::__new(self.0 << SHIFT) }
> > +    }
> 
> So, it protects most significant bits when shifting left, but doesn't
> protect least significant bits when shifting right.
> 
> It also makes impossible to left-shift Bounded::<u32, 32> at all, or
> shift Bounded::<u32, 31> for 2 or more bits. This doesn't look nice.
> 
> At this layer, there's seemingly nothing wrong to loose bits during
> regular shift, just like non-bounded integers do. (Lets consider them
> naturally bounded.) At higher layers, people may add any extra checks
> as desired.
> 
> Even more, you mention you're going to use .shl and .shr for bitfield
> extraction, which means you want to loose some bits intentionally.
> 
> Let's design shifts like this. Plain .shl() and .shr() will operate on
> bounded integers just like '<<' and '>>' operate on non-bounded ones,
> i.e. they may loose bits and the result has the same bit capacity. (But
> shifting over the capacity should be be forbidden as undef).
> 
> If I want to adjust the capacity, I just do it explicitly:
> 
>     let x = Bounded::<u32, 12>::new::<0x123>();
>     let a = x.shl(4); // 12-bit 0x230
>     let b = x.extend::<12+4>().shl(4) // 16-bit 0x1230
>     let c = x.shr(4); // 12-bit 0x012
>     let d = if x & 0xf { None } else { x.shr(4).try_shrink::<12-4>() }
> 
> For b and d you can invent handy helpers, of course, and for a and c
> you can add 'safe' versions that will check shifted-out parts for
> emptiness at runtime, in case you need it. 

This 'shr' method came up from a discussion that Alexandre and I had at
plumbers. The entire point of them is that when you shift right by a
compile-time constant amount, you can change the bit capacity in the
type, and doing exactly that lets us remove BUILD_BUG_ON calls that Nova
has right now. (Right now Nova does a shift-right by a compile-time
constant, then uses BUILD_BUG_ON to assert that the resulting *runtime
value* has the desired target bit-capacity.)

So if we want a shift right method that doesn't change the bit-capacity,
we can do that. It can even use the ordinary '>>' operator. But the
purpose of this patch is precisely to support shifts that:

1. Shift by a compile-time constant amount.
2. Change the bit-capacity accordingly.

All that to say ... support for left-shifting Bounded::<u32, 32> and
similar certainly makes sense as something we could support, but that's
not what this patch is trying to achieve. Ultimately, the end-goal of
this patch is to allow us to get rid of BUILD_BUG_ON() calls operating
on runtime values, while still performing the same check that the
bit-capacity is as expected at build-time - just using types instead of
compiler optimizations to check it.

Alice
Re: [PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`
Posted by kernel test robot 2 weeks, 5 days ago
Hi Alexandre,

kernel test robot noticed the following build errors:

[auto build test ERROR on 2af6ad09fc7dfe9b3610100983cccf16998bf34d]

url:    https://github.com/intel-lab-lkp/linux/commits/Alexandre-Courbot/rust-num-add-shr-and-shl-methods-to-Bounded/20260120-143042
base:   2af6ad09fc7dfe9b3610100983cccf16998bf34d
patch link:    https://lore.kernel.org/r/20260120-register-v1-1-723a1743b557%40nvidia.com
patch subject: [PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260120/202601202328.hnTsogt9-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260120/202601202328.hnTsogt9-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601202328.hnTsogt9-lkp@intel.com/

All errors (new ones prefixed by >>):

>> error[E0658]: const arguments cannot yet be inferred with `_`
   --> rust/doctests_kernel_generated.rs:10572:47
   |
   10572 | let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>();
   |                                               ^
   |
   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
   = note: this compiler was built on 2025-06-23; consider upgrading it if it is out of date
--
>> error[E0658]: const arguments cannot yet be inferred with `_`
   --> rust/doctests_kernel_generated.rs:10630:48
   |
   10630 | let v_shifted: Bounded::<u32, 16> = v.shl::<8, _>();
   |                                                ^
   |
   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
   = note: this compiler was built on 2025-06-23; consider upgrading it if it is out of date

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`
Posted by Alice Ryhl 2 weeks, 5 days ago
On Tue, Jan 20, 2026 at 03:17:54PM +0900, Alexandre Courbot wrote:
> Shifting a `Bounded` left or right changes the number of bits required
> to represent the value. Add methods that perform the shift and return a
> `Bounded` with the appropriately adjusted bit width.
> 
> These methods are particularly useful for bitfield extraction.
> 
> Suggested-by: Alice Ryhl <aliceryhl@google.com>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>

Reviewed-by: Alice Ryhl <aliceryhl@google.com>

> +    /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N - SHIFT }>`.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// use kernel::num::Bounded;
> +    ///
> +    /// let v = Bounded::<u32, 16>::new::<0xff00>();
> +    /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>();
> +    ///
> +    /// assert_eq!(v_shifted.get(), 0xff);
> +    /// ```
> +    pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
> +        const { assert!(RES == N - SHIFT) }

In principle this could be

const { assert!(RES >= N - SHIFT) }

Alice
Re: [PATCH 1/6] rust: num: add `shr` and `shl` methods to `Bounded`
Posted by Alexandre Courbot 2 weeks, 5 days ago
On Tue Jan 20, 2026 at 5:44 PM JST, Alice Ryhl wrote:
> On Tue, Jan 20, 2026 at 03:17:54PM +0900, Alexandre Courbot wrote:
>> Shifting a `Bounded` left or right changes the number of bits required
>> to represent the value. Add methods that perform the shift and return a
>> `Bounded` with the appropriately adjusted bit width.
>> 
>> These methods are particularly useful for bitfield extraction.
>> 
>> Suggested-by: Alice Ryhl <aliceryhl@google.com>
>> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
>
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
>
>> +    /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, { N - SHIFT }>`.
>> +    ///
>> +    /// # Examples
>> +    ///
>> +    /// ```
>> +    /// use kernel::num::Bounded;
>> +    ///
>> +    /// let v = Bounded::<u32, 16>::new::<0xff00>();
>> +    /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>();
>> +    ///
>> +    /// assert_eq!(v_shifted.get(), 0xff);
>> +    /// ```
>> +    pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
>> +        const { assert!(RES == N - SHIFT) }
>
> In principle this could be
>
> const { assert!(RES >= N - SHIFT) }

Oh, that's right and that's also more flexible - thanks, will do that for v2.