bitint: Introduce abi_limb_mode

Message ID ZXt/yRs1g4MhLj+W@tucnak
State Unresolved
Headers
Series bitint: Introduce abi_limb_mode |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek Dec. 14, 2023, 10:20 p.m. UTC
  Hi!

Given what I saw in the aarch64/arm psABIs for BITINT_TYPE, as I said
earlier I'm afraid we need to differentiate between the limb mode/precision
specified in the psABIs (what is used to decide how it is actually passed,
aligned or what size it has) vs. what limb mode/precision should be used
during bitint lowering and in the libgcc bitint APIs.
While in the x86_64 psABI a limb is 64-bit, which is perfect for both,
that is a wordsize which we can perform operations natively in,
e.g. aarch64 wants 128-bit limbs for alignment/sizing purposes, but
on the bitint lowering side I believe it would result in terribly bad code
and on the libgcc side wouldn't work at all (because it relies there on
longlong.h support).

So, the following patch makes it possible for aarch64 to use TImode
as abi_limb_mode for _BitInt(129) and larger, while using DImode as
limb_mode.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2023-12-14  Jakub Jelinek  <jakub@redhat.com>

	* target.h (struct bitint_info): Add abi_limb_mode member, adjust
	comment.
	* target.def (bitint_type_info): Mention abi_limb_mode instead of
	limb_mode.
	* varasm.cc (output_constant): Use abi_limb_mode rather than
	limb_mode.
	* stor-layout.cc (finish_bitfield_representative): Likewise.  Assert
	that if precision is smaller or equal to abi_limb_mode precision or
	if info.big_endian is different from WORDS_BIG_ENDIAN, info.limb_mode
	must be the same as info.abi_limb_mode.
	(layout_type): Use abi_limb_mode rather than limb_mode.
	* gimple-fold.cc (clear_padding_bitint_needs_padding_p): Likewise.
	(clear_padding_type): Likewise.
	* config/i386/i386.cc (ix86_bitint_type_info): Also set
	info->abi_limb_mode.
	* doc/tm.texi: Regenerated.


	Jakub
  

Comments

Richard Biener Dec. 15, 2023, 10:39 a.m. UTC | #1
On Thu, 14 Dec 2023, Jakub Jelinek wrote:

> Hi!
> 
> Given what I saw in the aarch64/arm psABIs for BITINT_TYPE, as I said
> earlier I'm afraid we need to differentiate between the limb mode/precision
> specified in the psABIs (what is used to decide how it is actually passed,
> aligned or what size it has) vs. what limb mode/precision should be used
> during bitint lowering and in the libgcc bitint APIs.
> While in the x86_64 psABI a limb is 64-bit, which is perfect for both,
> that is a wordsize which we can perform operations natively in,
> e.g. aarch64 wants 128-bit limbs for alignment/sizing purposes, but
> on the bitint lowering side I believe it would result in terribly bad code
> and on the libgcc side wouldn't work at all (because it relies there on
> longlong.h support).
> 
> So, the following patch makes it possible for aarch64 to use TImode
> as abi_limb_mode for _BitInt(129) and larger, while using DImode as
> limb_mode.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Thanks,
Richard.

> 2023-12-14  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* target.h (struct bitint_info): Add abi_limb_mode member, adjust
> 	comment.
> 	* target.def (bitint_type_info): Mention abi_limb_mode instead of
> 	limb_mode.
> 	* varasm.cc (output_constant): Use abi_limb_mode rather than
> 	limb_mode.
> 	* stor-layout.cc (finish_bitfield_representative): Likewise.  Assert
> 	that if precision is smaller or equal to abi_limb_mode precision or
> 	if info.big_endian is different from WORDS_BIG_ENDIAN, info.limb_mode
> 	must be the same as info.abi_limb_mode.
> 	(layout_type): Use abi_limb_mode rather than limb_mode.
> 	* gimple-fold.cc (clear_padding_bitint_needs_padding_p): Likewise.
> 	(clear_padding_type): Likewise.
> 	* config/i386/i386.cc (ix86_bitint_type_info): Also set
> 	info->abi_limb_mode.
> 	* doc/tm.texi: Regenerated.
> 
> --- 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
> 
> 	Jakub
> 
>
  

Patch

--- 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