netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields
@ 2024-12-03 23:53 Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 01/10] lib: packing: create __pack() and __unpack() variants without error checking Jacob Keller
                   ` (9 more replies)
  0 siblings, 10 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

This series improves the packing library with a new API for packing or
unpacking a large number of fields at once with minimal code footprint. The
API is then used to replace bespoke packing logic in the ice driver,
preparing it to handle unpacking in the future. Finally, the ice driver has
a few other cleanups related to the packing logic.

The pack_fields and unpack_fields functions have the following improvements
over the existing pack() and unpack() API:

 1. Packing or unpacking a large number of fields takes significantly less
    code. This significantly reduces the .text size for an increase in the
    .data size which is much smaller.

 2. The unpacked data can be stored in sizes smaller than u64 variables.
    This reduces the storage requirement both for runtime data structures,
    and for the rodata defining the fields. This scales with the number of
    fields used.

 3. Most of the error checking is done at compile time, rather than
    runtime, via CHECK_PACKED_FIELD macros.

The actual packing and unpacking code still uses the u64 size
variables. However, these are converted to the appropriate field sizes when
storing or reading the data from the buffer.

This version returns to the C pre-processor macro checks, rather than use
of external tools. To limit the amount of generated code and ease the
driver burden, we now enforce ordering (same as with v5), where the fields
must be in ascending or descending order. This reduces the overlap checks
from O(N^2) to O(N), and reduces the amount of generated code from 20K
lines to 3K lines.

I also refactored to place the generator script in
scripts/gen_packed_field_checks.c, and no longer automatically generate at
compile time. This avoids needing to mess too much with the top level build
system, at the expense of saving the macros in git. I think the reduction
to 3K lines is a bit more within reason vs the 20K lines from v2.

This version returns to the 5-argument format of pack_fields and
unpack_fields, but now enforces that the passed pbuflen is a compile-time
constant via __builtin_constant_p(). This ensures we can still perform the
size checks, but keeps the API flexible rather than forcing users to always
wrap their buffer in a struct typedef. I think this is acceptable, and
enforcing a compile-time known size is a reasonable constraint.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
Changes in v8:
- Add my missing SOB on one of the patches
- Remove include/linux/packing_types.h and put the generated code directly
  into include/linux/packing.h
- Split documentation to its own patch, and use the proposed documentation
  from Vladimir
- Link to v7: https://lore.kernel.org/r/20241202-packing-pack-fields-and-ice-implementation-v7-0-ed22e38e6c65@intel.com

Changes in v7:
- Dropped the RFC tag for submission to net-next
- Link to v6: https://lore.kernel.org/r/20241118-packing-pack-fields-and-ice-implementation-v6-0-6af8b658a6c3@intel.com

Changes in v6:
- Revert to macro checks similar to v2.
- Add a __builtin_choose_expr() based macro to automatically select the
  appropriate size macro.
- Keep the pbuflen check separate from the main loop check, similar to v5.
- Link to v5: https://lore.kernel.org/r/20241111-packing-pack-fields-and-ice-implementation-v5-0-80c07349e6b7@intel.com

Changes in v5:
- Fix printf format specifier for the sym->st_size
- Link to v4: https://lore.kernel.org/r/20241108-packing-pack-fields-and-ice-implementation-v4-0-81a9f42c30e5@intel.com

Changes in v4:
- Move the buffer size checks to (un)pack_fields() macros.
- Enforce use of a sized type of the packed buffer, removing the now
  unnecessary pbuflen argument of (un)pack_fields().
- Drop exporting the buffer size to modpost.
- Simplify modpost implementation to directly check each symbol in the
  handle_packed_field_symbol() function. This removes the need for a hash,
  and is ultimately much simpler now that modpost doesn't need the size of
  the target buffer.
- Fix the width check to correctly calculate the width and compare it
  properly.
- Refactor modpost messages to consistently report the module name first,
  the symbol name second, and the field number 3rd.
- Correctly implement overlap checks in the modpost, rather than only
  checking field ordering.
- Link to v3: https://lore.kernel.org/r/20241107-packing-pack-fields-and-ice-implementation-v3-0-27c566ac2436@intel.com

Changes in v3:
- Replace macro-based C pre-processor checks with checks implemented in
  modpost.
- Move structure definitions into  <linux/packing_types.h> to enable reuse
  within modpost.
- Add DECLARE_PACKED_FIELDS_S and DECLARE_PACKED_FIELDS_M to enable
  automatically generating the buffer size constants and the section
  attributes.
- Add additional unit tests for the pack_fields and unpack_fields APIs.
- Update documentation with an explanation of the new API as well as some
  example code.
- Link to v2: https://lore.kernel.org/r/20241025-packing-pack-fields-and-ice-implementation-v2-0-734776c88e40@intel.com

Changes in v2:
- Add my missing sign-off to the first patch
- Update the descriptions for a few patches
- Only generate CHECK_PACKED_FIELDS_N when another module selects it
- Add a new patch introducing wrapper structures for the packed Tx and Rx
  queue context, suggested by Vladimir.
- Drop the now unnecessary macros in ice, thanks to the new types
- Link to v1: https://lore.kernel.org/r/20241011-packing-pack-fields-and-ice-implementation-v1-0-d9b1f7500740@intel.com

---
Jacob Keller (7):
      lib: packing: document recently added APIs
      ice: remove int_q_state from ice_tlan_ctx
      ice: use structures to keep track of queue context size
      ice: use <linux/packing.h> for Tx and Rx queue context data
      ice: reduce size of queue context fields
      ice: move prefetch enable to ice_setup_rx_ctx
      ice: cleanup Rx queue context programming functions

Vladimir Oltean (3):
      lib: packing: create __pack() and __unpack() variants without error checking
      lib: packing: demote truncation error in pack() to a warning in __pack()
      lib: packing: add pack_fields() and unpack_fields()

 Makefile                                        |    4 +
 drivers/net/ethernet/intel/ice/ice_adminq_cmd.h |   11 +-
 drivers/net/ethernet/intel/ice/ice_common.h     |    5 +-
 drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h  |   49 +-
 include/linux/packing.h                         | 2855 +++++++++++++++++++++++
 drivers/net/dsa/sja1105/sja1105_static_config.c |    8 +-
 drivers/net/ethernet/intel/ice/ice_base.c       |    6 +-
 drivers/net/ethernet/intel/ice/ice_common.c     |  293 +--
 lib/packing.c                                   |  285 ++-
 lib/packing_test.c                              |   61 +
 scripts/gen_packed_field_checks.c               |   38 +
 Documentation/core-api/packing.rst              |  118 +-
 MAINTAINERS                                     |    1 +
 drivers/net/ethernet/intel/Kconfig              |    1 +
 scripts/Makefile                                |    2 +-
 15 files changed, 3377 insertions(+), 360 deletions(-)
---
base-commit: e8e7be7d212dc2bc83b8151e51088666a6c42092
change-id: 20241004-packing-pack-fields-and-ice-implementation-b17c7ce8e373

Best regards,
-- 
Jacob Keller <jacob.e.keller@intel.com>


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 01/10] lib: packing: create __pack() and __unpack() variants without error checking
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 02/10] lib: packing: demote truncation error in pack() to a warning in __pack() Jacob Keller
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

From: Vladimir Oltean <vladimir.oltean@nxp.com>

A future variant of the API, which works on arrays of packed_field
structures, will make most of these checks redundant. The idea will be
that we want to perform sanity checks at compile time, not once
for every function call.

Introduce new variants of pack() and unpack(), which elide the sanity
checks, assuming that the input was pre-sanitized.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 lib/packing.c | 142 ++++++++++++++++++++++++++++++++--------------------------
 1 file changed, 78 insertions(+), 64 deletions(-)

diff --git a/lib/packing.c b/lib/packing.c
index 793942745e34fde1810010e303742e6484861bc8..f237b8af99f5fa8e839c38126769c50b2bfe6361 100644
--- a/lib/packing.c
+++ b/lib/packing.c
@@ -51,64 +51,20 @@ static size_t calculate_box_addr(size_t box, size_t len, u8 quirks)
 	return offset_of_group + offset_in_group;
 }
 
-/**
- * pack - Pack u64 number into bitfield of buffer.
- *
- * @pbuf: Pointer to a buffer holding the packed value.
- * @uval: CPU-readable unpacked value to pack.
- * @startbit: The index (in logical notation, compensated for quirks) where
- *	      the packed value starts within pbuf. Must be larger than, or
- *	      equal to, endbit.
- * @endbit: The index (in logical notation, compensated for quirks) where
- *	    the packed value ends within pbuf. Must be smaller than, or equal
- *	    to, startbit.
- * @pbuflen: The length in bytes of the packed buffer pointed to by @pbuf.
- * @quirks: A bit mask of QUIRK_LITTLE_ENDIAN, QUIRK_LSW32_IS_FIRST and
- *	    QUIRK_MSB_ON_THE_RIGHT.
- *
- * Return: 0 on success, EINVAL or ERANGE if called incorrectly. Assuming
- *	   correct usage, return code may be discarded. The @pbuf memory will
- *	   be modified on success.
- */
-int pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, size_t pbuflen,
-	 u8 quirks)
+static void __pack(void *pbuf, u64 uval, size_t startbit, size_t endbit,
+		   size_t pbuflen, u8 quirks)
 {
 	/* Logical byte indices corresponding to the
 	 * start and end of the field.
 	 */
-	int plogical_first_u8, plogical_last_u8, box;
-	/* width of the field to access in the pbuf */
-	u64 value_width;
-
-	/* startbit is expected to be larger than endbit, and both are
-	 * expected to be within the logically addressable range of the buffer.
-	 */
-	if (unlikely(startbit < endbit || startbit >= BITS_PER_BYTE * pbuflen))
-		/* Invalid function call */
-		return -EINVAL;
-
-	value_width = startbit - endbit + 1;
-	if (unlikely(value_width > 64))
-		return -ERANGE;
-
-	/* Check if "uval" fits in "value_width" bits.
-	 * If value_width is 64, the check will fail, but any
-	 * 64-bit uval will surely fit.
-	 */
-	if (unlikely(value_width < 64 && uval >= (1ull << value_width)))
-		/* Cannot store "uval" inside "value_width" bits.
-		 * Truncating "uval" is most certainly not desirable,
-		 * so simply erroring out is appropriate.
-		 */
-		return -ERANGE;
+	int plogical_first_u8 = startbit / BITS_PER_BYTE;
+	int plogical_last_u8 = endbit / BITS_PER_BYTE;
+	int box;
 
 	/* Iterate through an idealistic view of the pbuf as an u64 with
 	 * no quirks, u8 by u8 (aligned at u8 boundaries), from high to low
 	 * logical bit significance. "box" denotes the current logical u8.
 	 */
-	plogical_first_u8 = startbit / BITS_PER_BYTE;
-	plogical_last_u8  = endbit / BITS_PER_BYTE;
-
 	for (box = plogical_first_u8; box >= plogical_last_u8; box--) {
 		/* Bit indices into the currently accessed 8-bit box */
 		size_t box_start_bit, box_end_bit, box_addr;
@@ -163,15 +119,13 @@ int pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, size_t pbuflen,
 		((u8 *)pbuf)[box_addr] &= ~box_mask;
 		((u8 *)pbuf)[box_addr] |= pval;
 	}
-	return 0;
 }
-EXPORT_SYMBOL(pack);
 
 /**
- * unpack - Unpack u64 number from packed buffer.
+ * pack - Pack u64 number into bitfield of buffer.
  *
  * @pbuf: Pointer to a buffer holding the packed value.
- * @uval: Pointer to an u64 holding the unpacked value.
+ * @uval: CPU-readable unpacked value to pack.
  * @startbit: The index (in logical notation, compensated for quirks) where
  *	      the packed value starts within pbuf. Must be larger than, or
  *	      equal to, endbit.
@@ -183,16 +137,12 @@ EXPORT_SYMBOL(pack);
  *	    QUIRK_MSB_ON_THE_RIGHT.
  *
  * Return: 0 on success, EINVAL or ERANGE if called incorrectly. Assuming
- *	   correct usage, return code may be discarded. The @uval will be
- *	   modified on success.
+ *	   correct usage, return code may be discarded. The @pbuf memory will
+ *	   be modified on success.
  */
-int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
-	   size_t pbuflen, u8 quirks)
+int pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, size_t pbuflen,
+	 u8 quirks)
 {
-	/* Logical byte indices corresponding to the
-	 * start and end of the field.
-	 */
-	int plogical_first_u8, plogical_last_u8, box;
 	/* width of the field to access in the pbuf */
 	u64 value_width;
 
@@ -207,6 +157,33 @@ int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
 	if (unlikely(value_width > 64))
 		return -ERANGE;
 
+	/* Check if "uval" fits in "value_width" bits.
+	 * If value_width is 64, the check will fail, but any
+	 * 64-bit uval will surely fit.
+	 */
+	if (value_width < 64 && uval >= (1ull << value_width))
+		/* Cannot store "uval" inside "value_width" bits.
+		 * Truncating "uval" is most certainly not desirable,
+		 * so simply erroring out is appropriate.
+		 */
+		return -ERANGE;
+
+	__pack(pbuf, uval, startbit, endbit, pbuflen, quirks);
+
+	return 0;
+}
+EXPORT_SYMBOL(pack);
+
+static void __unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
+		     size_t pbuflen, u8 quirks)
+{
+	/* Logical byte indices corresponding to the
+	 * start and end of the field.
+	 */
+	int plogical_first_u8 = startbit / BITS_PER_BYTE;
+	int plogical_last_u8 = endbit / BITS_PER_BYTE;
+	int box;
+
 	/* Initialize parameter */
 	*uval = 0;
 
@@ -214,9 +191,6 @@ int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
 	 * no quirks, u8 by u8 (aligned at u8 boundaries), from high to low
 	 * logical bit significance. "box" denotes the current logical u8.
 	 */
-	plogical_first_u8 = startbit / BITS_PER_BYTE;
-	plogical_last_u8  = endbit / BITS_PER_BYTE;
-
 	for (box = plogical_first_u8; box >= plogical_last_u8; box--) {
 		/* Bit indices into the currently accessed 8-bit box */
 		size_t box_start_bit, box_end_bit, box_addr;
@@ -271,6 +245,46 @@ int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
 		*uval &= ~proj_mask;
 		*uval |= pval;
 	}
+}
+
+/**
+ * unpack - Unpack u64 number from packed buffer.
+ *
+ * @pbuf: Pointer to a buffer holding the packed value.
+ * @uval: Pointer to an u64 holding the unpacked value.
+ * @startbit: The index (in logical notation, compensated for quirks) where
+ *	      the packed value starts within pbuf. Must be larger than, or
+ *	      equal to, endbit.
+ * @endbit: The index (in logical notation, compensated for quirks) where
+ *	    the packed value ends within pbuf. Must be smaller than, or equal
+ *	    to, startbit.
+ * @pbuflen: The length in bytes of the packed buffer pointed to by @pbuf.
+ * @quirks: A bit mask of QUIRK_LITTLE_ENDIAN, QUIRK_LSW32_IS_FIRST and
+ *	    QUIRK_MSB_ON_THE_RIGHT.
+ *
+ * Return: 0 on success, EINVAL or ERANGE if called incorrectly. Assuming
+ *	   correct usage, return code may be discarded. The @uval will be
+ *	   modified on success.
+ */
+int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
+	   size_t pbuflen, u8 quirks)
+{
+	/* width of the field to access in the pbuf */
+	u64 value_width;
+
+	/* startbit is expected to be larger than endbit, and both are
+	 * expected to be within the logically addressable range of the buffer.
+	 */
+	if (startbit < endbit || startbit >= BITS_PER_BYTE * pbuflen)
+		/* Invalid function call */
+		return -EINVAL;
+
+	value_width = startbit - endbit + 1;
+	if (value_width > 64)
+		return -ERANGE;
+
+	__unpack(pbuf, uval, startbit, endbit, pbuflen, quirks);
+
 	return 0;
 }
 EXPORT_SYMBOL(unpack);

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 02/10] lib: packing: demote truncation error in pack() to a warning in __pack()
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 01/10] lib: packing: create __pack() and __unpack() variants without error checking Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields() Jacob Keller
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

From: Vladimir Oltean <vladimir.oltean@nxp.com>

Most of the sanity checks in pack() and unpack() can be covered at
compile time. There is only one exception, and that is truncation of the
uval during a pack() operation.

We'd like the error-less __pack() to catch that condition as well. But
at the same time, it is currently the responsibility of consumer drivers
(currently just sja1105) to print anything at all when this error
occurs, and then discard the return code.

We can just print a loud warning in the library code and continue with
the truncated __pack() operation. In practice, having the warning is
very important, see commit 24deec6b9e4a ("net: dsa: sja1105: disallow
C45 transactions on the BASE-TX MDIO bus") where the bug was caught
exactly by noticing this print.

Add the first print to the packing library, and at the same time remove
the print for the same condition from the sja1105 driver, to avoid
double printing.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/dsa/sja1105/sja1105_static_config.c |  8 ++------
 lib/packing.c                                   | 26 ++++++++++---------------
 2 files changed, 12 insertions(+), 22 deletions(-)

diff --git a/drivers/net/dsa/sja1105/sja1105_static_config.c b/drivers/net/dsa/sja1105/sja1105_static_config.c
index baba204ad62f6b507a6ccf3337248dd02b777249..3d790f8c6f4dab3640ede014345ef469fefb7085 100644
--- a/drivers/net/dsa/sja1105/sja1105_static_config.c
+++ b/drivers/net/dsa/sja1105/sja1105_static_config.c
@@ -26,12 +26,8 @@ void sja1105_pack(void *buf, const u64 *val, int start, int end, size_t len)
 		pr_err("Start bit (%d) expected to be larger than end (%d)\n",
 		       start, end);
 	} else if (rc == -ERANGE) {
-		if ((start - end + 1) > 64)
-			pr_err("Field %d-%d too large for 64 bits!\n",
-			       start, end);
-		else
-			pr_err("Cannot store %llx inside bits %d-%d (would truncate)\n",
-			       *val, start, end);
+		pr_err("Field %d-%d too large for 64 bits!\n",
+		       start, end);
 	}
 	dump_stack();
 }
diff --git a/lib/packing.c b/lib/packing.c
index f237b8af99f5fa8e839c38126769c50b2bfe6361..09a2d195b9433b61c86f3b63ff019ab319c83e97 100644
--- a/lib/packing.c
+++ b/lib/packing.c
@@ -59,8 +59,17 @@ static void __pack(void *pbuf, u64 uval, size_t startbit, size_t endbit,
 	 */
 	int plogical_first_u8 = startbit / BITS_PER_BYTE;
 	int plogical_last_u8 = endbit / BITS_PER_BYTE;
+	int value_width = startbit - endbit + 1;
 	int box;
 
+	/* Check if "uval" fits in "value_width" bits.
+	 * The test only works for value_width < 64, but in the latter case,
+	 * any 64-bit uval will surely fit.
+	 */
+	WARN(value_width < 64 && uval >= (1ull << value_width),
+	     "Cannot store 0x%llx inside bits %zu-%zu - will truncate\n",
+	     uval, startbit, endbit);
+
 	/* Iterate through an idealistic view of the pbuf as an u64 with
 	 * no quirks, u8 by u8 (aligned at u8 boundaries), from high to low
 	 * logical bit significance. "box" denotes the current logical u8.
@@ -143,9 +152,6 @@ static void __pack(void *pbuf, u64 uval, size_t startbit, size_t endbit,
 int pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, size_t pbuflen,
 	 u8 quirks)
 {
-	/* width of the field to access in the pbuf */
-	u64 value_width;
-
 	/* startbit is expected to be larger than endbit, and both are
 	 * expected to be within the logically addressable range of the buffer.
 	 */
@@ -153,19 +159,7 @@ int pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, size_t pbuflen,
 		/* Invalid function call */
 		return -EINVAL;
 
-	value_width = startbit - endbit + 1;
-	if (unlikely(value_width > 64))
-		return -ERANGE;
-
-	/* Check if "uval" fits in "value_width" bits.
-	 * If value_width is 64, the check will fail, but any
-	 * 64-bit uval will surely fit.
-	 */
-	if (value_width < 64 && uval >= (1ull << value_width))
-		/* Cannot store "uval" inside "value_width" bits.
-		 * Truncating "uval" is most certainly not desirable,
-		 * so simply erroring out is appropriate.
-		 */
+	if (unlikely(startbit - endbit >= 64))
 		return -ERANGE;
 
 	__pack(pbuf, uval, startbit, endbit, pbuflen, quirks);

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 01/10] lib: packing: create __pack() and __unpack() variants without error checking Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 02/10] lib: packing: demote truncation error in pack() to a warning in __pack() Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-04 17:12   ` Vladimir Oltean
  2024-12-03 23:53 ` [PATCH net-next v8 04/10] lib: packing: document recently added APIs Jacob Keller
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

From: Vladimir Oltean <vladimir.oltean@nxp.com>

This is new API which caters to the following requirements:

- Pack or unpack a large number of fields to/from a buffer with a small
  code footprint. The current alternative is to open-code a large number
  of calls to pack() and unpack(), or to use packing() to reduce that
  number to half. But packing() is not const-correct.

- Use unpacked numbers stored in variables smaller than u64. This
  reduces the rodata footprint of the stored field arrays.

- Perform error checking at compile time, rather than runtime, and return
  void from the API functions. Because the C preprocessor can't generate
  variable length code (loops), this is a bit tricky to do with macros.

  To handle this, implement macros which sanity check the packed field
  definitions based on their size. Finally, a single macro with a chain of
  __builtin_choose_expr() is used to select the appropriate macros. We
  enforce the use of ascending or descending order to avoid O(N^2) scaling
  when checking for overlap. Note that the macros are written with care to
  ensure that the compilers can correctly evaluate the resulting code at
  compile time. In particular, the expressions for the pbuflen and the
  ordering check are passed all the way down via macros. Earlier versions
  attempted to use statement expressions with local variables, but not all
  compilers were able to fully analyze these at compile time, resulting in
  BUILD_BUG_ON failures.

  The overlap macro is passed a condition determining whether the fields
  are expected to be in ascending or descending order based on the relative
  ordering of the first two fields. This allows users to keep the fields in
  whichever order is most natural for their hardware, while still keeping
  the overlap checks scaling to O(N).

  This method also enables calling CHECK_PACKED_FIELDS directly from within
  the pack_fields and unpack_fields macros, ensuring all drivers using this
  API will receive type checking, without needing to remember to call the
  CHECK_PACKED_FIELDS macro themselves.

- Reduced rodata footprint for the storage of the packed field arrays.
  To that end, we have struct packed_field_s (small) and packed_field_m
  (medium). More can be added as needed (unlikely for now). On these
  types, the same generic pack_fields() and unpack_fields() API can be
  used, thanks to the new C11 _Generic() selection feature, which can
  call pack_fields_s() or pack_fields_m(), depending on the type of the
  "fields" array - a simplistic form of polymorphism. It is evaluated at
  compile time which function will actually be called.

Over time, packing() is expected to be completely replaced either with
pack() or with pack_fields().

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Co-developed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 Makefile                          |    4 +
 include/linux/packing.h           | 2855 +++++++++++++++++++++++++++++++++++++
 lib/packing.c                     |  145 ++
 lib/packing_test.c                |   61 +
 scripts/gen_packed_field_checks.c |   38 +
 MAINTAINERS                       |    1 +
 scripts/Makefile                  |    2 +-
 7 files changed, 3105 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 8129de0b214f5b73a3b1cca0798041d74270836b..58496942a7d13c6a53e4210d83deb2cc2033d00a 100644
--- a/Makefile
+++ b/Makefile
@@ -1315,6 +1315,10 @@ PHONY += scripts_unifdef
 scripts_unifdef: scripts_basic
 	$(Q)$(MAKE) $(build)=scripts scripts/unifdef
 
+PHONY += scripts_gen_packed_field_checks
+scripts_gen_packed_field_checks: scripts_basic
+	$(Q)$(MAKE) $(build)=scripts scripts/gen_packed_field_checks
+
 # ---------------------------------------------------------------------------
 # Install
 
diff --git a/include/linux/packing.h b/include/linux/packing.h
index 5d36dcd06f60420325473dae3a0e9ac37d03da4b..c4fc76ae64a512cf977f3a89da25717bd99a5d91 100644
--- a/include/linux/packing.h
+++ b/include/linux/packing.h
@@ -8,6 +8,61 @@
 #include <linux/types.h>
 #include <linux/bitops.h>
 
+#define GEN_PACKED_FIELD_MEMBERS(__type) \
+	__type startbit; \
+	__type endbit; \
+	__type offset; \
+	__type size
+
+/* Small packed field. Use with bit offsets < 256, buffers < 32B and
+ * unpacked structures < 256B.
+ */
+struct packed_field_s {
+	GEN_PACKED_FIELD_MEMBERS(u8);
+};
+
+/* Medium packed field. Use with bit offsets < 65536, buffers < 8KB and
+ * unpacked structures < 64KB.
+ */
+struct packed_field_m {
+	GEN_PACKED_FIELD_MEMBERS(u16);
+};
+
+#define PACKED_FIELD(start, end, struct_name, struct_field) \
+{ \
+	(start), \
+	(end), \
+	offsetof(struct_name, struct_field), \
+	sizeof_field(struct_name, struct_field), \
+}
+
+#define CHECK_PACKED_FIELD(field) ({ \
+	typeof(field) __f = (field); \
+	BUILD_BUG_ON(__f.startbit < __f.endbit); \
+	BUILD_BUG_ON(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size); \
+	BUILD_BUG_ON(__f.size != 1 && __f.size != 2 && \
+		     __f.size != 4 && __f.size != 8); \
+})
+
+
+#define CHECK_PACKED_FIELD_OVERLAP(ascending, field1, field2) ({ \
+	typeof(field1) _f1 = (field1); typeof(field2) _f2 = (field2); \
+	const bool _a = (ascending); \
+	BUILD_BUG_ON(_a && _f1.startbit >= _f2.startbit); \
+	BUILD_BUG_ON(!_a && _f1.startbit <= _f2.startbit); \
+	BUILD_BUG_ON(max(_f1.endbit, _f2.endbit) <= \
+		     min(_f1.startbit, _f2.startbit)); \
+})
+
+#define CHECK_PACKED_FIELDS_SIZE(fields, pbuflen) ({ \
+	typeof(&(fields)[0]) _f = (fields); \
+	typeof(pbuflen) _len = (pbuflen); \
+	const size_t num_fields = ARRAY_SIZE(fields); \
+	BUILD_BUG_ON(!__builtin_constant_p(_len)); \
+	BUILD_BUG_ON(_f[0].startbit >= BITS_PER_BYTE * _len); \
+	BUILD_BUG_ON(_f[num_fields - 1].startbit >= BITS_PER_BYTE * _len); \
+})
+
 #define QUIRK_MSB_ON_THE_RIGHT	BIT(0)
 #define QUIRK_LITTLE_ENDIAN	BIT(1)
 #define QUIRK_LSW32_IS_FIRST	BIT(2)
@@ -26,4 +81,2804 @@ int pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, size_t pbuflen,
 int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
 	   size_t pbuflen, u8 quirks);
 
+void pack_fields_s(void *pbuf, size_t pbuflen, const void *ustruct,
+		   const struct packed_field_s *fields, size_t num_fields,
+		   u8 quirks);
+
+void pack_fields_m(void *pbuf, size_t pbuflen, const void *ustruct,
+		   const struct packed_field_m *fields, size_t num_fields,
+		   u8 quirks);
+
+void unpack_fields_s(const void *pbuf, size_t pbuflen, void *ustruct,
+		     const struct packed_field_s *fields, size_t num_fields,
+		     u8 quirks);
+
+void unpack_fields_m(const void *pbuf, size_t pbuflen, void *ustruct,
+		     const struct packed_field_m *fields, size_t num_fields,
+		     u8 quirks);
+
+/* Do not hand-edit the following packed field check macros!
+ *
+ * They are generated using scripts/gen_packed_field_checks.c, which may be
+ * built via "make scripts_gen_packed_field_checks". If larger macro sizes are
+ * needed in the future, please use this program to re-generate the macros and
+ * insert them here.
+ */
+
+#define CHECK_PACKED_FIELDS_1(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 1); \
+	 CHECK_PACKED_FIELD(_f[0]); })
+
+#define CHECK_PACKED_FIELDS_2(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 2); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); })
+
+#define CHECK_PACKED_FIELDS_3(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 3); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); })
+
+#define CHECK_PACKED_FIELDS_4(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 4); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); })
+
+#define CHECK_PACKED_FIELDS_5(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 5); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); })
+
+#define CHECK_PACKED_FIELDS_6(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 6); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); })
+
+#define CHECK_PACKED_FIELDS_7(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 7); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); })
+
+#define CHECK_PACKED_FIELDS_8(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 8); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); })
+
+#define CHECK_PACKED_FIELDS_9(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 9); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); })
+
+#define CHECK_PACKED_FIELDS_10(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 10); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); })
+
+#define CHECK_PACKED_FIELDS_11(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 11); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); })
+
+#define CHECK_PACKED_FIELDS_12(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 12); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); })
+
+#define CHECK_PACKED_FIELDS_13(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 13); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); })
+
+#define CHECK_PACKED_FIELDS_14(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 14); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); })
+
+#define CHECK_PACKED_FIELDS_15(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 15); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); })
+
+#define CHECK_PACKED_FIELDS_16(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 16); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); })
+
+#define CHECK_PACKED_FIELDS_17(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 17); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); })
+
+#define CHECK_PACKED_FIELDS_18(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 18); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); })
+
+#define CHECK_PACKED_FIELDS_19(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 19); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); })
+
+#define CHECK_PACKED_FIELDS_20(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 20); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); })
+
+#define CHECK_PACKED_FIELDS_21(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 21); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); })
+
+#define CHECK_PACKED_FIELDS_22(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 22); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); })
+
+#define CHECK_PACKED_FIELDS_23(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 23); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); })
+
+#define CHECK_PACKED_FIELDS_24(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 24); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); })
+
+#define CHECK_PACKED_FIELDS_25(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 25); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); })
+
+#define CHECK_PACKED_FIELDS_26(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 26); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); })
+
+#define CHECK_PACKED_FIELDS_27(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 27); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); })
+
+#define CHECK_PACKED_FIELDS_28(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 28); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); })
+
+#define CHECK_PACKED_FIELDS_29(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 29); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); })
+
+#define CHECK_PACKED_FIELDS_30(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 30); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); })
+
+#define CHECK_PACKED_FIELDS_31(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 31); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); })
+
+#define CHECK_PACKED_FIELDS_32(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 32); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); })
+
+#define CHECK_PACKED_FIELDS_33(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 33); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); })
+
+#define CHECK_PACKED_FIELDS_34(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 34); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); })
+
+#define CHECK_PACKED_FIELDS_35(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 35); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); })
+
+#define CHECK_PACKED_FIELDS_36(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 36); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); })
+
+#define CHECK_PACKED_FIELDS_37(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 37); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); })
+
+#define CHECK_PACKED_FIELDS_38(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 38); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); })
+
+#define CHECK_PACKED_FIELDS_39(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 39); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); })
+
+#define CHECK_PACKED_FIELDS_40(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 40); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); })
+
+#define CHECK_PACKED_FIELDS_41(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 41); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); })
+
+#define CHECK_PACKED_FIELDS_42(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 42); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); })
+
+#define CHECK_PACKED_FIELDS_43(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 43); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); })
+
+#define CHECK_PACKED_FIELDS_44(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 44); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD(_f[43]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[42], _f[43]); })
+
+#define CHECK_PACKED_FIELDS_45(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 45); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD(_f[43]); \
+	 CHECK_PACKED_FIELD(_f[44]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[42], _f[43]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[43], _f[44]); })
+
+#define CHECK_PACKED_FIELDS_46(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 46); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD(_f[43]); \
+	 CHECK_PACKED_FIELD(_f[44]); \
+	 CHECK_PACKED_FIELD(_f[45]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[42], _f[43]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[43], _f[44]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[44], _f[45]); })
+
+#define CHECK_PACKED_FIELDS_47(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 47); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD(_f[43]); \
+	 CHECK_PACKED_FIELD(_f[44]); \
+	 CHECK_PACKED_FIELD(_f[45]); \
+	 CHECK_PACKED_FIELD(_f[46]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[42], _f[43]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[43], _f[44]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[44], _f[45]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[45], _f[46]); })
+
+#define CHECK_PACKED_FIELDS_48(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 48); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD(_f[43]); \
+	 CHECK_PACKED_FIELD(_f[44]); \
+	 CHECK_PACKED_FIELD(_f[45]); \
+	 CHECK_PACKED_FIELD(_f[46]); \
+	 CHECK_PACKED_FIELD(_f[47]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[42], _f[43]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[43], _f[44]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[44], _f[45]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[45], _f[46]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[46], _f[47]); })
+
+#define CHECK_PACKED_FIELDS_49(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 49); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD(_f[43]); \
+	 CHECK_PACKED_FIELD(_f[44]); \
+	 CHECK_PACKED_FIELD(_f[45]); \
+	 CHECK_PACKED_FIELD(_f[46]); \
+	 CHECK_PACKED_FIELD(_f[47]); \
+	 CHECK_PACKED_FIELD(_f[48]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[42], _f[43]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[43], _f[44]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[44], _f[45]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[45], _f[46]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[46], _f[47]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[47], _f[48]); })
+
+#define CHECK_PACKED_FIELDS_50(fields) \
+	({ typeof(&(fields)[0]) _f = (fields); \
+	 BUILD_BUG_ON(ARRAY_SIZE(fields) != 50); \
+	 CHECK_PACKED_FIELD(_f[0]); \
+	 CHECK_PACKED_FIELD(_f[1]); \
+	 CHECK_PACKED_FIELD(_f[2]); \
+	 CHECK_PACKED_FIELD(_f[3]); \
+	 CHECK_PACKED_FIELD(_f[4]); \
+	 CHECK_PACKED_FIELD(_f[5]); \
+	 CHECK_PACKED_FIELD(_f[6]); \
+	 CHECK_PACKED_FIELD(_f[7]); \
+	 CHECK_PACKED_FIELD(_f[8]); \
+	 CHECK_PACKED_FIELD(_f[9]); \
+	 CHECK_PACKED_FIELD(_f[10]); \
+	 CHECK_PACKED_FIELD(_f[11]); \
+	 CHECK_PACKED_FIELD(_f[12]); \
+	 CHECK_PACKED_FIELD(_f[13]); \
+	 CHECK_PACKED_FIELD(_f[14]); \
+	 CHECK_PACKED_FIELD(_f[15]); \
+	 CHECK_PACKED_FIELD(_f[16]); \
+	 CHECK_PACKED_FIELD(_f[17]); \
+	 CHECK_PACKED_FIELD(_f[18]); \
+	 CHECK_PACKED_FIELD(_f[19]); \
+	 CHECK_PACKED_FIELD(_f[20]); \
+	 CHECK_PACKED_FIELD(_f[21]); \
+	 CHECK_PACKED_FIELD(_f[22]); \
+	 CHECK_PACKED_FIELD(_f[23]); \
+	 CHECK_PACKED_FIELD(_f[24]); \
+	 CHECK_PACKED_FIELD(_f[25]); \
+	 CHECK_PACKED_FIELD(_f[26]); \
+	 CHECK_PACKED_FIELD(_f[27]); \
+	 CHECK_PACKED_FIELD(_f[28]); \
+	 CHECK_PACKED_FIELD(_f[29]); \
+	 CHECK_PACKED_FIELD(_f[30]); \
+	 CHECK_PACKED_FIELD(_f[31]); \
+	 CHECK_PACKED_FIELD(_f[32]); \
+	 CHECK_PACKED_FIELD(_f[33]); \
+	 CHECK_PACKED_FIELD(_f[34]); \
+	 CHECK_PACKED_FIELD(_f[35]); \
+	 CHECK_PACKED_FIELD(_f[36]); \
+	 CHECK_PACKED_FIELD(_f[37]); \
+	 CHECK_PACKED_FIELD(_f[38]); \
+	 CHECK_PACKED_FIELD(_f[39]); \
+	 CHECK_PACKED_FIELD(_f[40]); \
+	 CHECK_PACKED_FIELD(_f[41]); \
+	 CHECK_PACKED_FIELD(_f[42]); \
+	 CHECK_PACKED_FIELD(_f[43]); \
+	 CHECK_PACKED_FIELD(_f[44]); \
+	 CHECK_PACKED_FIELD(_f[45]); \
+	 CHECK_PACKED_FIELD(_f[46]); \
+	 CHECK_PACKED_FIELD(_f[47]); \
+	 CHECK_PACKED_FIELD(_f[48]); \
+	 CHECK_PACKED_FIELD(_f[49]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[0], _f[1]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[1], _f[2]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[2], _f[3]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[3], _f[4]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[4], _f[5]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[5], _f[6]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[6], _f[7]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[7], _f[8]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[8], _f[9]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[9], _f[10]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[10], _f[11]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[11], _f[12]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[12], _f[13]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[13], _f[14]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[14], _f[15]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[15], _f[16]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[16], _f[17]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[17], _f[18]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[18], _f[19]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[19], _f[20]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[20], _f[21]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[21], _f[22]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[22], _f[23]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[23], _f[24]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[24], _f[25]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[25], _f[26]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[26], _f[27]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[27], _f[28]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[28], _f[29]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[29], _f[30]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[30], _f[31]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[31], _f[32]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[32], _f[33]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[33], _f[34]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[34], _f[35]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[35], _f[36]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[36], _f[37]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[37], _f[38]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[38], _f[39]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[39], _f[40]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[40], _f[41]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[41], _f[42]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[42], _f[43]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[43], _f[44]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[44], _f[45]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[45], _f[46]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[46], _f[47]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[47], _f[48]); \
+	 CHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[48], _f[49]); })
+
+#define CHECK_PACKED_FIELDS(fields) \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 1, CHECK_PACKED_FIELDS_1(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 2, CHECK_PACKED_FIELDS_2(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 3, CHECK_PACKED_FIELDS_3(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 4, CHECK_PACKED_FIELDS_4(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 5, CHECK_PACKED_FIELDS_5(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 6, CHECK_PACKED_FIELDS_6(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 7, CHECK_PACKED_FIELDS_7(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 8, CHECK_PACKED_FIELDS_8(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 9, CHECK_PACKED_FIELDS_9(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 10, CHECK_PACKED_FIELDS_10(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 11, CHECK_PACKED_FIELDS_11(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 12, CHECK_PACKED_FIELDS_12(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 13, CHECK_PACKED_FIELDS_13(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 14, CHECK_PACKED_FIELDS_14(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 15, CHECK_PACKED_FIELDS_15(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 16, CHECK_PACKED_FIELDS_16(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 17, CHECK_PACKED_FIELDS_17(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 18, CHECK_PACKED_FIELDS_18(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 19, CHECK_PACKED_FIELDS_19(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 20, CHECK_PACKED_FIELDS_20(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 21, CHECK_PACKED_FIELDS_21(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 22, CHECK_PACKED_FIELDS_22(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 23, CHECK_PACKED_FIELDS_23(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 24, CHECK_PACKED_FIELDS_24(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 25, CHECK_PACKED_FIELDS_25(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 26, CHECK_PACKED_FIELDS_26(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 27, CHECK_PACKED_FIELDS_27(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 28, CHECK_PACKED_FIELDS_28(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 29, CHECK_PACKED_FIELDS_29(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 30, CHECK_PACKED_FIELDS_30(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 31, CHECK_PACKED_FIELDS_31(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 32, CHECK_PACKED_FIELDS_32(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 33, CHECK_PACKED_FIELDS_33(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 34, CHECK_PACKED_FIELDS_34(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 35, CHECK_PACKED_FIELDS_35(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 36, CHECK_PACKED_FIELDS_36(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 37, CHECK_PACKED_FIELDS_37(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 38, CHECK_PACKED_FIELDS_38(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 39, CHECK_PACKED_FIELDS_39(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 40, CHECK_PACKED_FIELDS_40(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 41, CHECK_PACKED_FIELDS_41(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 42, CHECK_PACKED_FIELDS_42(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 43, CHECK_PACKED_FIELDS_43(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 44, CHECK_PACKED_FIELDS_44(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 45, CHECK_PACKED_FIELDS_45(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 46, CHECK_PACKED_FIELDS_46(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 47, CHECK_PACKED_FIELDS_47(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 48, CHECK_PACKED_FIELDS_48(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 49, CHECK_PACKED_FIELDS_49(fields), \
+	__builtin_choose_expr(ARRAY_SIZE(fields) == 50, CHECK_PACKED_FIELDS_50(fields), \
+	({ BUILD_BUG_ON_MSG(1, "CHECK_PACKED_FIELDS() must be regenerated to support array sizes larger than 50."); }) \
+	))))))))))))))))))))))))))))))))))))))))))))))))))
+
+/* End of generated content */
+
+#define pack_fields(pbuf, pbuflen, ustruct, fields, quirks) \
+	({ \
+		CHECK_PACKED_FIELDS(fields); \
+		CHECK_PACKED_FIELDS_SIZE((fields), (pbuflen)); \
+		_Generic((fields), \
+			 const struct packed_field_s * : pack_fields_s, \
+			 const struct packed_field_m * : pack_fields_m \
+			)((pbuf), (pbuflen), (ustruct), (fields), ARRAY_SIZE(fields), (quirks)); \
+	})
+
+#define unpack_fields(pbuf, pbuflen, ustruct, fields, quirks) \
+	({ \
+		CHECK_PACKED_FIELDS(fields); \
+		CHECK_PACKED_FIELDS_SIZE((fields), (pbuflen)); \
+		_Generic((fields), \
+			 const struct packed_field_s * : unpack_fields_s, \
+			 const struct packed_field_m * : unpack_fields_m \
+			)((pbuf), (pbuflen), (ustruct), (fields), ARRAY_SIZE(fields), (quirks)); \
+	})
+
 #endif
diff --git a/lib/packing.c b/lib/packing.c
index 09a2d195b9433b61c86f3b63ff019ab319c83e97..45164f73fe5bf9f2c547eb22016af7e44fed9eb0 100644
--- a/lib/packing.c
+++ b/lib/packing.c
@@ -5,10 +5,37 @@
 #include <linux/packing.h>
 #include <linux/module.h>
 #include <linux/bitops.h>
+#include <linux/bits.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/bitrev.h>
 
+#define __pack_fields(pbuf, pbuflen, ustruct, fields, num_fields, quirks)	\
+	({									\
+		for (size_t i = 0; i < (num_fields); i++) {			\
+			typeof(&(fields)[0]) field = &(fields)[i];		\
+			u64 uval;						\
+										\
+			uval = ustruct_field_to_u64(ustruct, field->offset, field->size); \
+										\
+			__pack(pbuf, uval, field->startbit, field->endbit,	\
+			       pbuflen, quirks);				\
+		}								\
+	})
+
+#define __unpack_fields(pbuf, pbuflen, ustruct, fields, num_fields, quirks)	\
+	({									\
+		for (size_t i = 0; i < (num_fields); i++) {			\
+			typeof(&(fields)[0]) field = &fields[i];		\
+			u64 uval;						\
+										\
+			__unpack(pbuf, &uval, field->startbit, field->endbit,	\
+				 pbuflen, quirks);				\
+										\
+			u64_to_ustruct_field(ustruct, field->offset, field->size, uval); \
+		}								\
+	})
+
 /**
  * calculate_box_addr - Determine physical location of byte in buffer
  * @box: Index of byte within buffer seen as a logical big-endian big number
@@ -322,4 +349,122 @@ int packing(void *pbuf, u64 *uval, int startbit, int endbit, size_t pbuflen,
 }
 EXPORT_SYMBOL(packing);
 
+static u64 ustruct_field_to_u64(const void *ustruct, size_t field_offset,
+				size_t field_size)
+{
+	switch (field_size) {
+	case 1:
+		return *((u8 *)(ustruct + field_offset));
+	case 2:
+		return *((u16 *)(ustruct + field_offset));
+	case 4:
+		return *((u32 *)(ustruct + field_offset));
+	default:
+		return *((u64 *)(ustruct + field_offset));
+	}
+}
+
+static void u64_to_ustruct_field(void *ustruct, size_t field_offset,
+				 size_t field_size, u64 uval)
+{
+	switch (field_size) {
+	case 1:
+		*((u8 *)(ustruct + field_offset)) = uval;
+		break;
+	case 2:
+		*((u16 *)(ustruct + field_offset)) = uval;
+		break;
+	case 4:
+		*((u32 *)(ustruct + field_offset)) = uval;
+		break;
+	default:
+		*((u64 *)(ustruct + field_offset)) = uval;
+		break;
+	}
+}
+
+/**
+ * pack_fields_s - Pack array of small fields
+ *
+ * @pbuf: Pointer to a buffer holding the packed value.
+ * @pbuflen: The length in bytes of the packed buffer pointed to by @pbuf.
+ * @ustruct: Pointer to CPU-readable structure holding the unpacked value.
+ *	     It is expected (but not checked) that this has the same data type
+ *	     as all struct packed_field_s definitions.
+ * @fields: Array of small packed fields definition. They must not overlap.
+ * @num_fields: Length of @fields array.
+ * @quirks: A bit mask of QUIRK_LITTLE_ENDIAN, QUIRK_LSW32_IS_FIRST and
+ *	    QUIRK_MSB_ON_THE_RIGHT.
+ */
+void pack_fields_s(void *pbuf, size_t pbuflen, const void *ustruct,
+		   const struct packed_field_s *fields, size_t num_fields,
+		   u8 quirks)
+{
+	__pack_fields(pbuf, pbuflen, ustruct, fields, num_fields, quirks);
+}
+EXPORT_SYMBOL(pack_fields_s);
+
+/**
+ * pack_fields_m - Pack array of medium fields
+ *
+ * @pbuf: Pointer to a buffer holding the packed value.
+ * @pbuflen: The length in bytes of the packed buffer pointed to by @pbuf.
+ * @ustruct: Pointer to CPU-readable structure holding the unpacked value.
+ *	     It is expected (but not checked) that this has the same data type
+ *	     as all struct packed_field_s definitions.
+ * @fields: Array of medium packed fields definition. They must not overlap.
+ * @num_fields: Length of @fields array.
+ * @quirks: A bit mask of QUIRK_LITTLE_ENDIAN, QUIRK_LSW32_IS_FIRST and
+ *	    QUIRK_MSB_ON_THE_RIGHT.
+ */
+void pack_fields_m(void *pbuf, size_t pbuflen, const void *ustruct,
+		   const struct packed_field_m *fields, size_t num_fields,
+		   u8 quirks)
+{
+	__pack_fields(pbuf, pbuflen, ustruct, fields, num_fields, quirks);
+}
+EXPORT_SYMBOL(pack_fields_m);
+
+/**
+ * unpack_fields_s - Unpack array of small fields
+ *
+ * @pbuf: Pointer to a buffer holding the packed value.
+ * @pbuflen: The length in bytes of the packed buffer pointed to by @pbuf.
+ * @ustruct: Pointer to CPU-readable structure holding the unpacked value.
+ *	     It is expected (but not checked) that this has the same data type
+ *	     as all struct packed_field_s definitions.
+ * @fields: Array of small packed fields definition. They must not overlap.
+ * @num_fields: Length of @fields array.
+ * @quirks: A bit mask of QUIRK_LITTLE_ENDIAN, QUIRK_LSW32_IS_FIRST and
+ *	    QUIRK_MSB_ON_THE_RIGHT.
+ */
+void unpack_fields_s(const void *pbuf, size_t pbuflen, void *ustruct,
+		     const struct packed_field_s *fields, size_t num_fields,
+		     u8 quirks)
+{
+	__unpack_fields(pbuf, pbuflen, ustruct, fields, num_fields, quirks);
+}
+EXPORT_SYMBOL(unpack_fields_s);
+
+/**
+ * unpack_fields_m - Unpack array of medium fields
+ *
+ * @pbuf: Pointer to a buffer holding the packed value.
+ * @pbuflen: The length in bytes of the packed buffer pointed to by @pbuf.
+ * @ustruct: Pointer to CPU-readable structure holding the unpacked value.
+ *	     It is expected (but not checked) that this has the same data type
+ *	     as all struct packed_field_s definitions.
+ * @fields: Array of medium packed fields definition. They must not overlap.
+ * @num_fields: Length of @fields array.
+ * @quirks: A bit mask of QUIRK_LITTLE_ENDIAN, QUIRK_LSW32_IS_FIRST and
+ *	    QUIRK_MSB_ON_THE_RIGHT.
+ */
+void unpack_fields_m(const void *pbuf, size_t pbuflen, void *ustruct,
+		     const struct packed_field_m *fields, size_t num_fields,
+		     u8 quirks)
+{
+	__unpack_fields(pbuf, pbuflen, ustruct, fields, num_fields, quirks);
+}
+EXPORT_SYMBOL(unpack_fields_m);
+
 MODULE_DESCRIPTION("Generic bitfield packing and unpacking");
diff --git a/lib/packing_test.c b/lib/packing_test.c
index b38ea43c03fd83639f18a6f3e2a42eae36118c45..3b4167ce56bf65fa4d66cb55d3215aecc33f64c4 100644
--- a/lib/packing_test.c
+++ b/lib/packing_test.c
@@ -396,9 +396,70 @@ static void packing_test_unpack(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, uval, params->uval);
 }
 
+#define PACKED_BUF_SIZE 8
+
+typedef struct __packed { u8 buf[PACKED_BUF_SIZE]; } packed_buf_t;
+
+struct test_data {
+	u32 field3;
+	u16 field2;
+	u16 field4;
+	u16 field6;
+	u8 field1;
+	u8 field5;
+};
+
+static const struct packed_field_s test_fields[] = {
+	PACKED_FIELD(63, 61, struct test_data, field1),
+	PACKED_FIELD(60, 52, struct test_data, field2),
+	PACKED_FIELD(51, 28, struct test_data, field3),
+	PACKED_FIELD(27, 14, struct test_data, field4),
+	PACKED_FIELD(13, 9, struct test_data, field5),
+	PACKED_FIELD(8, 0, struct test_data, field6),
+};
+
+static void packing_test_pack_fields(struct kunit *test)
+{
+	const struct test_data data = {
+		.field1 = 0x2,
+		.field2 = 0x100,
+		.field3 = 0xF00050,
+		.field4 = 0x7D3,
+		.field5 = 0x9,
+		.field6 = 0x10B,
+	};
+	packed_buf_t expect = {
+		.buf = { 0x50, 0x0F, 0x00, 0x05, 0x01, 0xF4, 0xD3, 0x0B },
+	};
+	packed_buf_t buf = {};
+
+	pack_fields(&buf, sizeof(buf), &data, test_fields, 0);
+
+	KUNIT_EXPECT_MEMEQ(test, &expect, &buf, sizeof(buf));
+}
+
+static void packing_test_unpack_fields(struct kunit *test)
+{
+	const packed_buf_t buf = {
+		.buf = { 0x17, 0x28, 0x10, 0x19, 0x3D, 0xA9, 0x07, 0x9C },
+	};
+	struct test_data data = {};
+
+	unpack_fields(&buf, sizeof(buf), &data, test_fields, 0);
+
+	KUNIT_EXPECT_EQ(test, 0, data.field1);
+	KUNIT_EXPECT_EQ(test, 0x172, data.field2);
+	KUNIT_EXPECT_EQ(test, 0x810193, data.field3);
+	KUNIT_EXPECT_EQ(test, 0x36A4, data.field4);
+	KUNIT_EXPECT_EQ(test, 0x3, data.field5);
+	KUNIT_EXPECT_EQ(test, 0x19C, data.field6);
+}
+
 static struct kunit_case packing_test_cases[] = {
 	KUNIT_CASE_PARAM(packing_test_pack, packing_gen_params),
 	KUNIT_CASE_PARAM(packing_test_unpack, packing_gen_params),
+	KUNIT_CASE(packing_test_pack_fields),
+	KUNIT_CASE(packing_test_unpack_fields),
 	{},
 };
 
diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
new file mode 100644
index 0000000000000000000000000000000000000000..09a21afd640bdf37ad5ee9f6cfa1d4b9113efbcd
--- /dev/null
+++ b/scripts/gen_packed_field_checks.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2024, Intel Corporation
+#include <stdbool.h>
+#include <stdio.h>
+
+#define MAX_PACKED_FIELD_SIZE 50
+
+int main(int argc, char **argv)
+{
+	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
+		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);
+		printf("\ttypeof(&(fields)[0]) _f = (fields); \\\n");
+		printf("\tBUILD_BUG_ON(ARRAY_SIZE(fields) != %d); \\\n", i);
+
+		for (int j = 0; j < i; j++)
+			printf("\tCHECK_PACKED_FIELD(_f[%d]); \\\n", j);
+
+		for (int j = 1; j < i; j++)
+			printf("\tCHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[%d], _f[%d]); \\\n",
+			       j - 1, j);
+
+		printf("})\n\n");
+	}
+
+	printf("#define CHECK_PACKED_FIELDS(fields) \\\n");
+
+	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++)
+		printf("\t__builtin_choose_expr(ARRAY_SIZE(fields) == %d, CHECK_PACKED_FIELDS_%d(fields), \\\n",
+		       i, i);
+
+	printf("\t({ BUILD_BUG_ON_MSG(1, \"CHECK_PACKED_FIELDS() must be regenerated to support array sizes larger than %d.\"); }) \\\n",
+	       MAX_PACKED_FIELD_SIZE);
+
+	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++)
+		printf(")");
+
+	printf("\n");
+}
diff --git a/MAINTAINERS b/MAINTAINERS
index 0456a33ef65792bacb5d305a6384d245844fb743..397dfdab2d92a969d367dcf77207d387cda451e3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17561,6 +17561,7 @@ F:	Documentation/core-api/packing.rst
 F:	include/linux/packing.h
 F:	lib/packing.c
 F:	lib/packing_test.c
+F:	scripts/gen_packed_field_checks.c
 
 PADATA PARALLEL EXECUTION MECHANISM
 M:	Steffen Klassert <steffen.klassert@secunet.com>
diff --git a/scripts/Makefile b/scripts/Makefile
index 6bcda4b9d054021b185488841cd36c6e0fb86d0c..546e8175e1c4c8209e67a7f92f7d1e795a030988 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -47,7 +47,7 @@ HOSTCFLAGS_sorttable.o += -DMCOUNT_SORT_ENABLED
 endif
 
 # The following programs are only built on demand
-hostprogs += unifdef
+hostprogs += unifdef gen_packed_field_checks
 
 # The module linker script is preprocessed on demand
 targets += module.lds

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 04/10] lib: packing: document recently added APIs
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
                   ` (2 preceding siblings ...)
  2024-12-03 23:53 ` [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields() Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-04 23:26   ` Vladimir Oltean
  2024-12-04 23:31   ` Vladimir Oltean
  2024-12-03 23:53 ` [PATCH net-next v8 05/10] ice: remove int_q_state from ice_tlan_ctx Jacob Keller
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

Extend the documentation for the packing library, covering the intended use
for the recently added APIs. This includes the pack() and unpack() macros,
as well as the pack_fields() and unpack_fields() macros.

Add a note that the packing() API is now deprecated in favor of pack() and
unpack().

For the pack_fields() and unpack_fields() APIs, explain the rationale for
when a driver may want to select this API. Provide an example which shows
how to define the fields and call the pack_fields() and unpack_fields()
macros.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 Documentation/core-api/packing.rst | 118 +++++++++++++++++++++++++++++++++++--
 1 file changed, 113 insertions(+), 5 deletions(-)

diff --git a/Documentation/core-api/packing.rst b/Documentation/core-api/packing.rst
index 821691f23c541cee27995bb1d77e23ff04f82433..30fc2328f789920e27a1bcf3945a6793894ef1d4 100644
--- a/Documentation/core-api/packing.rst
+++ b/Documentation/core-api/packing.rst
@@ -227,11 +227,119 @@ Intended use
 
 Drivers that opt to use this API first need to identify which of the above 3
 quirk combinations (for a total of 8) match what the hardware documentation
-describes. Then they should wrap the packing() function, creating a new
-xxx_packing() that calls it using the proper QUIRK_* one-hot bits set.
+describes.
+
+There are 3 supported usage patterns, detailed below.
+
+packing()
+^^^^^^^^^
+
+This API function is deprecated.
 
 The packing() function returns an int-encoded error code, which protects the
 programmer against incorrect API use.  The errors are not expected to occur
-during runtime, therefore it is reasonable for xxx_packing() to return void
-and simply swallow those errors. Optionally it can dump stack or print the
-error description.
+during runtime, therefore it is reasonable to wrap packing() into a custom
+function which returns void and simply swallow those errors. Optionally it can
+dump stack or print the error description.
+
+.. code-block:: c
+
+  void my_packing(void *buf, u64 *val, int startbit, int endbit,
+                  size_t len, enum packing_op op)
+  {
+          int err;
+
+          /* Adjust quirks accordingly */
+          err = packing(buf, val, startbit, endbit, len, op, QUIRK_LSW32_IS_FIRST);
+          if (likely(!err))
+                  return;
+
+          if (err == -EINVAL) {
+                  pr_err("Start bit (%d) expected to be larger than end (%d)\n",
+                         startbit, endbit);
+          } else if (err == -ERANGE) {
+                  if ((startbit - endbit + 1) > 64)
+                          pr_err("Field %d-%d too large for 64 bits!\n",
+                                 startbit, endbit);
+                  else
+                          pr_err("Cannot store %llx inside bits %d-%d (would truncate)\n",
+                                 *val, startbit, endbit);
+          }
+          dump_stack();
+  }
+
+pack() and unpack()
+^^^^^^^^^^^^^^^^^^^
+
+These are const-correct variants of packing(), and eliminate the last "enum
+packing_op op" argument.
+
+Calling pack(...) is equivalent, and preferred, to calling packing(..., PACK).
+
+Calling unpack(...) is equivalent, and preferred, to calling packing(..., UNPACK).
+
+pack_fields() and unpack_fields()
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The library exposes optimized functions for the scenario where there are many
+fields represented in a buffer, and it encourages consumer drivers to avoid
+repetitive calls to pack() and unpack() for each field, but instead use
+pack_fields() and unpack_fields(), which reduces the code footprint.
+
+These APIs use field definitions in arrays of ``struct packed_field_s`` (small)
+or ``struct packed_field_m`` (medium), allowing consumer drivers to minimize
+the size of these arrays according to their custom requirements.
+
+The pack_fields() and unpack_fields() API functions are actually macros which
+automatically select the appropriate function at compile time, based on the
+type of the fields array passed in.
+
+An additional benefit over pack() and unpack() is that sanity checks on the
+field definitions are handled at compile time with ``BUILD_BUG_ON`` rather
+than only when the offending code is executed. These functions return void and
+wrapping them to handle unexpected errors is not necessary.
+
+It is recommended, but not required, that you wrap your packed buffer into a
+structured type with a fixed size. This generally makes it easier for the
+compiler to enforce that the correct size buffer is used.
+
+Here is an example of how to use the fields APIs:
+
+.. code-block:: c
+
+   /* Ordering inside the unpacked structure is flexible and can be different
+    * from the packed buffer. Here, it is optimized to reduce padding.
+    */
+   struct data {
+        u64 field3;
+        u32 field4;
+        u16 field1;
+        u8 field2;
+   };
+
+   #define SIZE 13
+
+   typdef struct __packed { u8 buf[SIZE]; } packed_buf_t;
+
+   static const struct packed_field_s fields[] = {
+           PACKED_FIELD(100, 90, struct data, field1),
+           PACKED_FIELD(90, 87, struct data, field2),
+           PACKED_FIELD(86, 30, struct data, field3),
+           PACKED_FIELD(29, 0, struct data, field4),
+   };
+
+   void unpack_your_data(const packed_buf_t *buf, struct data *unpacked)
+   {
+           BUILD_BUG_ON(sizeof(*buf) != SIZE;
+
+           unpack_fields(buf, sizeof(*buf), unpacked, fields,
+                         QUIRK_LITTLE_ENDIAN);
+   }
+
+   void pack_your_data(const struct data *unpacked, packed_buf_t *buf)
+   {
+           BUILD_BUG_ON(sizeof(*buf) != SIZE;
+
+           pack_fields(buf, sizeof(*buf), unpacked, fields,
+                       QUIRK_LITTLE_ENDIAN);
+   }

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 05/10] ice: remove int_q_state from ice_tlan_ctx
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
                   ` (3 preceding siblings ...)
  2024-12-03 23:53 ` [PATCH net-next v8 04/10] lib: packing: document recently added APIs Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 06/10] ice: use structures to keep track of queue context size Jacob Keller
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

The int_q_state field of the ice_tlan_ctx structure represents the internal
queue state. However, we never actually need to assign this or read this
during normal operation. In fact, trying to unpack it would not be possible
as it is larger than a u64. Remove this field from the ice_tlan_ctx
structure, and remove its packing field from the ice_tlan_ctx_info array.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h | 1 -
 drivers/net/ethernet/intel/ice/ice_common.c    | 1 -
 2 files changed, 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
index 611577ebc29d8250c8cce85f58f3477ff3b51a66..0e8ed8c226e68988664d64c1fd3297cee32af020 100644
--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
@@ -590,7 +590,6 @@ struct ice_tlan_ctx {
 	u8 drop_ena;
 	u8 cache_prof_idx;
 	u8 pkt_shaper_prof_idx;
-	u8 int_q_state;	/* width not needed - internal - DO NOT WRITE!!! */
 };
 
 #endif /* _ICE_LAN_TX_RX_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index b22e71dc59d4e4ec0efea96e5afd812859a98bdd..0f5a80269a7be0a302d4229a42bb8bbfc500905a 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1467,7 +1467,6 @@ const struct ice_ctx_ele ice_tlan_ctx_info[] = {
 	ICE_CTX_STORE(ice_tlan_ctx, drop_ena,			1,	165),
 	ICE_CTX_STORE(ice_tlan_ctx, cache_prof_idx,		2,	166),
 	ICE_CTX_STORE(ice_tlan_ctx, pkt_shaper_prof_idx,	3,	168),
-	ICE_CTX_STORE(ice_tlan_ctx, int_q_state,		122,	171),
 	{ 0 }
 };
 

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 06/10] ice: use structures to keep track of queue context size
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
                   ` (4 preceding siblings ...)
  2024-12-03 23:53 ` [PATCH net-next v8 05/10] ice: remove int_q_state from ice_tlan_ctx Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 07/10] ice: use <linux/packing.h> for Tx and Rx queue context data Jacob Keller
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

The ice Tx and Rx queue context are currently stored as arrays of bytes
with defined size (ICE_RXQ_CTX_SZ and ICE_TXQ_CTX_SZ). The packed queue
context is often passed to other functions as a simple u8 * pointer, which
does not allow tracking the size. This makes the queue context API easy to
misuse, as you can pass an arbitrary u8 array or pointer.

Introduce wrapper typedefs which use a __packed structure that has the
proper fixed size for the Tx and Rx context buffers. This enables the
compiler to track the size of the value and ensures that passing the wrong
buffer size will be detected by the compiler.

The existing APIs do not benefit much from this change, however the
wrapping structures will be used to simplify the arguments of new packing
functions based on the recently introduced pack_fields API.

Co-developed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 11 +++++++++--
 drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h  |  2 --
 drivers/net/ethernet/intel/ice/ice_base.c       |  2 +-
 drivers/net/ethernet/intel/ice/ice_common.c     | 24 +++++++++++-------------
 4 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index 1489a8ceec51df890f481f7fdc04b1845ca85255..3bf05b135b3557e5867ef037d02621a59dc251d4 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -12,6 +12,13 @@
 #define ICE_AQC_TOPO_MAX_LEVEL_NUM	0x9
 #define ICE_AQ_SET_MAC_FRAME_SIZE_MAX	9728
 
+#define ICE_RXQ_CTX_SIZE_DWORDS		8
+#define ICE_RXQ_CTX_SZ			(ICE_RXQ_CTX_SIZE_DWORDS * sizeof(u32))
+#define ICE_TXQ_CTX_SZ			22
+
+typedef struct __packed { u8 buf[ICE_RXQ_CTX_SZ]; } ice_rxq_ctx_buf_t;
+typedef struct __packed { u8 buf[ICE_TXQ_CTX_SZ]; } ice_txq_ctx_buf_t;
+
 struct ice_aqc_generic {
 	__le32 param0;
 	__le32 param1;
@@ -2084,10 +2091,10 @@ struct ice_aqc_add_txqs_perq {
 	__le16 txq_id;
 	u8 rsvd[2];
 	__le32 q_teid;
-	u8 txq_ctx[22];
+	ice_txq_ctx_buf_t txq_ctx;
 	u8 rsvd2[2];
 	struct ice_aqc_txsched_elem info;
-};
+} __packed;
 
 /* The format of the command buffer for Add Tx LAN Queues (0x0C30)
  * is an array of the following structs. Please note that the length of
diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
index 0e8ed8c226e68988664d64c1fd3297cee32af020..a76e5b0e7861e39e59013637cb176f67d1f7ef15 100644
--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
@@ -371,8 +371,6 @@ enum ice_rx_flex_desc_status_error_1_bits {
 	ICE_RX_FLEX_DESC_STATUS1_LAST /* this entry must be last!!! */
 };
 
-#define ICE_RXQ_CTX_SIZE_DWORDS		8
-#define ICE_RXQ_CTX_SZ			(ICE_RXQ_CTX_SIZE_DWORDS * sizeof(u32))
 #define ICE_TX_CMPLTNQ_CTX_SIZE_DWORDS	22
 #define ICE_TX_DRBELL_Q_CTX_SIZE_DWORDS	5
 #define GLTCLAN_CQ_CNTX(i, CQ)		(GLTCLAN_CQ_CNTX0(CQ) + ((i) * 0x0800))
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 82a9cd4ec7aec90febdc7ab31cf8d707314cbd1f..e7aaa06241210e764b4cb627031310e4fd5b6520 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -910,7 +910,7 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
 	ice_setup_tx_ctx(ring, &tlan_ctx, pf_q);
 	/* copy context contents into the qg_buf */
 	qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q);
-	ice_set_ctx(hw, (u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx,
+	ice_set_ctx(hw, (u8 *)&tlan_ctx, (u8 *)&qg_buf->txqs[0].txq_ctx,
 		    ice_tlan_ctx_info);
 
 	/* init queue specific tail reg. It is referred as
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 0f5a80269a7be0a302d4229a42bb8bbfc500905a..48d95cb49864ad73769487d2b95b2e8306156cf9 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1359,29 +1359,27 @@ int ice_reset(struct ice_hw *hw, enum ice_reset_req req)
 /**
  * ice_copy_rxq_ctx_to_hw
  * @hw: pointer to the hardware structure
- * @ice_rxq_ctx: pointer to the rxq context
+ * @rxq_ctx: pointer to the packed Rx queue context
  * @rxq_index: the index of the Rx queue
  *
  * Copies rxq context from dense structure to HW register space
  */
-static int
-ice_copy_rxq_ctx_to_hw(struct ice_hw *hw, u8 *ice_rxq_ctx, u32 rxq_index)
+static int ice_copy_rxq_ctx_to_hw(struct ice_hw *hw,
+				  const ice_rxq_ctx_buf_t *rxq_ctx,
+				  u32 rxq_index)
 {
 	u8 i;
 
-	if (!ice_rxq_ctx)
-		return -EINVAL;
-
 	if (rxq_index > QRX_CTRL_MAX_INDEX)
 		return -EINVAL;
 
 	/* Copy each dword separately to HW */
 	for (i = 0; i < ICE_RXQ_CTX_SIZE_DWORDS; i++) {
-		wr32(hw, QRX_CONTEXT(i, rxq_index),
-		     *((u32 *)(ice_rxq_ctx + (i * sizeof(u32)))));
+		u32 ctx = ((const u32 *)rxq_ctx)[i];
 
-		ice_debug(hw, ICE_DBG_QCTX, "qrxdata[%d]: %08X\n", i,
-			  *((u32 *)(ice_rxq_ctx + (i * sizeof(u32)))));
+		wr32(hw, QRX_CONTEXT(i, rxq_index), ctx);
+
+		ice_debug(hw, ICE_DBG_QCTX, "qrxdata[%d]: %08X\n", i, ctx);
 	}
 
 	return 0;
@@ -1426,15 +1424,15 @@ static const struct ice_ctx_ele ice_rlan_ctx_info[] = {
 int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
 		      u32 rxq_index)
 {
-	u8 ctx_buf[ICE_RXQ_CTX_SZ] = { 0 };
+	ice_rxq_ctx_buf_t buf = {};
 
 	if (!rlan_ctx)
 		return -EINVAL;
 
 	rlan_ctx->prefena = 1;
 
-	ice_set_ctx(hw, (u8 *)rlan_ctx, ctx_buf, ice_rlan_ctx_info);
-	return ice_copy_rxq_ctx_to_hw(hw, ctx_buf, rxq_index);
+	ice_set_ctx(hw, (u8 *)rlan_ctx, (u8 *)&buf, ice_rlan_ctx_info);
+	return ice_copy_rxq_ctx_to_hw(hw, &buf, rxq_index);
 }
 
 /* LAN Tx Queue Context */

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 07/10] ice: use <linux/packing.h> for Tx and Rx queue context data
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
                   ` (5 preceding siblings ...)
  2024-12-03 23:53 ` [PATCH net-next v8 06/10] ice: use structures to keep track of queue context size Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 08/10] ice: reduce size of queue context fields Jacob Keller
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

The ice driver needs to write the Tx and Rx queue context when programming
Tx and Rx queues. This is currently done using some bespoke custom logic
via the ice_set_ctx() and its helper functions, along with bit position
definitions in the ice_tlan_ctx_info and ice_rlan_ctx_info structures.

This logic does work, but is problematic for several reasons:

1) ice_set_ctx requires a helper function for each byte size being packed,
   as it uses a separate function to pack u8, u16, u32, and u64 fields.
   This requires 4 functions which contain near-duplicate logic with the
   types changed out.

2) The logic in the ice_pack_ctx_word, ice_pack_ctx_dword, and
   ice_pack_ctx_qword does not handle values which straddle alignment
   boundaries very well. This requires that several fields in the
   ice_tlan_ctx_info and ice_rlan_ctx_info be a size larger than their bit
   size should require.

3) Future support for live migration will require adding unpacking
   functions to take the packed hardware context and unpack it into the
   ice_rlan_ctx and ice_tlan_ctx structures. Implementing this would
   require implementing ice_get_ctx, and its associated helper functions,
   which essentially doubles the amount of code required.

The Linux kernel has had a packing library that can handle this logic since
commit 554aae35007e ("lib: Add support for generic packing operations").
The library was recently extended with support for packing or unpacking an
array of fields, with a similar structure as the ice_ctx_ele structure.

Replace the ice-specific ice_set_ctx() logic with the recently added
pack_fields and packed_field_s infrastructure from <linux/packing.h>

For API simplicity, the Tx and Rx queue context are programmed using
separate ice_pack_txq_ctx() and ice_pack_rxq_ctx(). This avoids needing to
export the packed_field_s arrays. The functions can pointers to the
appropriate ice_txq_ctx_buf_t and ice_rxq_ctx_buf_t types, ensuring that
only buffers of the appropriate size are passed.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_common.h    |   5 +-
 drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h |  14 --
 drivers/net/ethernet/intel/ice/ice_base.c      |   3 +-
 drivers/net/ethernet/intel/ice/ice_common.c    | 243 ++++---------------------
 drivers/net/ethernet/intel/Kconfig             |   1 +
 5 files changed, 42 insertions(+), 224 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 27208a60cece51f49d928a09ec6e9dcbb27fb9b1..a68bea3934e35a270a9809239fdf2f5cdce7b6bd 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -92,9 +92,8 @@ ice_aq_set_rss_key(struct ice_hw *hw, u16 vsi_handle,
 bool ice_check_sq_alive(struct ice_hw *hw, struct ice_ctl_q_info *cq);
 int ice_aq_q_shutdown(struct ice_hw *hw, bool unloading);
 void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode);
-extern const struct ice_ctx_ele ice_tlan_ctx_info[];
-int ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx,
-		const struct ice_ctx_ele *ce_info);
+
+void ice_pack_txq_ctx(const struct ice_tlan_ctx *ctx, ice_txq_ctx_buf_t *buf);
 
 extern struct mutex ice_global_cfg_lock_sw;
 
diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
index a76e5b0e7861e39e59013637cb176f67d1f7ef15..31d4a445d640df21c2aa007ffbd4f2310da264ad 100644
--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
@@ -408,20 +408,6 @@ struct ice_rlan_ctx {
 	u8 prefena;	/* NOTE: normally must be set to 1 at init */
 };
 
-struct ice_ctx_ele {
-	u16 offset;
-	u16 size_of;
-	u16 width;
-	u16 lsb;
-};
-
-#define ICE_CTX_STORE(_struct, _ele, _width, _lsb) {	\
-	.offset = offsetof(struct _struct, _ele),	\
-	.size_of = sizeof_field(struct _struct, _ele),	\
-	.width = _width,				\
-	.lsb = _lsb,					\
-}
-
 /* for hsplit_0 field of Rx RLAN context */
 enum ice_rlan_ctx_rx_hsplit_0 {
 	ICE_RLAN_RX_HSPLIT_0_NO_SPLIT		= 0,
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index e7aaa06241210e764b4cb627031310e4fd5b6520..5fe7b5a100202e6f0c33c617c604d45f9487b1f4 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -910,8 +910,7 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_tx_ring *ring,
 	ice_setup_tx_ctx(ring, &tlan_ctx, pf_q);
 	/* copy context contents into the qg_buf */
 	qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q);
-	ice_set_ctx(hw, (u8 *)&tlan_ctx, (u8 *)&qg_buf->txqs[0].txq_ctx,
-		    ice_tlan_ctx_info);
+	ice_pack_txq_ctx(&tlan_ctx, &qg_buf->txqs[0].txq_ctx);
 
 	/* init queue specific tail reg. It is referred as
 	 * transmit comm scheduler queue doorbell.
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 48d95cb49864ad73769487d2b95b2e8306156cf9..1b013c9c937826633db8cbe29d8e1dc310c7b6f0 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -6,6 +6,7 @@
 #include "ice_adminq_cmd.h"
 #include "ice_flow.h"
 #include "ice_ptp_hw.h"
+#include <linux/packing.h>
 
 #define ICE_PF_RESET_WAIT_COUNT	300
 #define ICE_MAX_NETLIST_SIZE	10
@@ -1385,9 +1386,12 @@ static int ice_copy_rxq_ctx_to_hw(struct ice_hw *hw,
 	return 0;
 }
 
+#define ICE_CTX_STORE(struct_name, struct_field, width, lsb) \
+	PACKED_FIELD((lsb) + (width) - 1, (lsb), struct struct_name, struct_field)
+
 /* LAN Rx Queue Context */
-static const struct ice_ctx_ele ice_rlan_ctx_info[] = {
-	/* Field		Width	LSB */
+static const struct packed_field_s ice_rlan_ctx_fields[] = {
+				 /* Field		Width	LSB */
 	ICE_CTX_STORE(ice_rlan_ctx, head,		13,	0),
 	ICE_CTX_STORE(ice_rlan_ctx, cpuid,		8,	13),
 	ICE_CTX_STORE(ice_rlan_ctx, base,		57,	32),
@@ -1408,9 +1412,23 @@ static const struct ice_ctx_ele ice_rlan_ctx_info[] = {
 	ICE_CTX_STORE(ice_rlan_ctx, tphhead_ena,	1,	196),
 	ICE_CTX_STORE(ice_rlan_ctx, lrxqthresh,		3,	198),
 	ICE_CTX_STORE(ice_rlan_ctx, prefena,		1,	201),
-	{ 0 }
 };
 
+/**
+ * ice_pack_rxq_ctx - Pack Rx queue context into a HW buffer
+ * @ctx: the Rx queue context to pack
+ * @buf: the HW buffer to pack into
+ *
+ * Pack the Rx queue context from the CPU-friendly unpacked buffer into its
+ * bit-packed HW layout.
+ */
+static void ice_pack_rxq_ctx(const struct ice_rlan_ctx *ctx,
+			     ice_rxq_ctx_buf_t *buf)
+{
+	pack_fields(buf, sizeof(*buf), ctx, ice_rlan_ctx_fields,
+		    QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST);
+}
+
 /**
  * ice_write_rxq_ctx
  * @hw: pointer to the hardware structure
@@ -1431,12 +1449,13 @@ int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
 
 	rlan_ctx->prefena = 1;
 
-	ice_set_ctx(hw, (u8 *)rlan_ctx, (u8 *)&buf, ice_rlan_ctx_info);
+	ice_pack_rxq_ctx(rlan_ctx, &buf);
+
 	return ice_copy_rxq_ctx_to_hw(hw, &buf, rxq_index);
 }
 
 /* LAN Tx Queue Context */
-const struct ice_ctx_ele ice_tlan_ctx_info[] = {
+static const struct packed_field_s ice_tlan_ctx_fields[] = {
 				    /* Field			Width	LSB */
 	ICE_CTX_STORE(ice_tlan_ctx, base,			57,	0),
 	ICE_CTX_STORE(ice_tlan_ctx, port_num,			3,	57),
@@ -1465,9 +1484,22 @@ const struct ice_ctx_ele ice_tlan_ctx_info[] = {
 	ICE_CTX_STORE(ice_tlan_ctx, drop_ena,			1,	165),
 	ICE_CTX_STORE(ice_tlan_ctx, cache_prof_idx,		2,	166),
 	ICE_CTX_STORE(ice_tlan_ctx, pkt_shaper_prof_idx,	3,	168),
-	{ 0 }
 };
 
+/**
+ * ice_pack_txq_ctx - Pack Tx queue context into a HW buffer
+ * @ctx: the Tx queue context to pack
+ * @buf: the HW buffer to pack into
+ *
+ * Pack the Tx queue context from the CPU-friendly unpacked buffer into its
+ * bit-packed HW layout.
+ */
+void ice_pack_txq_ctx(const struct ice_tlan_ctx *ctx, ice_txq_ctx_buf_t *buf)
+{
+	pack_fields(buf, sizeof(*buf), ctx, ice_tlan_ctx_fields,
+		    QUIRK_LITTLE_ENDIAN | QUIRK_LSW32_IS_FIRST);
+}
+
 /* Sideband Queue command wrappers */
 
 /**
@@ -4545,205 +4577,6 @@ ice_aq_add_rdma_qsets(struct ice_hw *hw, u8 num_qset_grps,
 
 /* End of FW Admin Queue command wrappers */
 
-/**
- * ice_pack_ctx_byte - write a byte to a packed context structure
- * @src_ctx: unpacked source context structure
- * @dest_ctx: packed destination context data
- * @ce_info: context element description
- */
-static void ice_pack_ctx_byte(u8 *src_ctx, u8 *dest_ctx,
-			      const struct ice_ctx_ele *ce_info)
-{
-	u8 src_byte, dest_byte, mask;
-	u8 *from, *dest;
-	u16 shift_width;
-
-	/* copy from the next struct field */
-	from = src_ctx + ce_info->offset;
-
-	/* prepare the bits and mask */
-	shift_width = ce_info->lsb % 8;
-	mask = GENMASK(ce_info->width - 1 + shift_width, shift_width);
-
-	src_byte = *from;
-	src_byte <<= shift_width;
-	src_byte &= mask;
-
-	/* get the current bits from the target bit string */
-	dest = dest_ctx + (ce_info->lsb / 8);
-
-	memcpy(&dest_byte, dest, sizeof(dest_byte));
-
-	dest_byte &= ~mask;	/* get the bits not changing */
-	dest_byte |= src_byte;	/* add in the new bits */
-
-	/* put it all back */
-	memcpy(dest, &dest_byte, sizeof(dest_byte));
-}
-
-/**
- * ice_pack_ctx_word - write a word to a packed context structure
- * @src_ctx: unpacked source context structure
- * @dest_ctx: packed destination context data
- * @ce_info: context element description
- */
-static void ice_pack_ctx_word(u8 *src_ctx, u8 *dest_ctx,
-			      const struct ice_ctx_ele *ce_info)
-{
-	u16 src_word, mask;
-	__le16 dest_word;
-	u8 *from, *dest;
-	u16 shift_width;
-
-	/* copy from the next struct field */
-	from = src_ctx + ce_info->offset;
-
-	/* prepare the bits and mask */
-	shift_width = ce_info->lsb % 8;
-	mask = GENMASK(ce_info->width - 1 + shift_width, shift_width);
-
-	/* don't swizzle the bits until after the mask because the mask bits
-	 * will be in a different bit position on big endian machines
-	 */
-	src_word = *(u16 *)from;
-	src_word <<= shift_width;
-	src_word &= mask;
-
-	/* get the current bits from the target bit string */
-	dest = dest_ctx + (ce_info->lsb / 8);
-
-	memcpy(&dest_word, dest, sizeof(dest_word));
-
-	dest_word &= ~(cpu_to_le16(mask));	/* get the bits not changing */
-	dest_word |= cpu_to_le16(src_word);	/* add in the new bits */
-
-	/* put it all back */
-	memcpy(dest, &dest_word, sizeof(dest_word));
-}
-
-/**
- * ice_pack_ctx_dword - write a dword to a packed context structure
- * @src_ctx: unpacked source context structure
- * @dest_ctx: packed destination context data
- * @ce_info: context element description
- */
-static void ice_pack_ctx_dword(u8 *src_ctx, u8 *dest_ctx,
-			       const struct ice_ctx_ele *ce_info)
-{
-	u32 src_dword, mask;
-	__le32 dest_dword;
-	u8 *from, *dest;
-	u16 shift_width;
-
-	/* copy from the next struct field */
-	from = src_ctx + ce_info->offset;
-
-	/* prepare the bits and mask */
-	shift_width = ce_info->lsb % 8;
-	mask = GENMASK(ce_info->width - 1 + shift_width, shift_width);
-
-	/* don't swizzle the bits until after the mask because the mask bits
-	 * will be in a different bit position on big endian machines
-	 */
-	src_dword = *(u32 *)from;
-	src_dword <<= shift_width;
-	src_dword &= mask;
-
-	/* get the current bits from the target bit string */
-	dest = dest_ctx + (ce_info->lsb / 8);
-
-	memcpy(&dest_dword, dest, sizeof(dest_dword));
-
-	dest_dword &= ~(cpu_to_le32(mask));	/* get the bits not changing */
-	dest_dword |= cpu_to_le32(src_dword);	/* add in the new bits */
-
-	/* put it all back */
-	memcpy(dest, &dest_dword, sizeof(dest_dword));
-}
-
-/**
- * ice_pack_ctx_qword - write a qword to a packed context structure
- * @src_ctx: unpacked source context structure
- * @dest_ctx: packed destination context data
- * @ce_info: context element description
- */
-static void ice_pack_ctx_qword(u8 *src_ctx, u8 *dest_ctx,
-			       const struct ice_ctx_ele *ce_info)
-{
-	u64 src_qword, mask;
-	__le64 dest_qword;
-	u8 *from, *dest;
-	u16 shift_width;
-
-	/* copy from the next struct field */
-	from = src_ctx + ce_info->offset;
-
-	/* prepare the bits and mask */
-	shift_width = ce_info->lsb % 8;
-	mask = GENMASK_ULL(ce_info->width - 1 + shift_width, shift_width);
-
-	/* don't swizzle the bits until after the mask because the mask bits
-	 * will be in a different bit position on big endian machines
-	 */
-	src_qword = *(u64 *)from;
-	src_qword <<= shift_width;
-	src_qword &= mask;
-
-	/* get the current bits from the target bit string */
-	dest = dest_ctx + (ce_info->lsb / 8);
-
-	memcpy(&dest_qword, dest, sizeof(dest_qword));
-
-	dest_qword &= ~(cpu_to_le64(mask));	/* get the bits not changing */
-	dest_qword |= cpu_to_le64(src_qword);	/* add in the new bits */
-
-	/* put it all back */
-	memcpy(dest, &dest_qword, sizeof(dest_qword));
-}
-
-/**
- * ice_set_ctx - set context bits in packed structure
- * @hw: pointer to the hardware structure
- * @src_ctx:  pointer to a generic non-packed context structure
- * @dest_ctx: pointer to memory for the packed structure
- * @ce_info: List of Rx context elements
- */
-int ice_set_ctx(struct ice_hw *hw, u8 *src_ctx, u8 *dest_ctx,
-		const struct ice_ctx_ele *ce_info)
-{
-	int f;
-
-	for (f = 0; ce_info[f].width; f++) {
-		/* We have to deal with each element of the FW response
-		 * using the correct size so that we are correct regardless
-		 * of the endianness of the machine.
-		 */
-		if (ce_info[f].width > (ce_info[f].size_of * BITS_PER_BYTE)) {
-			ice_debug(hw, ICE_DBG_QCTX, "Field %d width of %d bits larger than size of %d byte(s) ... skipping write\n",
-				  f, ce_info[f].width, ce_info[f].size_of);
-			continue;
-		}
-		switch (ce_info[f].size_of) {
-		case sizeof(u8):
-			ice_pack_ctx_byte(src_ctx, dest_ctx, &ce_info[f]);
-			break;
-		case sizeof(u16):
-			ice_pack_ctx_word(src_ctx, dest_ctx, &ce_info[f]);
-			break;
-		case sizeof(u32):
-			ice_pack_ctx_dword(src_ctx, dest_ctx, &ce_info[f]);
-			break;
-		case sizeof(u64):
-			ice_pack_ctx_qword(src_ctx, dest_ctx, &ce_info[f]);
-			break;
-		default:
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-
 /**
  * ice_get_lan_q_ctx - get the LAN queue context for the given VSI and TC
  * @hw: pointer to the HW struct
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 20bc40eec487a3449ff1ac7432b2b029cb2b1155..24ec9a4f1ffa88ef550d4a552f6cd7a2f84dd83a 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -292,6 +292,7 @@ config ICE
 	select DIMLIB
 	select LIBIE
 	select NET_DEVLINK
+	select PACKING
 	select PLDMFW
 	select DPLL
 	help

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 08/10] ice: reduce size of queue context fields
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
                   ` (6 preceding siblings ...)
  2024-12-03 23:53 ` [PATCH net-next v8 07/10] ice: use <linux/packing.h> for Tx and Rx queue context data Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 09/10] ice: move prefetch enable to ice_setup_rx_ctx Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 10/10] ice: cleanup Rx queue context programming functions Jacob Keller
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

The ice_rlan_ctx and ice_tlan_ctx structures have some fields which are
intentionally sized larger than necessary relative to the packed sizes the
data must fit into. This was done because the original ice_set_ctx()
function and its helpers did not correctly handle packing when the packed
bits straddled a byte. This is no longer the case with the use of the
<linux/packing.h> implementation.

Save some bytes in these structures by sizing the variables to the number
of bytes the actual bitpacked fields fit into.

There are a couple of gaps left in the structure, which is a result of the
fields being in the order they appear in the packed bit layout, but where
alignment forces some extra gaps. We could fix this, saving ~8 bytes from
each structure. However, these structures are not used heavily, and the
resulting savings is minimal:

$ bloat-o-meter ice-before-reorder.ko ice-after-reorder.ko
add/remove: 0/0 grow/shrink: 1/1 up/down: 26/-70 (-44)
Function                                     old     new   delta
ice_vsi_cfg_txq                             1873    1899     +26
ice_setup_rx_ctx.constprop                  1529    1459     -70
Total: Before=1459555, After=1459511, chg -0.00%

Thus, the fields are left in the same order as the packed bit layout,
despite the gaps this causes.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h | 32 ++++++++------------------
 1 file changed, 10 insertions(+), 22 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
index 31d4a445d640df21c2aa007ffbd4f2310da264ad..1479b45738af15bf6e00aed24b2c6a3f91675f4d 100644
--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
@@ -375,23 +375,17 @@ enum ice_rx_flex_desc_status_error_1_bits {
 #define ICE_TX_DRBELL_Q_CTX_SIZE_DWORDS	5
 #define GLTCLAN_CQ_CNTX(i, CQ)		(GLTCLAN_CQ_CNTX0(CQ) + ((i) * 0x0800))
 
-/* RLAN Rx queue context data
- *
- * The sizes of the variables may be larger than needed due to crossing byte
- * boundaries. If we do not have the width of the variable set to the correct
- * size then we could end up shifting bits off the top of the variable when the
- * variable is at the top of a byte and crosses over into the next byte.
- */
+/* RLAN Rx queue context data */
 struct ice_rlan_ctx {
 	u16 head;
-	u16 cpuid; /* bigger than needed, see above for reason */
+	u8 cpuid;
 #define ICE_RLAN_BASE_S 7
 	u64 base;
 	u16 qlen;
 #define ICE_RLAN_CTX_DBUF_S 7
-	u16 dbuf; /* bigger than needed, see above for reason */
+	u8 dbuf;
 #define ICE_RLAN_CTX_HBUF_S 6
-	u16 hbuf; /* bigger than needed, see above for reason */
+	u8 hbuf;
 	u8 dtype;
 	u8 dsize;
 	u8 crcstrip;
@@ -399,12 +393,12 @@ struct ice_rlan_ctx {
 	u8 hsplit_0;
 	u8 hsplit_1;
 	u8 showiv;
-	u32 rxmax; /* bigger than needed, see above for reason */
+	u16 rxmax;
 	u8 tphrdesc_ena;
 	u8 tphwdesc_ena;
 	u8 tphdata_ena;
 	u8 tphhead_ena;
-	u16 lrxqthresh; /* bigger than needed, see above for reason */
+	u8 lrxqthresh;
 	u8 prefena;	/* NOTE: normally must be set to 1 at init */
 };
 
@@ -535,18 +529,12 @@ enum ice_tx_ctx_desc_eipt_offload {
 #define ICE_LAN_TXQ_MAX_QGRPS	127
 #define ICE_LAN_TXQ_MAX_QDIS	1023
 
-/* Tx queue context data
- *
- * The sizes of the variables may be larger than needed due to crossing byte
- * boundaries. If we do not have the width of the variable set to the correct
- * size then we could end up shifting bits off the top of the variable when the
- * variable is at the top of a byte and crosses over into the next byte.
- */
+/* Tx queue context data */
 struct ice_tlan_ctx {
 #define ICE_TLAN_CTX_BASE_S	7
 	u64 base;		/* base is defined in 128-byte units */
 	u8 port_num;
-	u16 cgd_num;		/* bigger than needed, see above for reason */
+	u8 cgd_num;
 	u8 pf_num;
 	u16 vmvf_num;
 	u8 vmvf_type;
@@ -557,7 +545,7 @@ struct ice_tlan_ctx {
 	u8 tsyn_ena;
 	u8 internal_usage_flag;
 	u8 alt_vlan;
-	u16 cpuid;		/* bigger than needed, see above for reason */
+	u8 cpuid;
 	u8 wb_mode;
 	u8 tphrd_desc;
 	u8 tphrd;
@@ -566,7 +554,7 @@ struct ice_tlan_ctx {
 	u16 qnum_in_func;
 	u8 itr_notification_mode;
 	u8 adjust_prof_id;
-	u32 qlen;		/* bigger than needed, see above for reason */
+	u16 qlen;
 	u8 quanta_prof_idx;
 	u8 tso_ena;
 	u16 tso_qnum;

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 09/10] ice: move prefetch enable to ice_setup_rx_ctx
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
                   ` (7 preceding siblings ...)
  2024-12-03 23:53 ` [PATCH net-next v8 08/10] ice: reduce size of queue context fields Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  2024-12-03 23:53 ` [PATCH net-next v8 10/10] ice: cleanup Rx queue context programming functions Jacob Keller
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

The ice_write_rxq_ctx() function is responsible for programming the Rx
Queue context into hardware. It receives the configuration in unpacked form
via the ice_rlan_ctx structure.

This function unconditionally modifies the context to set the prefetch
enable bit. This was done by commit c31a5c25bb19 ("ice: Always set prefena
when configuring an Rx queue"). Setting this bit makes sense, since
prefetching descriptors is almost always the preferred behavior.

However, the ice_write_rxq_ctx() function is not the place that actually
defines the queue context. We initialize the Rx Queue context in
ice_setup_rx_ctx(). It is surprising to have the Rx queue context changed
by a function who's responsibility is to program the given context to
hardware.

Following the principle of least surprise, move the setting of the prefetch
enable bit out of ice_write_rxq_ctx() and into the ice_setup_rx_ctx().

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_base.c   | 3 +++
 drivers/net/ethernet/intel/ice/ice_common.c | 9 +++------
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 5fe7b5a100202e6f0c33c617c604d45f9487b1f4..b2af8e3586f7620d372f2055e337485d102d3cbc 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -454,6 +454,9 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
 	/* Rx queue threshold in units of 64 */
 	rlan_ctx.lrxqthresh = 1;
 
+	/* Enable descriptor prefetch */
+	rlan_ctx.prefena = 1;
+
 	/* PF acts as uplink for switchdev; set flex descriptor with src_vsi
 	 * metadata and flags to allow redirecting to PR netdev
 	 */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 1b013c9c937826633db8cbe29d8e1dc310c7b6f0..379040593d975342eaa2a3032938683b419f4f60 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1430,14 +1430,13 @@ static void ice_pack_rxq_ctx(const struct ice_rlan_ctx *ctx,
 }
 
 /**
- * ice_write_rxq_ctx
+ * ice_write_rxq_ctx - Write Rx Queue context to hardware
  * @hw: pointer to the hardware structure
  * @rlan_ctx: pointer to the rxq context
  * @rxq_index: the index of the Rx queue
  *
- * Converts rxq context from sparse to dense structure and then writes
- * it to HW register space and enables the hardware to prefetch descriptors
- * instead of only fetching them on demand
+ * Pack the sparse Rx Queue context into dense hardware format and write it
+ * into the HW register space.
  */
 int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
 		      u32 rxq_index)
@@ -1447,8 +1446,6 @@ int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
 	if (!rlan_ctx)
 		return -EINVAL;
 
-	rlan_ctx->prefena = 1;
-
 	ice_pack_rxq_ctx(rlan_ctx, &buf);
 
 	return ice_copy_rxq_ctx_to_hw(hw, &buf, rxq_index);

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH net-next v8 10/10] ice: cleanup Rx queue context programming functions
  2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
                   ` (8 preceding siblings ...)
  2024-12-03 23:53 ` [PATCH net-next v8 09/10] ice: move prefetch enable to ice_setup_rx_ctx Jacob Keller
@ 2024-12-03 23:53 ` Jacob Keller
  9 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-03 23:53 UTC (permalink / raw)
  To: Vladimir Oltean, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Przemek Kitszel, Masahiro Yamada,
	netdev
  Cc: Jacob Keller

The ice_copy_rxq_ctx_to_hw() and ice_write_rxq_ctx() functions perform some
defensive checks which are typically frowned upon by kernel style
guidelines.

In particular, NULL checks on buffers which point to the stack are
discouraged, especially when the functions are static and only called once.
Checks of this sort only serve to hide potential programming error, as we
will not produce the normal crash dump on a NULL access.

In addition, ice_copy_rxq_ctx_to_hw() cannot fail in another way, so could
be made void.

Future support for VF Live Migration will need to introduce an inverse
function for reading Rx queue context from HW registers to unpack it, as
well as functions to pack and unpack Tx queue context from HW.

Rather than copying these style issues into the new functions, lets first
cleanup the existing code.

For the ice_copy_rxq_ctx_to_hw() function:

 * Move the Rx queue index check out of this function.
 * Convert the function to a void return.
 * Use a simple int variable instead of a u8 for the for loop index, and
   initialize it inside the for loop.
 * Update the function description to better align with kernel doc style.

For the ice_write_rxq_ctx() function:

 * Move the Rx queue index check into this function.
 * Update the function description with a Returns: to align with kernel doc
   style.

These changes align the existing write functions to current kernel
style, and will align with the style of the new functions added when we
implement live migration in a future series.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/ice/ice_common.c | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 379040593d975342eaa2a3032938683b419f4f60..6c6862beab6a961ce5c0bc34e9c5794ed8cda865 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1358,32 +1358,23 @@ int ice_reset(struct ice_hw *hw, enum ice_reset_req req)
 }
 
 /**
- * ice_copy_rxq_ctx_to_hw
+ * ice_copy_rxq_ctx_to_hw - Copy packed Rx queue context to HW registers
  * @hw: pointer to the hardware structure
  * @rxq_ctx: pointer to the packed Rx queue context
  * @rxq_index: the index of the Rx queue
- *
- * Copies rxq context from dense structure to HW register space
  */
-static int ice_copy_rxq_ctx_to_hw(struct ice_hw *hw,
-				  const ice_rxq_ctx_buf_t *rxq_ctx,
-				  u32 rxq_index)
+static void ice_copy_rxq_ctx_to_hw(struct ice_hw *hw,
+				   const ice_rxq_ctx_buf_t *rxq_ctx,
+				   u32 rxq_index)
 {
-	u8 i;
-
-	if (rxq_index > QRX_CTRL_MAX_INDEX)
-		return -EINVAL;
-
 	/* Copy each dword separately to HW */
-	for (i = 0; i < ICE_RXQ_CTX_SIZE_DWORDS; i++) {
+	for (int i = 0; i < ICE_RXQ_CTX_SIZE_DWORDS; i++) {
 		u32 ctx = ((const u32 *)rxq_ctx)[i];
 
 		wr32(hw, QRX_CONTEXT(i, rxq_index), ctx);
 
 		ice_debug(hw, ICE_DBG_QCTX, "qrxdata[%d]: %08X\n", i, ctx);
 	}
-
-	return 0;
 }
 
 #define ICE_CTX_STORE(struct_name, struct_field, width, lsb) \
@@ -1432,23 +1423,26 @@ static void ice_pack_rxq_ctx(const struct ice_rlan_ctx *ctx,
 /**
  * ice_write_rxq_ctx - Write Rx Queue context to hardware
  * @hw: pointer to the hardware structure
- * @rlan_ctx: pointer to the rxq context
+ * @rlan_ctx: pointer to the unpacked Rx queue context
  * @rxq_index: the index of the Rx queue
  *
  * Pack the sparse Rx Queue context into dense hardware format and write it
  * into the HW register space.
+ *
+ * Return: 0 on success, or -EINVAL if the Rx queue index is invalid.
  */
 int ice_write_rxq_ctx(struct ice_hw *hw, struct ice_rlan_ctx *rlan_ctx,
 		      u32 rxq_index)
 {
 	ice_rxq_ctx_buf_t buf = {};
 
-	if (!rlan_ctx)
+	if (rxq_index > QRX_CTRL_MAX_INDEX)
 		return -EINVAL;
 
 	ice_pack_rxq_ctx(rlan_ctx, &buf);
+	ice_copy_rxq_ctx_to_hw(hw, &buf, rxq_index);
 
-	return ice_copy_rxq_ctx_to_hw(hw, &buf, rxq_index);
+	return 0;
 }
 
 /* LAN Tx Queue Context */

-- 
2.47.0.265.g4ca455297942


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-03 23:53 ` [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields() Jacob Keller
@ 2024-12-04 17:12   ` Vladimir Oltean
  2024-12-04 18:47     ` Jacob Keller
                       ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Vladimir Oltean @ 2024-12-04 17:12 UTC (permalink / raw)
  To: Jacob Keller
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Przemek Kitszel, Masahiro Yamada, netdev

On Tue, Dec 03, 2024 at 03:53:49PM -0800, Jacob Keller wrote:
> +#define CHECK_PACKED_FIELD(field) ({ \
> +	typeof(field) __f = (field); \
> +	BUILD_BUG_ON(__f.startbit < __f.endbit); \
> +	BUILD_BUG_ON(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size); \
> +	BUILD_BUG_ON(__f.size != 1 && __f.size != 2 && \
> +		     __f.size != 4 && __f.size != 8); \
> +})
> +
> +
> +#define CHECK_PACKED_FIELD_OVERLAP(ascending, field1, field2) ({ \
> +	typeof(field1) _f1 = (field1); typeof(field2) _f2 = (field2); \
> +	const bool _a = (ascending); \
> +	BUILD_BUG_ON(_a && _f1.startbit >= _f2.startbit); \
> +	BUILD_BUG_ON(!_a && _f1.startbit <= _f2.startbit); \
> +	BUILD_BUG_ON(max(_f1.endbit, _f2.endbit) <= \
> +		     min(_f1.startbit, _f2.startbit)); \
> +})
> +
> +#define CHECK_PACKED_FIELDS_SIZE(fields, pbuflen) ({ \
> +	typeof(&(fields)[0]) _f = (fields); \
> +	typeof(pbuflen) _len = (pbuflen); \
> +	const size_t num_fields = ARRAY_SIZE(fields); \
> +	BUILD_BUG_ON(!__builtin_constant_p(_len)); \
> +	BUILD_BUG_ON(_f[0].startbit >= BITS_PER_BYTE * _len); \

Please add a comment here stating that we check both the first and last
element to cover the ascending as well as descending ordering scenarios.
It took me a while to realize this, I thought the _f[0] check was unnecessary.

> +	BUILD_BUG_ON(_f[num_fields - 1].startbit >= BITS_PER_BYTE * _len); \
> +})
> +
>  #define QUIRK_MSB_ON_THE_RIGHT	BIT(0)
>  #define QUIRK_LITTLE_ENDIAN	BIT(1)
>  #define QUIRK_LSW32_IS_FIRST	BIT(2)

I spent some time today to play around with this version, and it seems
to work, but I took some liberty and made the following changes:

- Tail-call CHECK_PACKED_FIELD_OVERLAP() from CHECK_PACKED_FIELD(). This
  reduces the size of the generated code from 2753 lines to 1478 lines,
  which already brings it a little bit more into the realm of "tolerable" IMO.

- Remove the BUILD_BUG_ON(ARRAY_SIZE(fields) == N), since I think
  that's just wasteful (in terms of space and compiler CPU cycles) and
  ultra-defensive, when the auto-generated __builtin_choose_expr() is
  the only caller. It was justified when the consumer had to explicitly
  select the right checking macro.

- Add some prettier error messages. Compare (for an error injected by me):

../drivers/net/ethernet/intel/ice/ice_common.c:1419:2: error: call to '__compiletime_assert_3302' declared with 'error' attribute: BUILD_BUG_ON failed: max(_f1.endbit, _f2.endbit) <= min(_f1.startbit, _f2.startbit)
        pack_fields(buf, sizeof(*buf), ctx, ice_rlan_ctx_fields,
        ^

with:


../drivers/net/ethernet/intel/ice/ice_common.c:1419:2: error: call to '__compiletime_assert_3414' declared with 'error' attribute: ice_rlan_ctx_fields field 3 overlaps with previous field
        pack_fields(buf, sizeof(*buf), ctx, ice_rlan_ctx_fields,
        ^


That incremental improvement is below, if you'd be interested in including it
(the auto-generated code is not part of the diff):

diff --git a/include/linux/packing.h b/include/linux/packing.h
index c4fc76ae64a5..1c89a5129b06 100644
--- a/include/linux/packing.h
+++ b/include/linux/packing.h
@@ -36,22 +36,38 @@ struct packed_field_m {
 	sizeof_field(struct_name, struct_field), \
 }
 
-#define CHECK_PACKED_FIELD(field) ({ \
-	typeof(field) __f = (field); \
-	BUILD_BUG_ON(__f.startbit < __f.endbit); \
-	BUILD_BUG_ON(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size); \
-	BUILD_BUG_ON(__f.size != 1 && __f.size != 2 && \
-		     __f.size != 4 && __f.size != 8); \
+#define CHECK_PACKED_FIELD_OVERLAP(fields, index1, index2) ({ \
+	typeof(&(fields)[0]) __f = (fields); \
+	typeof(__f[0]) _f1 = __f[index1]; typeof(__f[0]) _f2 = __f[index2]; \
+	const bool _ascending = __f[0].startbit < __f[1].startbit; \
+	BUILD_BUG_ON_MSG(_ascending && _f1.startbit >= _f2.startbit, \
+			 __stringify(fields) " field " __stringify(index2) \
+			 " breaks ascending order"); \
+	BUILD_BUG_ON_MSG(!_ascending && _f1.startbit <= _f2.startbit, \
+			 __stringify(fields) " field " __stringify(index2) \
+			 " breaks descending order"); \
+	BUILD_BUG_ON_MSG(max(_f1.endbit, _f2.endbit) <= \
+			 min(_f1.startbit, _f2.startbit), \
+			 __stringify(fields) " field " __stringify(index2) \
+			 " overlaps with previous field"); \
 })
 
-
-#define CHECK_PACKED_FIELD_OVERLAP(ascending, field1, field2) ({ \
-	typeof(field1) _f1 = (field1); typeof(field2) _f2 = (field2); \
-	const bool _a = (ascending); \
-	BUILD_BUG_ON(_a && _f1.startbit >= _f2.startbit); \
-	BUILD_BUG_ON(!_a && _f1.startbit <= _f2.startbit); \
-	BUILD_BUG_ON(max(_f1.endbit, _f2.endbit) <= \
-		     min(_f1.startbit, _f2.startbit)); \
+#define CHECK_PACKED_FIELD(fields, index) ({ \
+	typeof(&(fields)[0]) _f = (fields); \
+	typeof(_f[0]) __f = _f[index]; \
+	BUILD_BUG_ON_MSG(__f.startbit < __f.endbit, \
+			 __stringify(fields) " field " __stringify(index) \
+			 " start bit must not be smaller than end bit"); \
+	BUILD_BUG_ON_MSG(__f.size != 1 && __f.size != 2 && \
+			 __f.size != 4 && __f.size != 8, \
+			 __stringify(fields) " field " __stringify(index) \
+			" has unsupported unpacked storage size"); \
+	BUILD_BUG_ON_MSG(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size, \
+			 __stringify(fields) " field " __stringify(index) \
+			 " exceeds unpacked storage size"); \
+	__builtin_choose_expr(index != 0, \
+			      CHECK_PACKED_FIELD_OVERLAP(fields, index - 1, index), \
+			      1); \
 })
 
 #define CHECK_PACKED_FIELDS_SIZE(fields, pbuflen) ({ \
diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
index 09a21afd640b..fabbb741c9a8 100644
--- a/scripts/gen_packed_field_checks.c
+++ b/scripts/gen_packed_field_checks.c
@@ -9,15 +9,9 @@ int main(int argc, char **argv)
 {
 	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
 		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);
-		printf("\ttypeof(&(fields)[0]) _f = (fields); \\\n");
-		printf("\tBUILD_BUG_ON(ARRAY_SIZE(fields) != %d); \\\n", i);
 
 		for (int j = 0; j < i; j++)
-			printf("\tCHECK_PACKED_FIELD(_f[%d]); \\\n", j);
-
-		for (int j = 1; j < i; j++)
-			printf("\tCHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[%d], _f[%d]); \\\n",
-			       j - 1, j);
+			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);
 
 		printf("})\n\n");
 	}

And there's one more thing I tried, which mostly worked. That was to
express CHECK_PACKED_FIELDS_N in terms of CHECK_PACKED_FIELDS_N-1.
This further reduced the auto-generated code size from 1478 lines to 302
lines, which I think is appealing.

diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
index fabbb741c9a8..bac85c04ef20 100644
--- a/scripts/gen_packed_field_checks.c
+++ b/scripts/gen_packed_field_checks.c
@@ -10,9 +10,10 @@ int main(int argc, char **argv)
 	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
 		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);
 
-		for (int j = 0; j < i; j++)
-			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);
+		if (i != 1)
+			printf("\tCHECK_PACKED_FIELDS_%d(fields); \\\n", i - 1);
 
+		printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", i);
 		printf("})\n\n");
 	}
 

The problem is that, for some reason, it introduces this sparse warning:

../lib/packing_test.c:436:9: warning: invalid access past the end of 'test_fields' (24 24)
../lib/packing_test.c:448:9: warning: invalid access past the end of 'test_fields' (24 24)

Nobody accesses past element 6 (ARRAY_SIZE) of test_fields[]. I ran the
KUnit with kasan and I saw no warning. The strace warning comes from
check_access() in flow.c, but I don't have any energy left today to go
further into this.

I'm suspecting either a strace bug/false positive, or some sort of
variable name aliasing issue which I haven't identified yet.

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-04 17:12   ` Vladimir Oltean
@ 2024-12-04 18:47     ` Jacob Keller
  2024-12-04 23:24     ` Jacob Keller
  2024-12-04 23:43     ` Przemek Kitszel
  2 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-04 18:47 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Przemek Kitszel, Masahiro Yamada, netdev



On 12/4/2024 9:12 AM, Vladimir Oltean wrote:
> On Tue, Dec 03, 2024 at 03:53:49PM -0800, Jacob Keller wrote:
>> +#define CHECK_PACKED_FIELD(field) ({ \
>> +	typeof(field) __f = (field); \
>> +	BUILD_BUG_ON(__f.startbit < __f.endbit); \
>> +	BUILD_BUG_ON(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size); \
>> +	BUILD_BUG_ON(__f.size != 1 && __f.size != 2 && \
>> +		     __f.size != 4 && __f.size != 8); \
>> +})
>> +
>> +
>> +#define CHECK_PACKED_FIELD_OVERLAP(ascending, field1, field2) ({ \
>> +	typeof(field1) _f1 = (field1); typeof(field2) _f2 = (field2); \
>> +	const bool _a = (ascending); \
>> +	BUILD_BUG_ON(_a && _f1.startbit >= _f2.startbit); \
>> +	BUILD_BUG_ON(!_a && _f1.startbit <= _f2.startbit); \
>> +	BUILD_BUG_ON(max(_f1.endbit, _f2.endbit) <= \
>> +		     min(_f1.startbit, _f2.startbit)); \
>> +})
>> +
>> +#define CHECK_PACKED_FIELDS_SIZE(fields, pbuflen) ({ \
>> +	typeof(&(fields)[0]) _f = (fields); \
>> +	typeof(pbuflen) _len = (pbuflen); \
>> +	const size_t num_fields = ARRAY_SIZE(fields); \
>> +	BUILD_BUG_ON(!__builtin_constant_p(_len)); \
>> +	BUILD_BUG_ON(_f[0].startbit >= BITS_PER_BYTE * _len); \
> 
> Please add a comment here stating that we check both the first and last
> element to cover the ascending as well as descending ordering scenarios.
> It took me a while to realize this, I thought the _f[0] check was unnecessary.
> 

Sure. I will also try to adopt the BUILD_BUG_ON_MSG style you have used
for the overlap to help with better error messages.

>> +	BUILD_BUG_ON(_f[num_fields - 1].startbit >= BITS_PER_BYTE * _len); \
>> +})
>> +
>>  #define QUIRK_MSB_ON_THE_RIGHT	BIT(0)
>>  #define QUIRK_LITTLE_ENDIAN	BIT(1)
>>  #define QUIRK_LSW32_IS_FIRST	BIT(2)
> 
> I spent some time today to play around with this version, and it seems
> to work, but I took some liberty and made the following changes:
> 
> - Tail-call CHECK_PACKED_FIELD_OVERLAP() from CHECK_PACKED_FIELD(). This
>   reduces the size of the generated code from 2753 lines to 1478 lines,
>   which already brings it a little bit more into the realm of "tolerable" IMO.
> 

Nice thats a good improvement.

> - Remove the BUILD_BUG_ON(ARRAY_SIZE(fields) == N), since I think
>   that's just wasteful (in terms of space and compiler CPU cycles) and
>   ultra-defensive, when the auto-generated __builtin_choose_expr() is
>   the only caller. It was justified when the consumer had to explicitly
>   select the right checking macro.
> 

Sure, we can drop these. I had kept them because I felt it was
worthwhile in case someone does call them manually, but I don't think we
should encourage that behavior, and it is otherwise completely wasted
cycles. I guess its defense against screwing up the builtin_choose_expr,
but that is auto-generated now too.

> - Add some prettier error messages. Compare (for an error injected by me):
> 
> ../drivers/net/ethernet/intel/ice/ice_common.c:1419:2: error: call to '__compiletime_assert_3302' declared with 'error' attribute: BUILD_BUG_ON failed: max(_f1.endbit, _f2.endbit) <= min(_f1.startbit, _f2.startbit)
>         pack_fields(buf, sizeof(*buf), ctx, ice_rlan_ctx_fields,
>         ^
> 
> with:
> 
> 
> ../drivers/net/ethernet/intel/ice/ice_common.c:1419:2: error: call to '__compiletime_assert_3414' declared with 'error' attribute: ice_rlan_ctx_fields field 3 overlaps with previous field
>         pack_fields(buf, sizeof(*buf), ctx, ice_rlan_ctx_fields,
>         ^
> 

That is much nicer, thanks.

> 
> That incremental improvement is below, if you'd be interested in including it
> (the auto-generated code is not part of the diff):
> 
> diff --git a/include/linux/packing.h b/include/linux/packing.h
> index c4fc76ae64a5..1c89a5129b06 100644
> --- a/include/linux/packing.h
> +++ b/include/linux/packing.h
> @@ -36,22 +36,38 @@ struct packed_field_m {
>  	sizeof_field(struct_name, struct_field), \
>  }
>  
> -#define CHECK_PACKED_FIELD(field) ({ \
> -	typeof(field) __f = (field); \
> -	BUILD_BUG_ON(__f.startbit < __f.endbit); \
> -	BUILD_BUG_ON(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size); \
> -	BUILD_BUG_ON(__f.size != 1 && __f.size != 2 && \
> -		     __f.size != 4 && __f.size != 8); \
> +#define CHECK_PACKED_FIELD_OVERLAP(fields, index1, index2) ({ \
> +	typeof(&(fields)[0]) __f = (fields); \
> +	typeof(__f[0]) _f1 = __f[index1]; typeof(__f[0]) _f2 = __f[index2]; \
> +	const bool _ascending = __f[0].startbit < __f[1].startbit; \
> +	BUILD_BUG_ON_MSG(_ascending && _f1.startbit >= _f2.startbit, \
> +			 __stringify(fields) " field " __stringify(index2) \
> +			 " breaks ascending order"); \
> +	BUILD_BUG_ON_MSG(!_ascending && _f1.startbit <= _f2.startbit, \
> +			 __stringify(fields) " field " __stringify(index2) \
> +			 " breaks descending order"); \
> +	BUILD_BUG_ON_MSG(max(_f1.endbit, _f2.endbit) <= \
> +			 min(_f1.startbit, _f2.startbit), \
> +			 __stringify(fields) " field " __stringify(index2) \
> +			 " overlaps with previous field"); \
>  })
>  
> -
> -#define CHECK_PACKED_FIELD_OVERLAP(ascending, field1, field2) ({ \
> -	typeof(field1) _f1 = (field1); typeof(field2) _f2 = (field2); \
> -	const bool _a = (ascending); \
> -	BUILD_BUG_ON(_a && _f1.startbit >= _f2.startbit); \
> -	BUILD_BUG_ON(!_a && _f1.startbit <= _f2.startbit); \
> -	BUILD_BUG_ON(max(_f1.endbit, _f2.endbit) <= \
> -		     min(_f1.startbit, _f2.startbit)); \
> +#define CHECK_PACKED_FIELD(fields, index) ({ \
> +	typeof(&(fields)[0]) _f = (fields); \
> +	typeof(_f[0]) __f = _f[index]; \
> +	BUILD_BUG_ON_MSG(__f.startbit < __f.endbit, \
> +			 __stringify(fields) " field " __stringify(index) \
> +			 " start bit must not be smaller than end bit"); \
> +	BUILD_BUG_ON_MSG(__f.size != 1 && __f.size != 2 && \
> +			 __f.size != 4 && __f.size != 8, \
> +			 __stringify(fields) " field " __stringify(index) \
> +			" has unsupported unpacked storage size"); \
> +	BUILD_BUG_ON_MSG(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size, \
> +			 __stringify(fields) " field " __stringify(index) \
> +			 " exceeds unpacked storage size"); \
> +	__builtin_choose_expr(index != 0, \
> +			      CHECK_PACKED_FIELD_OVERLAP(fields, index - 1, index), \
> +			      1); \
>  })
>  
>  #define CHECK_PACKED_FIELDS_SIZE(fields, pbuflen) ({ \
> diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
> index 09a21afd640b..fabbb741c9a8 100644
> --- a/scripts/gen_packed_field_checks.c
> +++ b/scripts/gen_packed_field_checks.c
> @@ -9,15 +9,9 @@ int main(int argc, char **argv)
>  {
>  	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
>  		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);
> -		printf("\ttypeof(&(fields)[0]) _f = (fields); \\\n");
> -		printf("\tBUILD_BUG_ON(ARRAY_SIZE(fields) != %d); \\\n", i);
>  
>  		for (int j = 0; j < i; j++)
> -			printf("\tCHECK_PACKED_FIELD(_f[%d]); \\\n", j);
> -
> -		for (int j = 1; j < i; j++)
> -			printf("\tCHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[%d], _f[%d]); \\\n",
> -			       j - 1, j);
> +			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);
>  
>  		printf("})\n\n");
>  	}
> 
> And there's one more thing I tried, which mostly worked. That was to
> express CHECK_PACKED_FIELDS_N in terms of CHECK_PACKED_FIELDS_N-1.
> This further reduced the auto-generated code size from 1478 lines to 302
> lines, which I think is appealing.
> 
> diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
> index fabbb741c9a8..bac85c04ef20 100644
> --- a/scripts/gen_packed_field_checks.c
> +++ b/scripts/gen_packed_field_checks.c
> @@ -10,9 +10,10 @@ int main(int argc, char **argv)
>  	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
>  		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);
>  
> -		for (int j = 0; j < i; j++)
> -			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);
> +		if (i != 1)
> +			printf("\tCHECK_PACKED_FIELDS_%d(fields); \\\n", i - 1);
>  
> +		printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", i);
>  		printf("})\n\n");
>  	}
>  
> 
> The problem is that, for some reason, it introduces this sparse warning:
> 
> ../lib/packing_test.c:436:9: warning: invalid access past the end of 'test_fields' (24 24)
> ../lib/packing_test.c:448:9: warning: invalid access past the end of 'test_fields' (24 24)
> 

I'll take a look and see if I can spot it.

> Nobody accesses past element 6 (ARRAY_SIZE) of test_fields[]. I ran the
> KUnit with kasan and I saw no warning. The strace warning comes from
> check_access() in flow.c, but I don't have any energy left today to go
> further into this.
> 
> I'm suspecting either a strace bug/false positive, or some sort of
> variable name aliasing issue which I haven't identified yet.

I had some issues with various attempts I made at the compiler checks
because different compilers would not always track constants.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-04 17:12   ` Vladimir Oltean
  2024-12-04 18:47     ` Jacob Keller
@ 2024-12-04 23:24     ` Jacob Keller
  2024-12-04 23:52       ` Vladimir Oltean
  2024-12-04 23:43     ` Przemek Kitszel
  2 siblings, 1 reply; 21+ messages in thread
From: Jacob Keller @ 2024-12-04 23:24 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Przemek Kitszel, Masahiro Yamada, netdev



On 12/4/2024 9:12 AM, Vladimir Oltean wrote:
> And there's one more thing I tried, which mostly worked. That was to
> express CHECK_PACKED_FIELDS_N in terms of CHECK_PACKED_FIELDS_N-1.
> This further reduced the auto-generated code size from 1478 lines to 302
> lines, which I think is appealing.
> 

I figured it out! There are two key issues involved:

> diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
> index fabbb741c9a8..bac85c04ef20 100644
> --- a/scripts/gen_packed_field_checks.c
> +++ b/scripts/gen_packed_field_checks.c
> @@ -10,9 +10,10 @@ int main(int argc, char **argv)
>  	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
>  		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);
>  
> -		for (int j = 0; j < i; j++)
> -			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);
> +		if (i != 1)
> +			printf("\tCHECK_PACKED_FIELDS_%d(fields); \\\n", i - 1);
>  
> +		printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", i);

This needs to be i - 1, since arrays are 0-indexed, so this code expands
to checking the wrong value.

CHECK_PACKED_FIELDS_1 needs to become

CHECK_PACKED_FIELD(fields, 0)

but this code makes it:

CHECK_PACKED_FIELD(fields, 1)

Thus, all the array definitions are off-by-one, leading to the last one
being out-of-bounds.

>  		printf("})\n\n");
>  	}
>  
> 
> The problem is that, for some reason, it introduces this sparse warning:
> 
> ../lib/packing_test.c:436:9: warning: invalid access past the end of 'test_fields' (24 24)
> ../lib/packing_test.c:448:9: warning: invalid access past the end of 'test_fields' (24 24)
> 
> Nobody accesses past element 6 (ARRAY_SIZE) of test_fields[]. I ran the

The array size is 6, but we try to access element 6 which is one past
the array... good old off-by-one error :)

There is one further complication which is that the nested statement
expressions ({ ... }) for each CHECK_PACKED_FIELD_N eventually make GCC
confused, as it doesn't seem to keep track of the types very well.

I fixed that by changing the individual CHECK_PACKED_FIELD_N to be
non-statement expressions, and then wrapping their calls in the
builtin_choose_expr() with ({ ... }), which prevents us from creating
too many expression layers for GCC. It actually results in identical
code being evaluated as with the old version but now with a constant
scaling of the text size: 2 lines per additional check. Of course the
complexity scales linearly, but that means our text size no longer
scales with O(n*log(n)) but just as O(N).

Its fantastic improvement, thanks for the suggestion. I'll have v9 out
with these improvements soon.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 04/10] lib: packing: document recently added APIs
  2024-12-03 23:53 ` [PATCH net-next v8 04/10] lib: packing: document recently added APIs Jacob Keller
@ 2024-12-04 23:26   ` Vladimir Oltean
  2024-12-04 23:31   ` Vladimir Oltean
  1 sibling, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2024-12-04 23:26 UTC (permalink / raw)
  To: Jacob Keller
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Przemek Kitszel, Masahiro Yamada, netdev

On Tue, Dec 03, 2024 at 03:53:50PM -0800, Jacob Keller wrote:
> Extend the documentation for the packing library, covering the intended use
> for the recently added APIs. This includes the pack() and unpack() macros,
> as well as the pack_fields() and unpack_fields() macros.
> 
> Add a note that the packing() API is now deprecated in favor of pack() and
> unpack().
> 
> For the pack_fields() and unpack_fields() APIs, explain the rationale for
> when a driver may want to select this API. Provide an example which shows
> how to define the fields and call the pack_fields() and unpack_fields()
> macros.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> ---
>  Documentation/core-api/packing.rst | 118 +++++++++++++++++++++++++++++++++++--
>  1 file changed, 113 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/core-api/packing.rst b/Documentation/core-api/packing.rst
> index 821691f23c541cee27995bb1d77e23ff04f82433..30fc2328f789920e27a1bcf3945a6793894ef1d4 100644
> --- a/Documentation/core-api/packing.rst
> +++ b/Documentation/core-api/packing.rst
> @@ -227,11 +227,119 @@ Intended use
>  
>  Drivers that opt to use this API first need to identify which of the above 3
>  quirk combinations (for a total of 8) match what the hardware documentation
> -describes. Then they should wrap the packing() function, creating a new
> -xxx_packing() that calls it using the proper QUIRK_* one-hot bits set.
> +describes.
> +
> +There are 3 supported usage patterns, detailed below.
> +
> +packing()
> +^^^^^^^^^
> +
> +This API function is deprecated.
>  
>  The packing() function returns an int-encoded error code, which protects the
>  programmer against incorrect API use.  The errors are not expected to occur
> -during runtime, therefore it is reasonable for xxx_packing() to return void
> -and simply swallow those errors. Optionally it can dump stack or print the
> -error description.
> +during runtime, therefore it is reasonable to wrap packing() into a custom
> +function which returns void and simply swallow those errors. Optionally it can

returns (...) and swallows

> +dump stack or print the error description.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 04/10] lib: packing: document recently added APIs
  2024-12-03 23:53 ` [PATCH net-next v8 04/10] lib: packing: document recently added APIs Jacob Keller
  2024-12-04 23:26   ` Vladimir Oltean
@ 2024-12-04 23:31   ` Vladimir Oltean
  1 sibling, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2024-12-04 23:31 UTC (permalink / raw)
  To: Jacob Keller
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Przemek Kitszel, Masahiro Yamada, netdev

On Tue, Dec 03, 2024 at 03:53:50PM -0800, Jacob Keller wrote:
> Extend the documentation for the packing library, covering the intended use
> for the recently added APIs. This includes the pack() and unpack() macros,
> as well as the pack_fields() and unpack_fields() macros.
> 
> Add a note that the packing() API is now deprecated in favor of pack() and
> unpack().
> 
> For the pack_fields() and unpack_fields() APIs, explain the rationale for
> when a driver may want to select this API. Provide an example which shows
> how to define the fields and call the pack_fields() and unpack_fields()
> macros.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
> ---

I think this combination of Author: and Signed-off-by: makes it unclear
what my role for this patch is (normally you'd expect that the author
coincides with the first sign off). You could add a Co-developed-by:
before my sign off and it should be ok.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-04 17:12   ` Vladimir Oltean
  2024-12-04 18:47     ` Jacob Keller
  2024-12-04 23:24     ` Jacob Keller
@ 2024-12-04 23:43     ` Przemek Kitszel
  2024-12-05  9:52       ` Vladimir Oltean
  2 siblings, 1 reply; 21+ messages in thread
From: Przemek Kitszel @ 2024-12-04 23:43 UTC (permalink / raw)
  To: Vladimir Oltean, Jacob Keller
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Masahiro Yamada, netdev

On 12/4/24 18:12, Vladimir Oltean wrote:
> On Tue, Dec 03, 2024 at 03:53:49PM -0800, Jacob Keller wrote:

Amazing stuff :), I really like the fact that you both keep striving for
the best result, even way past the point of cut off of most other ;)

> diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
> index 09a21afd640b..fabbb741c9a8 100644
> --- a/scripts/gen_packed_field_checks.c
> +++ b/scripts/gen_packed_field_checks.c
> @@ -9,15 +9,9 @@ int main(int argc, char **argv)
>   {
>   	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
>   		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);

[i]
@i in range 1..MAX_PACKED_FIELD_SIZE; inclusive

> -		printf("\ttypeof(&(fields)[0]) _f = (fields); \\\n");
> -		printf("\tBUILD_BUG_ON(ARRAY_SIZE(fields) != %d); \\\n", i);
>   
>   		for (int j = 0; j < i; j++)
> -			printf("\tCHECK_PACKED_FIELD(_f[%d]); \\\n", j);
> -
> -		for (int j = 1; j < i; j++)
> -			printf("\tCHECK_PACKED_FIELD_OVERLAP(_f[0].startbit < _f[1].startbit, _f[%d], _f[%d]); \\\n",
> -			       j - 1, j);
> +			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);

[j]
@j < @i

>   
>   		printf("})\n\n");
>   	}
> 
> And there's one more thing I tried, which mostly worked. That was to
> express CHECK_PACKED_FIELDS_N in terms of CHECK_PACKED_FIELDS_N-1.
> This further reduced the auto-generated code size from 1478 lines to 302
> lines, which I think is appealing.

a lot :)

> 
> diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
> index fabbb741c9a8..bac85c04ef20 100644
> --- a/scripts/gen_packed_field_checks.c
> +++ b/scripts/gen_packed_field_checks.c
> @@ -10,9 +10,10 @@ int main(int argc, char **argv)
>   	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
>   		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);

same as [i] above, ok

>   
> -		for (int j = 0; j < i; j++)
> -			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);
> +		if (i != 1)
> +			printf("\tCHECK_PACKED_FIELDS_%d(fields); \\\n", i - 1);
>   
> +		printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", i);

prior to the change CHECK_PACKED_FIELD() was called on values smaller
than MAX_PACKED_FIELD_SIZE, compare with [j] above, now you call it also
for the MAX one

>   		printf("})\n\n");
>   	}
>   
> 
> The problem is that, for some reason, it introduces this sparse warning:
> 
> ../lib/packing_test.c:436:9: warning: invalid access past the end of 'test_fields' (24 24)
> ../lib/packing_test.c:448:9: warning: invalid access past the end of 'test_fields' (24 24)
> 

off by one error? see above

> Nobody accesses past element 6 (ARRAY_SIZE) of test_fields[]. I ran the
> KUnit with kasan and I saw no warning. The strace warning comes from
> check_access() in flow.c, but I don't have any energy left today to go
> further into this.
> 
> I'm suspecting either a strace bug/false positive, or some sort of
> variable name aliasing issue which I haven't identified yet.

PS. incremental diff in a single patch is harder to apply, but easier to
review, comment both in a single reply == great idea

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-04 23:24     ` Jacob Keller
@ 2024-12-04 23:52       ` Vladimir Oltean
  2024-12-05  0:23         ` Jacob Keller
  0 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2024-12-04 23:52 UTC (permalink / raw)
  To: Jacob Keller
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Przemek Kitszel, Masahiro Yamada, netdev

On Wed, Dec 04, 2024 at 03:24:59PM -0800, Jacob Keller wrote:
> On 12/4/2024 9:12 AM, Vladimir Oltean wrote:
> > And there's one more thing I tried, which mostly worked. That was to
> > express CHECK_PACKED_FIELDS_N in terms of CHECK_PACKED_FIELDS_N-1.
> > This further reduced the auto-generated code size from 1478 lines to 302
> > lines, which I think is appealing.
> > 
> 
> I figured it out! There are two key issues involved:
> 
> > diff --git a/scripts/gen_packed_field_checks.c b/scripts/gen_packed_field_checks.c
> > index fabbb741c9a8..bac85c04ef20 100644
> > --- a/scripts/gen_packed_field_checks.c
> > +++ b/scripts/gen_packed_field_checks.c
> > @@ -10,9 +10,10 @@ int main(int argc, char **argv)
> >  	for (int i = 1; i <= MAX_PACKED_FIELD_SIZE; i++) {
> >  		printf("#define CHECK_PACKED_FIELDS_%d(fields) ({ \\\n", i);
> >  
> > -		for (int j = 0; j < i; j++)
> > -			printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", j);
> > +		if (i != 1)
> > +			printf("\tCHECK_PACKED_FIELDS_%d(fields); \\\n", i - 1);
> >  
> > +		printf("\tCHECK_PACKED_FIELD(fields, %d); \\\n", i);
> 
> This needs to be i - 1, since arrays are 0-indexed, so this code expands
> to checking the wrong value.
> 
> CHECK_PACKED_FIELDS_1 needs to become
> 
> CHECK_PACKED_FIELD(fields, 0)
> 
> but this code makes it:
> 
> CHECK_PACKED_FIELD(fields, 1)
> 
> Thus, all the array definitions are off-by-one, leading to the last one
> being out-of-bounds.

ah :-/

I should have paid more attention, sorry.

> >  		printf("})\n\n");
> >  	}
> >  
> > 
> > The problem is that, for some reason, it introduces this sparse warning:
> > 
> > ../lib/packing_test.c:436:9: warning: invalid access past the end of 'test_fields' (24 24)
> > ../lib/packing_test.c:448:9: warning: invalid access past the end of 'test_fields' (24 24)
> > 
> > Nobody accesses past element 6 (ARRAY_SIZE) of test_fields[]. I ran the
> 
> The array size is 6, but we try to access element 6 which is one past
> the array... good old off-by-one error :)
> 
> There is one further complication which is that the nested statement
> expressions ({ ... }) for each CHECK_PACKED_FIELD_N eventually make GCC
> confused, as it doesn't seem to keep track of the types very well.

I only tested with clang which didn't complain, sorry.

> I fixed that by changing the individual CHECK_PACKED_FIELD_N to be
> non-statement expressions, and then wrapping their calls in the
> builtin_choose_expr() with ({ ... }), which prevents us from creating
> too many expression layers for GCC. It actually results in identical
> code being evaluated as with the old version but now with a constant
> scaling of the text size: 2 lines per additional check.

Yeah, I think that was the logical next development step. By doing this now,
I think you just saved an extra patch iteration, thanks.

> Of course the complexity scales linearly, but that means our text size
> no longer scales with O(n*log(n)) but just as O(N).

Well, technically, the number of lines of code required, in "naive" form,
for overlap checking of arrays up to length N should be N*(N+1)/2, which
"grows quicker" than N*log(N).

But I don't think we can talk about algorithmic complexity here (big O
notation), which stays the same (linear) in both ways of expressing the
same thing.

> Its fantastic improvement, thanks for the suggestion. I'll have v9 out
> with these improvements soon.

And thanks for staying online with this effort for more than an entire
kernel development cycle! Looking forward to v9.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-04 23:52       ` Vladimir Oltean
@ 2024-12-05  0:23         ` Jacob Keller
  0 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-05  0:23 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Przemek Kitszel, Masahiro Yamada, netdev



On 12/4/2024 3:52 PM, Vladimir Oltean wrote:
> On Wed, Dec 04, 2024 at 03:24:59PM -0800, Jacob Keller wrote:
>> On 12/4/2024 9:12 AM, Vladimir Oltean wrote:
>> Thus, all the array definitions are off-by-one, leading to the last one
>> being out-of-bounds.
> 
> ah :-/
> 
> I should have paid more attention, sorry.
> 

It happens to the best of us. As they say, in programming there are 3
hard problems: naming things, and off-by-one errors.

>>>  		printf("})\n\n");
>>>  	}
>>>  
>>>
>>> The problem is that, for some reason, it introduces this sparse warning:
>>>
>>> ../lib/packing_test.c:436:9: warning: invalid access past the end of 'test_fields' (24 24)
>>> ../lib/packing_test.c:448:9: warning: invalid access past the end of 'test_fields' (24 24)
>>>
>>> Nobody accesses past element 6 (ARRAY_SIZE) of test_fields[]. I ran the
>>
>> The array size is 6, but we try to access element 6 which is one past
>> the array... good old off-by-one error :)
>>
>> There is one further complication which is that the nested statement
>> expressions ({ ... }) for each CHECK_PACKED_FIELD_N eventually make GCC
>> confused, as it doesn't seem to keep track of the types very well.
> 
> I only tested with clang which didn't complain, sorry.
> 

Yea, I have had mixed luck between compilers. Masahiro had suggested a
for-loop which clang handles just fine, but GCC doesn't bother parsing.
I don't like only having the checks on some compilers.

>> I fixed that by changing the individual CHECK_PACKED_FIELD_N to be
>> non-statement expressions, and then wrapping their calls in the
>> builtin_choose_expr() with ({ ... }), which prevents us from creating
>> too many expression layers for GCC. It actually results in identical
>> code being evaluated as with the old version but now with a constant
>> scaling of the text size: 2 lines per additional check.
> 
> Yeah, I think that was the logical next development step. By doing this now,
> I think you just saved an extra patch iteration, thanks.
> 
>> Of course the complexity scales linearly, but that means our text size
>> no longer scales with O(n*log(n)) but just as O(N).
> 
> Well, technically, the number of lines of code required, in "naive" form,
> for overlap checking of arrays up to length N should be N*(N+1)/2, which
> "grows quicker" than N*log(N).
> 

Right. I was thinking of with this ordered check, you have O(N) scaling
for the number of checks, but that means that we have O(N^2) number of
lines as we scale the number of checks up. Each macro required ~N lines,
but we have N macros, so we get N^2 number of lines.

> But I don't think we can talk about algorithmic complexity here (big O
> notation), which stays the same (linear) in both ways of expressing the
> same thing.
>

Right. The computation stays the same. But now, we only need 4 lines per
check, because each check is built on top of the previous ones recursively.

>> Its fantastic improvement, thanks for the suggestion. I'll have v9 out
>> with these improvements soon.
> 
> And thanks for staying online with this effort for more than an entire
> kernel development cycle! Looking forward to v9.

Yea. This has certainly taken longer than I would have liked, but I'm
happy with the end result. We got something much better, even if it took
fiddling around in the wrong areas for longer than I would have liked. I
think these changes are great for ice, and also make packing much easier
to use for others on the long run. Hopefully we can see more adoption now.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-04 23:43     ` Przemek Kitszel
@ 2024-12-05  9:52       ` Vladimir Oltean
  2024-12-05 21:26         ` Jacob Keller
  0 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2024-12-05  9:52 UTC (permalink / raw)
  To: Przemek Kitszel
  Cc: Jacob Keller, Andrew Morton, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Tony Nguyen, Masahiro Yamada, netdev

On Thu, Dec 05, 2024 at 12:43:35AM +0100, Przemek Kitszel wrote:
> On 12/4/24 18:12, Vladimir Oltean wrote:
> > On Tue, Dec 03, 2024 at 03:53:49PM -0800, Jacob Keller wrote:
> 
> Amazing stuff :), I really like the fact that you both keep striving for
> the best result, even way past the point of cut off of most other ;)

It's all Jake. I openly admit I would have given up and not followed
through with the review feedback to go to modpost and back.
Additionally, the __builtin_choose_expr() breakthrough was all his.

Jake's determination, perseverence, discipline and level of skill are
something to aspire to. It's safe to say that without him, this set
would have gotten nowhere.

> prior to the change CHECK_PACKED_FIELD() was called on values smaller
> than MAX_PACKED_FIELD_SIZE, compare with [j] above, now you call it also
> for the MAX one
(...)
> 
> off by one error? see above

Yes, indeed, thank you for pointing this out. Jake also replied a few
minutes prior to your message.

> PS. incremental diff in a single patch is harder to apply, but easier to
> review, comment both in a single reply == great idea

I'm interpreting this as a positive comment :) I got mixed feedback
about posting diffs in reply to patches, it seems to confuse b4 when
applying.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields()
  2024-12-05  9:52       ` Vladimir Oltean
@ 2024-12-05 21:26         ` Jacob Keller
  0 siblings, 0 replies; 21+ messages in thread
From: Jacob Keller @ 2024-12-05 21:26 UTC (permalink / raw)
  To: Vladimir Oltean, Przemek Kitszel
  Cc: Andrew Morton, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Tony Nguyen, Masahiro Yamada, netdev



On 12/5/2024 1:52 AM, Vladimir Oltean wrote:
> On Thu, Dec 05, 2024 at 12:43:35AM +0100, Przemek Kitszel wrote:
>> On 12/4/24 18:12, Vladimir Oltean wrote:
>>> On Tue, Dec 03, 2024 at 03:53:49PM -0800, Jacob Keller wrote:
>>
>> Amazing stuff :), I really like the fact that you both keep striving for
>> the best result, even way past the point of cut off of most other ;)
> 
> It's all Jake. I openly admit I would have given up and not followed
> through with the review feedback to go to modpost and back.
> Additionally, the __builtin_choose_expr() breakthrough was all his.
> 
> Jake's determination, perseverence, discipline and level of skill are
> something to aspire to. It's safe to say that without him, this set
> would have gotten nowhere.
> 

Thanks :) I'm happy to finally arrive at a version I am quite happy
with. It certainly took longer than I had planned, but I believe the end
result is significant improvement and code which hopefully many other
drivers can adopt.

>> prior to the change CHECK_PACKED_FIELD() was called on values smaller
>> than MAX_PACKED_FIELD_SIZE, compare with [j] above, now you call it also
>> for the MAX one
> (...)
>>
>> off by one error? see above
> 
> Yes, indeed, thank you for pointing this out. Jake also replied a few
> minutes prior to your message.
> 
>> PS. incremental diff in a single patch is harder to apply, but easier to
>> review, comment both in a single reply == great idea
> 
> I'm interpreting this as a positive comment :) I got mixed feedback
> about posting diffs in reply to patches, it seems to confuse b4 when
> applying.

Yea, b4 am / b4 shazam don't seem to handle inline diffs like this very
well. However, I've made good use of:

$ b4 mbox --single-message <message-id>

and then editing the file to extract the diffs myself.

I think there may be some possibility to use the scissors lines as a way
to identify the diffs, but I don't know if b4 has this builtin. See the
section from git mailinfo:

>        --scissors
>            Remove everything in body before a scissors line (e.g. "-- >8 --"). The line represents scissors and perforation marks, and is used to request
>            the reader to cut the message at that line. If that line appears in the body of the message before the patch, everything before it (including the
>            scissors line itself) is ignored when this option is used.
> 
>            This is useful if you want to begin your message in a discussion thread with comments and suggestions on the message you are responding to, and
>            to conclude it with a patch submission, separating the discussion and the beginning of the proposed commit log message with a scissors line.
> 
>            This can be enabled by default with the configuration option mailinfo.scissors.
> 

Perhaps some way of marking diffs with the -- >8 -- lines could be used
as convenient markers for where a diff in a message is, vs regular text.

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2024-12-05 21:26 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-03 23:53 [PATCH net-next v8 00/10] lib: packing: introduce and use (un)pack_fields Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 01/10] lib: packing: create __pack() and __unpack() variants without error checking Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 02/10] lib: packing: demote truncation error in pack() to a warning in __pack() Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 03/10] lib: packing: add pack_fields() and unpack_fields() Jacob Keller
2024-12-04 17:12   ` Vladimir Oltean
2024-12-04 18:47     ` Jacob Keller
2024-12-04 23:24     ` Jacob Keller
2024-12-04 23:52       ` Vladimir Oltean
2024-12-05  0:23         ` Jacob Keller
2024-12-04 23:43     ` Przemek Kitszel
2024-12-05  9:52       ` Vladimir Oltean
2024-12-05 21:26         ` Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 04/10] lib: packing: document recently added APIs Jacob Keller
2024-12-04 23:26   ` Vladimir Oltean
2024-12-04 23:31   ` Vladimir Oltean
2024-12-03 23:53 ` [PATCH net-next v8 05/10] ice: remove int_q_state from ice_tlan_ctx Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 06/10] ice: use structures to keep track of queue context size Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 07/10] ice: use <linux/packing.h> for Tx and Rx queue context data Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 08/10] ice: reduce size of queue context fields Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 09/10] ice: move prefetch enable to ice_setup_rx_ctx Jacob Keller
2024-12-03 23:53 ` [PATCH net-next v8 10/10] ice: cleanup Rx queue context programming functions Jacob Keller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).