diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 3e78949c7a661dc9eae1cd45301569fd5a3c95a6..0bba93f651fcae2cd230582d0e01311264fdf1e6 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -25679,6 +25679,7 @@ ix86_bitint_type_info (int n, struct bitint_info *info)
     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;
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 768ada0af52227a62f666ead3d303887041a9544..0bb6da080f8492629537b6c0160674edb425de9c 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -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
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index a5be2ee048bd60c4439f808a239ce600c04370bc..cb4b57250a825b5c4a43566bff0f72e1e803c207 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -4604,7 +4604,7 @@ clear_padding_bitint_needs_padding_p (tree type)
   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 *buf, tree type,
 	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);
diff --git a/gcc/stor-layout.cc b/gcc/stor-layout.cc
index ba375fa423c95be4bb021226e69d98954b080f36..0c095aa3c3ce087663ee5edf93689116ef9c0f26 100644
--- a/gcc/stor-layout.cc
+++ b/gcc/stor-layout.cc
@@ -2154,7 +2154,8 @@ finish_bitfield_representative (tree repr, tree field)
 	  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));
diff --git a/gcc/target.def b/gcc/target.def
index 08218f3a42adff15150fa815391a9096832665c4..ca030abab6c6694ded178a62dbc4e1dbd20540ca 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -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\
diff --git a/gcc/target.h b/gcc/target.h
index a055b25af7cc77a2d7cce2a4306b9c6b2df450bb..53f03b3efbde118448bbdb86c7519c3c0ac73829 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -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;
 };
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
index 167aea87091d17be0ee9be2d0e52269a655129c9..69f8f8ee01866b124fc77bdd5bd009dc83c85dca 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -5315,7 +5315,8 @@ output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align,
 	  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);