From 47c56d122e33383564976d154a602a5c4047eb08 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sat, 20 Sep 2025 17:26:48 -0700 Subject: [PATCH] nasmlib: set of neat macros to create a useful bitfield enum When dealing with bitmasks/bitfields, definining them in macros tends to cause a lot of desirable constants out because it is a pain to create all of them. C macros can't create other macros, but they *can* be used to create fields in an enum, so provide some neat convenience macros for doing so. Signed-off-by: H. Peter Anvin (Intel) --- configure.ac | 1 + include/nasmlib.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/configure.ac b/configure.ac index dc3502d63..865c7edec 100644 --- a/configure.ac +++ b/configure.ac @@ -246,6 +246,7 @@ AC_CHECK_DECLS(strnlen) AC_CHECK_DECLS(strrchrnul) dnl Check for missing types +AC_TYPE_UINTMAX_T AC_TYPE_UINTPTR_T dnl Documentation: should we generate an uncompressed PDF? It is diff --git a/include/nasmlib.h b/include/nasmlib.h index e8777094e..703b9fb14 100644 --- a/include/nasmlib.h +++ b/include/nasmlib.h @@ -54,6 +54,59 @@ union intorptr { }; typedef union intorptr intorptr; +/* + * Handy macro to use as the base of shifts + */ +#define ONE ((uintmax_t)1) + +/* + * Handy macros for defining and accessing enums of bitfields; + * provides a set of standard-named parameters for each field. + * + * mk_field_mask() is indended to be used for non-contiguous fields. + */ + +#define mk_field_mask(name,pos,width,basemask) \ + name ## _POS = (pos), \ + name ## _WIDTH = (width), \ + name ## _BASEMASK = (basemask), \ + name ## _MASK = name ## _BASEMASK << name ## _POS, \ + name = name ## _MASK + +#define mk_field(name,pos,width) \ + mk_field_mask(name,pos,width, \ + (ONE << name ## _WIDTH)-1) + +/* + * Cast a value to a suitable type to represent the encoded + * (post-shift) and extracted (pre-shift) values, respectively. + */ +#ifdef HAVE_TYPEOF +# define fieldenc_cast(x,y) ((typeof(x ## _MASK))(y)) +# define fieldval_cast(x,y) ((typeof(x ## _BASEMASK))(y)) +#else +# define fieldenc_cast(x,y) ((uintmax_t)(y)) +# define fieldval_cast(x,y) (y) +#endif + +/* + * Macros to get/set bitfield values (the set macro returns the + * updated value, it does not change the input.) + * + * The fieldenc() macro produces the masked and shifted value + * corresponding to a base value; it is equivalent to + * setfield(field,0,val). + */ +#define getfield(field,from) \ + fieldval_cast(field, \ + (((from) >> field ## _POS) & \ + field ## _BASEMASK)) +#define fieldval(field,val) \ + (((val) & fieldenc_cast(field,field ## _BASEMASK)) \ + << field ## _POS) +#define setfield(field,from,val) \ + (((from) & ~(field ## _MASK)) + fieldval(field,val)) + /* * Wrappers around malloc, realloc, free and a few more. nasm_malloc * will fatal-error and die rather than return NULL; nasm_realloc will