All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alexandre Courbot" <acourbot@nvidia.com>
To: "Daniel Almeida" <daniel.almeida@collabora.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" <benno.lossin@proton.me>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>
Cc: <linux-kernel@vger.kernel.org>, <rust-for-linux@vger.kernel.org>,
	"Fiona Behrens" <me@kloenk.dev>
Subject: Re: [PATCH v5] rust: kernel: add support for bits/genmask macros
Date: Thu, 22 May 2025 12:17:26 +0900	[thread overview]
Message-ID: <DA2D41UHSQTB.2P6FHWB6TBVO7@nvidia.com> (raw)
In-Reply-To: <20250326-topic-panthor-rs-genmask-v5-1-bfa6140214da@collabora.com>

On Wed Mar 26, 2025 at 11:06 PM JST, Daniel Almeida wrote:
<snip>
> diff --git a/rust/kernel/bits.rs b/rust/kernel/bits.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..ddae8a5be4698bb7df66ee2c42ac6c2bc07eae7e
> --- /dev/null
> +++ b/rust/kernel/bits.rs
> @@ -0,0 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Bit manipulation macros.
> +//!
> +//! C header: [`include/linux/bits.h`](srctree/include/linux/bits.h)
> +
> +/// Produces a literal where bit `n` is set.
> +///
> +/// Equivalent to the kernel's `BIT` macro.

The compiler is probably smart enough to figure that out, but shall we
make all these functions `#[inline(always)]`?

Also, how about adding a few examples for `bit_*` in their respective
doc comment, similarly to `genmask_*`?

> +pub const fn bit_u64(n: u32) -> u64 {
> +    1u64 << n as u64

The `n as u64` cast seems unneeded (and in other functions as well).

> +}
> +
> +/// Produces a literal where bit `n` is set.
> +///
> +/// Equivalent to the kernel's `BIT` macro.
> +pub const fn bit_u32(n: u32) -> u32 {
> +    1u32 << n
> +}
> +
> +/// Produces a literal where bit `n` is set.
> +///
> +/// Equivalent to the kernel's `BIT` macro.
> +pub const fn bit_u16(n: u32) -> u16 {
> +    1u16 << n as u16
> +}
> +
> +/// Produces a literal where bit `n` is set.
> +///
> +/// Equivalent to the kernel's `BIT` macro.
> +pub const fn bit_u8(n: u32) -> u8 {
> +    1u8 << n as u8
> +}

Doing `bit_u8(foo)` if `foo >=8` (and the compiler cannot determine this
at build-time) will overflow and possibly panic. This should be
documented at the very least, but the best would be to avoid that
entirely.

Maybe we could have several variants:

	  // Returns `None` if `n` is out of bounds.
	  pub fn checked_bit_u32(n: u32) -> Option<u32> {
			  1u32.checked_shl(n)
		}

		// Returns `0` if `n` is out of bounds.
		pub fn unbounded_bit_u32(n: u32) -> u32 {
			  // Cannot use `unwrap_or` as it is not const.
			  match checked_bit_u32(n) {
					  Some(v) => v,
					  None => 0,
				}
		}

		// Compile-time error if `n` is out of bounds.
		pub const fn bit_u32(n: u32) -> u32 {
        // Only accept values known at compile-time.
			  static_assert!(n < u32::BITS);
			  1u32 << n
		}

All versions are guaranteed to never panic, and can come in handy depending on
context. The preferred one being `bit_u32` with a constant value, but if the
bit index is not known until runtime then users can use one of the other
variants depending on whether they want to validate the input.

I know that's a lot more functions, but the standard library does that
with e.g. `checked_add`, `overflowing_add`, etc. So it is definitely an
accepted pattern.

> +
> +/// Create a contiguous bitmask starting at bit position `l` and ending at
> +/// position `h`, where `h >= l`.
> +///
> +/// # Examples
> +/// ```
> +///     use kernel::bits::genmask_u64;
> +///     let mask = genmask_u64(39, 21);
> +///     assert_eq!(mask, 0x000000ffffe00000);
> +/// ```
> +///
> +pub const fn genmask_u64(h: u32, l: u32) -> u64 {

Would it make sense to take a range as argument here? This would invert
`h` and `l`, but carries the intent better imho, e.g.

    let mask = genmask_u64(8..15);

Makes it pretty clear that bits 8 to 15 will constitute the mask.

> +    assert!(h >= l);

Do we want to use asserts here? This adds a path for the kernel to panic in a
very common function, and it looks like we are trying to avoid such panics when
they are preventable:

https://lore.kernel.org/rust-for-linux/aBJPwKeJy1ixtwg2@pollux/

If `h > l` then this function returns 0 - I wonder if we cannot just accept
that this is a valid input.

One thing to consider also is how to behave when `h` or `l` is larger than the
number of bits in the type. The current version overflows, so maybe we need to
introduce several variants here as well.

> +    (!0u64 - (1u64 << l) + 1) & (!0u64 >> (64 - 1 - h))

Nit: using `u64::MAX` might be more idiomatic than `!0u64`.

Instead of doing `(1u64 << l)`, let's leverage one of the `bit_u64`
methods since they are available.

`(64 - 1 - h)` can also be `(u64::BITS - 1 - h)`. Here as well, beware
of underflows.


  parent reply	other threads:[~2025-05-22  3:17 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-26 14:06 [PATCH v5] rust: kernel: add support for bits/genmask macros Daniel Almeida
2025-03-27 21:27 ` Miguel Ojeda
2025-05-13 18:52   ` Daniel Almeida
2025-05-19 17:57     ` Miguel Ojeda
2025-05-22  5:01     ` Alexandre Courbot
2025-05-21  7:53 ` Alexandre Courbot
2025-05-22  3:17 ` Alexandre Courbot [this message]
2025-05-22  8:21   ` Miguel Ojeda
2025-05-22  8:23     ` Alexandre Courbot
2025-05-22  8:37       ` Miguel Ojeda

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=DA2D41UHSQTB.2P6FHWB6TBVO7@nvidia.com \
    --to=acourbot@nvidia.com \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=gary@garyguo.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=me@kloenk.dev \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.