diff mbox series

[v4,2/2] linux/bits.h: simplify GENMASK_INPUT_CHECK()

Message ID 20241113172939.747686-6-mailhol.vincent@wanadoo.fr (mailing list archive)
State New
Headers show
Series add const_true() to simplify GENMASK_INPUT_CHECK() | expand

Commit Message

Vincent Mailhol Nov. 13, 2024, 5:18 p.m. UTC
In GENMASK_INPUT_CHECK(),

  __builtin_choose_expr(__is_constexpr((l) > (h)), (l) > (h), 0)

is the exact expansion of:

  const_true((l) > (h))

Apply const_true() to simplify GENMASK_INPUT_CHECK().

Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
---
This change passes the unit tests from CONFIG_BITS_TEST, including the
extra negative tests provided under #ifdef TEST_GENMASK_FAILURES [1].

[1] commit 6d511020e13d ("lib/test_bits.c: add tests of GENMASK")
Link: https://git.kernel.org/torvalds/c/6d511020e13d
---
 include/linux/bits.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

Comments

David Laight Nov. 17, 2024, 5:24 p.m. UTC | #1
From: Vincent Mailhol
> Sent: 13 November 2024 17:19
> 
> In GENMASK_INPUT_CHECK(),
> 
>   __builtin_choose_expr(__is_constexpr((l) > (h)), (l) > (h), 0)
> 
> is the exact expansion of:
> 
>   const_true((l) > (h))
> 
> Apply const_true() to simplify GENMASK_INPUT_CHECK().

Wouldn't statically_true() give better coverage ?
I wouldn't have though that GENMASK() got used anywhere where a constant
integer expression was needed.

More interesting would be to get it to pass a W=1 build for
any place where 'l' is 0u.

	David

> 
> Signed-off-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr>
> ---
> This change passes the unit tests from CONFIG_BITS_TEST, including the
> extra negative tests provided under #ifdef TEST_GENMASK_FAILURES [1].
> 
> [1] commit 6d511020e13d ("lib/test_bits.c: add tests of GENMASK")
> Link: https://git.kernel.org/torvalds/c/6d511020e13d
> ---
>  include/linux/bits.h | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/bits.h b/include/linux/bits.h
> index 60044b608817..61a75d3f294b 100644
> --- a/include/linux/bits.h
> +++ b/include/linux/bits.h
> @@ -20,9 +20,8 @@
>   */
>  #if !defined(__ASSEMBLY__)
>  #include <linux/build_bug.h>
> -#define GENMASK_INPUT_CHECK(h, l) \
> -	(BUILD_BUG_ON_ZERO(__builtin_choose_expr( \
> -		__is_constexpr((l) > (h)), (l) > (h), 0)))
> +#include <linux/compiler.h>
> +#define GENMASK_INPUT_CHECK(h, l) BUILD_BUG_ON_ZERO(const_true((l) > (h)))
>  #else
>  /*
>   * BUILD_BUG_ON_ZERO is not available in h files included from asm files,
> --
> 2.45.2
> 

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
David Laight Nov. 17, 2024, 7:45 p.m. UTC | #2
From: David Laight
> Sent: 17 November 2024 17:25
> 
> From: Vincent Mailhol
> > Sent: 13 November 2024 17:19
> >
> > In GENMASK_INPUT_CHECK(),
> >
> >   __builtin_choose_expr(__is_constexpr((l) > (h)), (l) > (h), 0)
> >
> > is the exact expansion of:
> >
> >   const_true((l) > (h))
> >
> > Apply const_true() to simplify GENMASK_INPUT_CHECK().
> 
> Wouldn't statically_true() give better coverage ?
> I wouldn't have though that GENMASK() got used anywhere where a constant
> integer expression was needed.

If it is, maybe add a GENMASK_CONST() that uses BUILD_BUG_ON_ZERO_MSG()
(recently proposed) and so validates that the values are constants.
And then use statically_true() in the normal case to pick up more errors.

(Or just remove the check because coders really aren't that stupid!)

The interesting cases are the ones using variables.
And they'd need run-time checks of some form.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Vincent Mailhol Nov. 18, 2024, 1:12 a.m. UTC | #3
On Mon. 18 Nov. 2024 at 02:24, David Laight <David.Laight@aculab.com> wrote:
> From: Vincent Mailhol
> > Sent: 13 November 2024 17:19
> >
> > In GENMASK_INPUT_CHECK(),
> >
> >   __builtin_choose_expr(__is_constexpr((l) > (h)), (l) > (h), 0)
> >
> > is the exact expansion of:
> >
> >   const_true((l) > (h))
> >
> > Apply const_true() to simplify GENMASK_INPUT_CHECK().
>
> Wouldn't statically_true() give better coverage ?
> I wouldn't have though that GENMASK() got used anywhere where a constant
> integer expression was needed.
>
> More interesting would be to get it to pass a W=1 build for
> any place where 'l' is 0u.

Are you referring to -Wtype-limits? If yes, this warning was moved to
W=2. I suggested in the past to add a cast to silence this warning,
but got rejected:

  https://lore.kernel.org/lkml/CAHk-=whvGWbpsTa538CvQ9e=VF+m8WPQmES2y6-=0=-64uGkgg@mail.gmail.com/

Yours sincerely,
Vincent Mailhol
Vincent Mailhol Nov. 18, 2024, 1:14 a.m. UTC | #4
On Mon. 18 Nov. 2024 at 04:45, David Laight <David.Laight@aculab.com> wrote:
> From: David Laight
> > Sent: 17 November 2024 17:25
> >
> > From: Vincent Mailhol
> > > Sent: 13 November 2024 17:19
> > >
> > > In GENMASK_INPUT_CHECK(),
> > >
> > >   __builtin_choose_expr(__is_constexpr((l) > (h)), (l) > (h), 0)
> > >
> > > is the exact expansion of:
> > >
> > >   const_true((l) > (h))
> > >
> > > Apply const_true() to simplify GENMASK_INPUT_CHECK().
> >
> > Wouldn't statically_true() give better coverage ?

Yes, it would.

> > I wouldn't have though that GENMASK() got used anywhere where a constant
> > integer expression was needed.

It is used in many places, including some inline functions such as bitmap_set():

  https://elixir.bootlin.com/linux/v6.11/source/include/linux/bitmap.h#L469

where the input is not an integer constant expression (thus preventing
the use of statically_true()).

> If it is, maybe add a GENMASK_CONST() that uses BUILD_BUG_ON_ZERO_MSG()
> (recently proposed) and so validates that the values are constants.
> And then use statically_true() in the normal case to pick up more errors.

The issue if you introduce GENMASK_CONST() is that there is no gain.

The only advantage of const_true(x) is that it works on cases where
statically_true(x) would cause a compilation error. But for
statically_true(x) to cause a compilation error, x has to be a non
constant expression. And if x is non constant, then const_true(x)
returns false.

Regardless, considering the number of times where GENMASK() is used
with integer literals, I do not think it would be worth it to replace
all of these with GENMASK_CONST() tree wide.

Trying to go in your direction, we already have two genmasks:

   - GENMASK(): which uses GENMASK_INPUT_CHECK()

  - __GENMASK(): no check, used in uapi

What would make more sense to me would be to:

  1. replace const_true() by statically_true() in GENMASK_INPUT_CHECK()

  2. replace all the instances where GENMASK() breaks compilation with
     __GENMASK()

But this idea was already proposed in the past and was rejected here:

  https://lore.kernel.org/lkml/YJm5Dpo+RspbAtye@rikard/

> (Or just remove the check because coders really aren't that stupid!)

I think that this check exists in the first place *because* such a
mistake was made in the past.

> The interesting cases are the ones using variables.
> And they'd need run-time checks of some form.

Then, instead of introducing GENMASK_CONST(), maybe introduce
GENMASK_NON_CONST()? But then, the number of instances in which
GENMASK() is used with something other than literal integers is pretty
rare. So probably not worth it.


Yours sincerely,
Vincent Mailhol
diff mbox series

Patch

diff --git a/include/linux/bits.h b/include/linux/bits.h
index 60044b608817..61a75d3f294b 100644
--- a/include/linux/bits.h
+++ b/include/linux/bits.h
@@ -20,9 +20,8 @@ 
  */
 #if !defined(__ASSEMBLY__)
 #include <linux/build_bug.h>
-#define GENMASK_INPUT_CHECK(h, l) \
-	(BUILD_BUG_ON_ZERO(__builtin_choose_expr( \
-		__is_constexpr((l) > (h)), (l) > (h), 0)))
+#include <linux/compiler.h>
+#define GENMASK_INPUT_CHECK(h, l) BUILD_BUG_ON_ZERO(const_true((l) > (h)))
 #else
 /*
  * BUILD_BUG_ON_ZERO is not available in h files included from asm files,