public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Joel Fernandes <joelagnelf@nvidia.com>
To: Alexandre Courbot <acourbot@nvidia.com>
Cc: "Danilo Krummrich" <dakr@kernel.org>,
	"Yury Norov" <yury.norov@gmail.com>,
	"Jesung Yang" <y.j3ms.n@gmail.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	nouveau@lists.freedesktop.org, linux-kernel@vger.kernel.org,
	rust-for-linux@vger.kernel.org,
	Nouveau <nouveau-bounces@lists.freedesktop.org>
Subject: Re: [PATCH RFC v2 2/3] rust: kernel: add bounded integer types
Date: Fri, 10 Oct 2025 11:23:02 -0400	[thread overview]
Message-ID: <b53e554c-252d-4b21-a337-578c97c80dde@nvidia.com> (raw)
In-Reply-To: <DDEIH181JDA9.2DG2C3DBOB2V@nvidia.com>



On 10/10/2025 4:49 AM, Alexandre Courbot wrote:
> On Fri Oct 10, 2025 at 6:33 AM JST, Joel Fernandes wrote:
>> Hi Alex,
>>
>> Great effort, thanks. I replied with few comments below. Since the patch is
>> large, it would be great if could be possibly split. Maybe the From
>> primitives deserve a separate patch.
> 
> I'm all for smaller patches when it makes reviewing easier, but in this
> case all it would achieve is making the second patch append code right
> after the next. :) Is there a benefit in doing so?

I think there is a benefit, because reviewers don't have to scroll through huge
emails :). Plus separate commit messages would be added in too, to reason about
new code. There's other possible logical splits too, was just giving example but
I am Ok with it if you still want to keep it singular. :)

>>> +impl<const NUM_BITS: u32> Boundable<NUM_BITS> for u16 {
>>> +    const MASK: u16 = crate::bits::genmask_u16(0..=(NUM_BITS - 1));
>>> +}
>>> +
>>> +impl<const NUM_BITS: u32> Boundable<NUM_BITS> for u32 {
>>> +    const MASK: u32 = crate::bits::genmask_u32(0..=(NUM_BITS - 1));
>>> +}
>>> +
>>> +impl<const NUM_BITS: u32> Boundable<NUM_BITS> for u64 {
>>> +    const MASK: u64 = crate::bits::genmask_u64(0..=(NUM_BITS - 1));
>>> +}
>>> +
>>> +impl<T, const NUM_BITS: u32> BoundedInt<T, NUM_BITS>
>>> +where
>>> +    T: Boundable<NUM_BITS>,
>>> +{
>>> +    /// Checks that `value` is valid for this type at compile-time and build a new value.
>>> +    ///
>>> +    /// This relies on [`build_assert!`] to perform validation at compile-time. If `value` cannot
>>> +    /// be inferred to be in bounds at compile-time, use the fallible [`Self::try_new`] instead.
>>> +    ///
>>> +    /// When possible, use one of the `new_const` methods instead of this method as it statically
>>> +    /// validates `value` instead of relying on the compiler's optimizations.
>>
>> This sounds like, users might use the less-optimal API first with the same
>> build_assert issues we had with the IO accessors, since new() sounds very obvious.
>> How about the following naming?
>>
>> new::<VALUE>()        // Primary constructor for constants using const generics.
>> try_new(value)        // Keep as-is for fallible runtime
>> new_from_expr(value)  // For compile-time validated runtime values
>>
>> If new::<VALUE>() does not work for the user, the compiler will fail.
>>
>> Or, new_from_expr() could be from_value(), Ok with either naming or a better name.
> 
> Agreed, the preferred method should appear first. IIRC Alice also made a
> similar suggestion about v1 during the DRM sync, sorry for not picking
> it up.

Cool, sounds good.

[..]>>> +    /// Returns the contained value as a primitive type.
>>> +    ///
>>> +    /// # Examples
>>> +    ///
>>> +    /// ```
>>> +    /// use kernel::num::BoundedInt;
>>> +    ///
>>> +    /// let v = BoundedInt::<u32, 4>::new_const::<7>();
>>> +    /// assert_eq!(v.get(), 7u32);
>>> +    /// ```
>>> +    pub fn get(self) -> T {
>>> +        if !T::is_in_bounds(self.0) {
>>> +            // SAFETY: Per the invariants, `self.0` cannot have bits set outside of `MASK`, so
>>> +            // this block will
>>> +            // never be reached.
>>> +            unsafe { core::hint::unreachable_unchecked() }
>>> +        }
>>
>> Does this if block help the compiler generate better code? I wonder if code
>> gen could be checked to confirm the rationale.
> 
> Benno suggested that it would on a different patch:
> 
> https://lore.kernel.org/rust-for-linux/DBL1ZGZCSJF3.29HNS9BSN89C6@kernel.org/
> 
> OTOH as shown in patch 3/3, this doesn't exempt us from handling
> impossible values when using this in a match expression...

Interesting, TIL.

>>> +        self.0
>>> +    }
>>> +
>>> +    /// Increase the number of bits usable for `self`.
>>> +    ///
>>> +    /// This operation cannot fail.
>>> +    ///
>>> +    /// # Examples
>>> +    ///
>>> +    /// ```
>>> +    /// use kernel::num::BoundedInt;
>>> +    ///
>>> +    /// let v = BoundedInt::<u32, 4>::new_const::<7>();
>>> +    /// let larger_v = v.enlarge::<12>();
>>> +    /// // The contained values are equal even though `larger_v` has a bigger capacity.
>>> +    /// assert_eq!(larger_v, v);
>>> +    /// ```
>>> +    pub const fn enlarge<const NEW_NUM_BITS: u32>(self) -> BoundedInt<T, NEW_NUM_BITS>
>>> +    where
>>> +        T: Boundable<NEW_NUM_BITS>,
>>> +        T: Copy,
>>
>> Boundable already implies copy so T: Copy is redundant.
> 
> Thanks. I need to do a thorough review of all the contraints as I've
> changed them quite a bit as the implementation matured.

Cool. :)

>> [...]
>>> +impl_const_new!(u8 u16 u32 u64);
>>> +
>>> +/// Declares a new `$trait` and implements it for all bounded types represented using `$num_bits`.
>>> +///
>>> +/// This is used to declare properties as traits that we can use for later implementations.
>>> +macro_rules! impl_size_rule {
>>> +    ($trait:ident, $($num_bits:literal)*) => {
>>> +        trait $trait {}
>>> +
>>> +        $(
>>> +        impl<T> $trait for BoundedInt<T, $num_bits> where T: Boundable<$num_bits> {}
>>> +        )*
>>> +    };
>>> +}
>>> +
>>> +// Bounds that are larger than a `u64`.
>>> +impl_size_rule!(LargerThanU64, 64);
>>> +
>>> +// Bounds that are larger than a `u32`.
>>> +impl_size_rule!(LargerThanU32,
>>> +    32 33 34 35 36 37 38 39
>>
>> If num_bits == 32 (number of bits), how could BoundedInt<T, 32> a
>> LargerThanU32? It should be AtleastU32 or something.
>>
>> Or the above list should start from 33. Only a >= 33-bit wide integer can be
>> LargerThanU32.
> 
> The name is a bit ambiguous indeed. An accurate one would be
> `LargerOrEqualThanU32`, but `AtLeastU32` should also work.
Sure, I prefer AtLeastU32 since it is shorter :)

thanks,

 - Joel



  reply	other threads:[~2025-10-10 15:23 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-09 12:37 [RFC PATCH v2 0/3] rust: bounded integer types and use in register macro Alexandre Courbot
2025-10-09 12:37 ` [PATCH RFC v2 1/3] gpu: nova-core: register: use field type for Into implementation Alexandre Courbot
2025-10-09 15:17   ` Joel Fernandes
2025-10-09 15:41     ` Joel Fernandes
2025-10-10  8:24       ` Alexandre Courbot
2025-10-10  8:26         ` Alexandre Courbot
2025-10-10 14:59           ` Joel Fernandes
2025-10-09 20:10   ` Edwin Peer
2025-10-16 14:51   ` Joel Fernandes
2025-10-09 12:37 ` [PATCH RFC v2 2/3] rust: kernel: add bounded integer types Alexandre Courbot
2025-10-09 21:33   ` Joel Fernandes
2025-10-10  8:49     ` Alexandre Courbot
2025-10-10 15:23       ` Joel Fernandes [this message]
2025-10-11 10:33   ` Alice Ryhl
2025-10-09 12:37 ` [PATCH RFC v2 3/3] gpu: nova-core: use BoundedInt Alexandre Courbot
2025-10-09 16:40   ` Yury Norov
2025-10-09 17:18     ` Danilo Krummrich
2025-10-09 18:28       ` Yury Norov
2025-10-09 18:37         ` Joel Fernandes
2025-10-09 19:19         ` Miguel Ojeda
2025-10-09 19:34         ` Danilo Krummrich
2025-10-09 18:29     ` Joel Fernandes
2025-10-10  9:19     ` Alexandre Courbot
2025-10-10 17:20       ` Yury Norov
2025-10-10 17:58         ` Danilo Krummrich
2025-10-13 13:58         ` Joel Fernandes

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b53e554c-252d-4b21-a337-578c97c80dde@nvidia.com \
    --to=joelagnelf@nvidia.com \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=dakr@kernel.org \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=nouveau-bounces@lists.freedesktop.org \
    --cc=nouveau@lists.freedesktop.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    --cc=y.j3ms.n@gmail.com \
    --cc=yury.norov@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox