--- gcc/target.h.jj	2023-09-06 17:28:24.228977486 +0200
+++ gcc/target.h	2023-12-14 14:26:48.490047206 +0100
@@ -69,15 +69,23 @@ union cumulative_args_t { void *p; };
 #endif /* !CHECKING_P */
 
 /* Target properties of _BitInt(N) type.  _BitInt(N) is to be represented
-   as series of limb_mode CEIL (N, GET_MODE_PRECISION (limb_mode)) limbs,
-   ordered from least significant to most significant if !big_endian,
+   as series of abi_limb_mode CEIL (N, GET_MODE_PRECISION (abi_limb_mode))
+   limbs, ordered from least significant to most significant if !big_endian,
    otherwise from most significant to least significant.  If extended is
    false, the bits above or equal to N are undefined when stored in a register
    or memory, otherwise they are zero or sign extended depending on if
-   it is unsigned _BitInt(N) or _BitInt(N) / signed _BitInt(N).  */
+   it is unsigned _BitInt(N) or _BitInt(N) / signed _BitInt(N).
+   limb_mode is either the same as abi_limb_mode, or some narrower mode
+   in which _BitInt lowering should actually perform operations in and
+   what libgcc _BitInt helpers should use.
+   E.g. abi_limb_mode could be TImode which is something some processor
+   specific ABI would specify to use, but it would be desirable to handle
+   it as an array of DImode instead for efficiency.
+   Note, abi_limb_mode can be different from limb_mode only if big_endian
+   matches WORDS_BIG_ENDIAN.  */
 
 struct bitint_info {
-  machine_mode limb_mode;
+  machine_mode abi_limb_mode, limb_mode;
   bool big_endian;
   bool extended;
 };
--- gcc/target.def.jj	2023-12-08 08:28:23.644171016 +0100
+++ gcc/target.def	2023-12-14 14:27:25.239537794 +0100
@@ -6357,8 +6357,8 @@ DEFHOOK
 (bitint_type_info,
  "This target hook returns true if @code{_BitInt(@var{N})} is supported and\n\
 provides details on it.  @code{_BitInt(@var{N})} is to be represented as\n\
-series of @code{info->limb_mode}\n\
-@code{CEIL (@var{N}, GET_MODE_PRECISION (info->limb_mode))} limbs,\n\
+series of @code{info->abi_limb_mode}\n\
+@code{CEIL (@var{N}, GET_MODE_PRECISION (info->abi_limb_mode))} limbs,\n\
 ordered from least significant to most significant if\n\
 @code{!info->big_endian}, otherwise from most significant to least\n\
 significant.  If @code{info->extended} is false, the bits above or equal to\n\
--- gcc/varasm.cc.jj	2023-12-01 08:10:44.504299177 +0100
+++ gcc/varasm.cc	2023-12-14 14:55:45.821971713 +0100
@@ -5315,7 +5315,8 @@ output_constant (tree exp, unsigned HOST
 	  tree type = TREE_TYPE (exp);
 	  bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
 	  gcc_assert (ok);
-	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	  scalar_int_mode limb_mode
+	    = as_a <scalar_int_mode> (info.abi_limb_mode);
 	  if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
 	    {
 	      cst = expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
--- gcc/stor-layout.cc.jj	2023-10-08 16:37:31.780273377 +0200
+++ gcc/stor-layout.cc	2023-12-14 14:59:27.147904721 +0100
@@ -2154,7 +2154,8 @@ finish_bitfield_representative (tree rep
 	  unsigned prec = TYPE_PRECISION (TREE_TYPE (field));
 	  bool ok = targetm.c.bitint_type_info (prec, &info);
 	  gcc_assert (ok);
-	  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	  scalar_int_mode limb_mode
+	    = as_a <scalar_int_mode> (info.abi_limb_mode);
 	  unsigned lprec = GET_MODE_PRECISION (limb_mode);
 	  if (prec > lprec)
 	    {
@@ -2416,16 +2417,20 @@ layout_type (tree type)
 	int cnt;
 	bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
 	gcc_assert (ok);
-	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	scalar_int_mode limb_mode
+	  = as_a <scalar_int_mode> (info.abi_limb_mode);
 	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
 	  {
 	    SET_TYPE_MODE (type, limb_mode);
+	    gcc_assert (info.abi_limb_mode == info.limb_mode);
 	    cnt = 1;
 	  }
 	else
 	  {
 	    SET_TYPE_MODE (type, BLKmode);
 	    cnt = CEIL (TYPE_PRECISION (type), GET_MODE_PRECISION (limb_mode));
+	    gcc_assert (info.abi_limb_mode == info.limb_mode
+			|| !info.big_endian == !WORDS_BIG_ENDIAN);
 	  }
 	TYPE_SIZE (type) = bitsize_int (cnt * GET_MODE_BITSIZE (limb_mode));
 	TYPE_SIZE_UNIT (type) = size_int (cnt * GET_MODE_SIZE (limb_mode));
--- gcc/gimple-fold.cc.jj	2023-11-30 20:43:32.273640149 +0100
+++ gcc/gimple-fold.cc	2023-12-14 14:52:13.363915817 +0100
@@ -4604,7 +4604,7 @@ clear_padding_bitint_needs_padding_p (tr
   gcc_assert (ok);
   if (info.extended)
     return false;
-  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+  scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.abi_limb_mode);
   if (TYPE_PRECISION (type) < GET_MODE_PRECISION (limb_mode))
     return true;
   else if (TYPE_PRECISION (type) == GET_MODE_PRECISION (limb_mode))
@@ -4881,7 +4881,8 @@ clear_padding_type (clear_padding_struct
 	struct bitint_info info;
 	bool ok = targetm.c.bitint_type_info (TYPE_PRECISION (type), &info);
 	gcc_assert (ok);
-	scalar_int_mode limb_mode = as_a <scalar_int_mode> (info.limb_mode);
+	scalar_int_mode limb_mode
+	  = as_a <scalar_int_mode> (info.abi_limb_mode);
 	if (TYPE_PRECISION (type) <= GET_MODE_PRECISION (limb_mode))
 	  {
 	    gcc_assert ((size_t) sz <= clear_padding_unit);
--- gcc/config/i386/i386.cc.jj	2023-12-13 11:34:05.836511498 +0100
+++ gcc/config/i386/i386.cc	2023-12-14 14:28:34.074583610 +0100
@@ -25679,6 +25679,7 @@ ix86_bitint_type_info (int n, struct bit
     info->limb_mode = SImode;
   else
     info->limb_mode = DImode;
+  info->abi_limb_mode = info->limb_mode;
   info->big_endian = false;
   info->extended = false;
   return true;
--- gcc/doc/tm.texi.jj	2023-12-08 08:28:23.520172768 +0100
+++ gcc/doc/tm.texi	2023-12-14 14:58:12.643937150 +0100
@@ -1032,8 +1032,8 @@ applied.
 @deftypefn {Target Hook} bool TARGET_C_BITINT_TYPE_INFO (int @var{n}, struct bitint_info *@var{info})
 This target hook returns true if @code{_BitInt(@var{N})} is supported and
 provides details on it.  @code{_BitInt(@var{N})} is to be represented as
-series of @code{info->limb_mode}
-@code{CEIL (@var{N}, GET_MODE_PRECISION (info->limb_mode))} limbs,
+series of @code{info->abi_limb_mode}
+@code{CEIL (@var{N}, GET_MODE_PRECISION (info->abi_limb_mode))} limbs,
 ordered from least significant to most significant if
 @code{!info->big_endian}, otherwise from most significant to least
 significant.  If @code{info->extended} is false, the bits above or equal to
