Messages in this thread | | | Date | Wed, 21 Jun 2023 23:15:51 -0700 | From | Lucas De Marchi <> | Subject | Re: [PATCH 2/3] linux/bits.h: Add fixed-width GENMASK and BIT macros |
| |
On Wed, Jun 21, 2023 at 07:20:59PM -0700, Yury Norov wrote: >Hi Lucas, all! > >(Thanks, Andy, for pointing to this thread.) > >On Mon, May 08, 2023 at 10:14:02PM -0700, Lucas De Marchi wrote: >> Add GENMASK_U32(), GENMASK_U16() and GENMASK_U8() macros to create >> masks for fixed-width types and also the corresponding BIT_U32(), >> BIT_U16() and BIT_U8(). > >Can you split BIT() and GENMASK() material to separate patches? > >> All of those depend on a new "U" suffix added to the integer constant. >> Due to naming clashes it's better to call the macro U32. Since C doesn't >> have a proper suffix for short and char types, the U16 and U18 variants >> just use U32 with one additional check in the BIT_* macros to make >> sure the compiler gives an error when the those types overflow. > >I feel like I don't understand the sentence...
maybe it was a digression of the integer constants
> >> The BIT_U16() and BIT_U8() need the help of GENMASK_INPUT_CHECK(), >> as otherwise they would allow an invalid bit to be passed. Hence >> implement them in include/linux/bits.h rather than together with >> the other BIT* variants. > >I don't think it's a good way to go because BIT() belongs to a more basic >level than GENMASK(). Not mentioning possible header dependency issues. >If you need to test against tighter numeric region, I'd suggest to >do the same trick as GENMASK_INPUT_CHECK() does, but in uapi/linux/const.h >directly. Something like: > #define _U8(x) (CONST_GT(U8_MAX, x) + _AC(x, U)) > >> The following test file is is used to test this: >> >> $ cat mask.c >> #include <linux/types.h> >> #include <linux/bits.h> >> >> static const u32 a = GENMASK_U32(31, 0); >> static const u16 b = GENMASK_U16(15, 0); >> static const u8 c = GENMASK_U8(7, 0); >> static const u32 x = BIT_U32(31); >> static const u16 y = BIT_U16(15); >> static const u8 z = BIT_U8(7); >> >> #if FAIL >> static const u32 a2 = GENMASK_U32(32, 0); >> static const u16 b2 = GENMASK_U16(16, 0); >> static const u8 c2 = GENMASK_U8(8, 0); >> static const u32 x2 = BIT_U32(32); >> static const u16 y2 = BIT_U16(16); >> static const u8 z2 = BIT_U8(8); >> #endif >> >> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com> >> --- >> include/linux/bits.h | 22 ++++++++++++++++++++++ >> include/uapi/linux/const.h | 2 ++ >> include/vdso/const.h | 1 + >> 3 files changed, 25 insertions(+) >> >> diff --git a/include/linux/bits.h b/include/linux/bits.h >> index 7c0cf5031abe..ff4786c99b8c 100644 >> --- a/include/linux/bits.h >> +++ b/include/linux/bits.h >> @@ -42,4 +42,26 @@ >> #define GENMASK_ULL(h, l) \ >> (GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l)) >> >> +#define __GENMASK_U32(h, l) \ >> + (((~U32(0)) - (U32(1) << (l)) + 1) & \ >> + (~U32(0) >> (32 - 1 - (h)))) >> +#define GENMASK_U32(h, l) \ >> + (GENMASK_INPUT_CHECK(h, l) + __GENMASK_U32(h, l)) >> + >> +#define __GENMASK_U16(h, l) \ >> + ((U32(0xffff) - (U32(1) << (l)) + 1) & \ >> + (U32(0xffff) >> (16 - 1 - (h)))) >> +#define GENMASK_U16(h, l) \ >> + (GENMASK_INPUT_CHECK(h, l) + __GENMASK_U16(h, l)) >> + >> +#define __GENMASK_U8(h, l) \ >> + (((U32(0xff)) - (U32(1) << (l)) + 1) & \ >> + (U32(0xff) >> (8 - 1 - (h)))) >> +#define GENMASK_U8(h, l) \ >> + (GENMASK_INPUT_CHECK(h, l) + __GENMASK_U8(h, l)) > >[...] > >I see nothing wrong with fixed-wight versions of GENMASK if it helps >people to write safer code. Can you please in commit message mention >the exact patch(es) that added a bug related to GENMASK() misuse? It >would be easier to advocate the purpose of new API with that in mind. > >Regarding implementation - we should avoid copy-pasting in cases >like this. Below is the patch that I boot-tested for x86_64 and >compile-tested for arm64. > >It looks less opencoded, and maybe Andy will be less skeptical about >this approach because of less maintenance burden. Please take it if >you like for v2. > >Thanks, >Yury > >From 39c5b35075df67e7d88644470ca78a3486367c02 Mon Sep 17 00:00:00 2001 >From: Yury Norov <yury.norov@gmail.com> >Date: Wed, 21 Jun 2023 15:27:29 -0700 >Subject: [PATCH] bits: introduce fixed-type genmasks > >Generalize __GENMASK() to support different types, and implement >fixed-types versions of GENMASK() based on it. > >Signed-off-by: Yury Norov <yury.norov@gmail.com> >--- > include/linux/bitops.h | 1 - > include/linux/bits.h | 22 ++++++++++++---------- > 2 files changed, 12 insertions(+), 11 deletions(-) > >diff --git a/include/linux/bitops.h b/include/linux/bitops.h >index 2ba557e067fe..1db50c69cfdb 100644 >--- a/include/linux/bitops.h >+++ b/include/linux/bitops.h >@@ -15,7 +15,6 @@ > # define aligned_byte_mask(n) (~0xffUL << (BITS_PER_LONG - 8 - 8*(n))) > #endif > >-#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) > #define BITS_TO_LONGS(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(long)) > #define BITS_TO_U64(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u64)) > #define BITS_TO_U32(nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u32)) >diff --git a/include/linux/bits.h b/include/linux/bits.h >index 7c0cf5031abe..cb94128171b2 100644 >--- a/include/linux/bits.h >+++ b/include/linux/bits.h >@@ -6,6 +6,8 @@ > #include <vdso/bits.h> > #include <asm/bitsperlong.h> > >+#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE) >+ > #define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG)) > #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) > #define BIT_ULL_MASK(nr) (ULL(1) << ((nr) % BITS_PER_LONG_LONG)) >@@ -30,16 +32,16 @@ > #define GENMASK_INPUT_CHECK(h, l) 0 > #endif > >-#define __GENMASK(h, l) \ >- (((~UL(0)) - (UL(1) << (l)) + 1) & \ >- (~UL(0) >> (BITS_PER_LONG - 1 - (h)))) >-#define GENMASK(h, l) \ >- (GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l)) >+#define __GENMASK(t, h, l) \ >+ (GENMASK_INPUT_CHECK(h, l) + \ >+ (((t)~0ULL - ((t)(1) << (l)) + 1) & \ >+ ((t)~0ULL >> (BITS_PER_TYPE(t) - 1 - (h)))))
yeah... forcing the use of ull and then casting to the type is simpler and does the job. Checked that it does not break the build if h is greater than the type and it works
../include/linux/bits.h:40:20: error: right shift count >= width of type [-Werror=shift-count-overflow] 40 | ((t)~0ULL >> (BITS_PER_TYPE(t) - 1 - (h))))) | ^~
However this new version does increase the size. Using i915 module to test:
$ size build64/drivers/gpu/drm/i915/i915.ko* text data bss dec hex filename 4355676 213473 7048 4576197 45d3c5 build64/drivers/gpu/drm/i915/i915.ko 4361052 213505 7048 4581605 45e8e5 build64/drivers/gpu/drm/i915/i915.ko.new
Lucas De Marchi
> >-#define __GENMASK_ULL(h, l) \ >- (((~ULL(0)) - (ULL(1) << (l)) + 1) & \ >- (~ULL(0) >> (BITS_PER_LONG_LONG - 1 - (h)))) >-#define GENMASK_ULL(h, l) \ >- (GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l)) >+#define GENMASK(h, l) __GENMASK(unsigned long, h, l) >+#define GENMASK_ULL(h, l) __GENMASK(unsigned long long, h, l) >+#define GENMASK_U8(h, l) __GENMASK(u8, h, l) >+#define GENMASK_U16(h, l) __GENMASK(u16, h, l) >+#define GENMASK_U32(h, l) __GENMASK(u32, h, l) >+#define GENMASK_U64(h, l) __GENMASK(u64, h, l) > > #endif /* __LINUX_BITS_H */ >-- >2.39.2 >
| |