Search Linux Wireless

Re: [PATCH] bitfield: add FIELD_PREP_CONST()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Johannes Berg <johannes@xxxxxxxxxxxxxxxx>
Date: Wed, 18 Jan 2023 14:26:53 +0100

> From: Johannes Berg <johannes.berg@xxxxxxxxx>
> 
> Neither FIELD_PREP() nor *_encode_bits() can be used
> in constant contexts (such as initializers), but we
> don't want to define shift constants for all masks
> just for use in initializers, and having checks that
> the values fit is also useful.
> 
> Therefore, add FIELD_PREP_CONST() which is a smaller
> version of FIELD_PREP() that can only take constant
> arguments and has less friendly (but not less strict)
> error checks, and expands to a constant value.
> 
> Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx>
> ---
>  include/linux/bitfield.h | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
> index c9be1657f03d..ebfa12f69501 100644
> --- a/include/linux/bitfield.h
> +++ b/include/linux/bitfield.h
> @@ -115,6 +115,32 @@
>  		((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask);	\
>  	})
>  
> +#define __BF_CHECK_POW2(n)	BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0)
> +
> +/**
> + * FIELD_PREP_CONST() - prepare a constant bitfield element
> + * @_mask: shifted mask defining the field's length and position
> + * @_val:  value to put in the field
> + *
> + * FIELD_PREP_CONST() masks and shifts up the value.  The result should
> + * be combined with other fields of the bitfield using logical OR.
> + *
> + * Unlike FIELD_PREP() this is a constant expression and can therefore
> + * be used in initializers. Error checking is less comfortable for this
> + * version, and non-constant masks cannot be used.
> + */
> +#define FIELD_PREP_CONST(_mask, _val)					\

Have you tried combining it with FIELD_PREP() using
__builtin_choose_expr() + __builtin_is_constexpr() (or
__builtin_constant_p() depending on which will satisfy the compiler)?
I'm not saying it's 100% possible, but worth trying.

> +	(								\
> +		/* mask must be non-zero */				\
> +		BUILD_BUG_ON_ZERO((_mask) == 0) +			\
> +		/* check if value fits */				\
> +		BUILD_BUG_ON_ZERO(~((_mask) >> __bf_shf(_mask)) & (_val)) + \
> +		/* check if mask is contiguous */			\
> +		__BF_CHECK_POW2((_mask) + (1ULL << __bf_shf(_mask))) +	\
> +		/* and create the value */				\
> +		(((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask))	\
> +	)
> +
>  /**
>   * FIELD_GET() - extract a bitfield element
>   * @_mask: shifted mask defining the field's length and position

Thanks,
Olek



[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux