[2/2] aarch64: Add support for _BitInt
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Testing passed
|
Commit Message
This patch adds support for C23's _BitInt for the AArch64 port when compiling
for little endianness. Big Endianness requires further target-agnostic
support and we therefor disable it for now.
gcc/ChangeLog:
* config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
(aarch64_bitint_type_info): New function.
(aarch64_return_in_memory_1): Return large _BitInt's in memory.
(aarch64_function_arg_alignment): Adapt to correctly return the ABI
mandated alignment of _BitInt(N) where N > 128 as the alignment of
TImode.
(aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
libgcc/ChangeLog:
* config/aarch64/t-softfp: Add fixtfbitint, floatbitinttf and
floatbitinthf to the softfp_extras variable to ensure the
runtime support is available for _BitInt.
---
gcc/config/aarch64/aarch64.cc | 44 +++++++++++++++++++++++++++++++++-
libgcc/config/aarch64/t-softfp | 3 ++-
2 files changed, 45 insertions(+), 2 deletions(-)
Comments
Andre Vieira <andre.simoesdiasvieira@arm.com> writes:
> This patch adds support for C23's _BitInt for the AArch64 port when compiling
> for little endianness. Big Endianness requires further target-agnostic
> support and we therefor disable it for now.
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
> (aarch64_bitint_type_info): New function.
> (aarch64_return_in_memory_1): Return large _BitInt's in memory.
> (aarch64_function_arg_alignment): Adapt to correctly return the ABI
> mandated alignment of _BitInt(N) where N > 128 as the alignment of
> TImode.
> (aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
>
> libgcc/ChangeLog:
>
> * config/aarch64/t-softfp: Add fixtfbitint, floatbitinttf and
> floatbitinthf to the softfp_extras variable to ensure the
> runtime support is available for _BitInt.
> ---
> gcc/config/aarch64/aarch64.cc | 44 +++++++++++++++++++++++++++++++++-
> libgcc/config/aarch64/t-softfp | 3 ++-
> 2 files changed, 45 insertions(+), 2 deletions(-)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index e6bd3fd0bb4..48bac51bc7c 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -6534,7 +6534,7 @@ aarch64_return_in_memory_1 (const_tree type)
> machine_mode ag_mode;
> int count;
>
> - if (!AGGREGATE_TYPE_P (type)
> + if (!(AGGREGATE_TYPE_P (type) || TREE_CODE (type) == BITINT_TYPE)
> && TREE_CODE (type) != COMPLEX_TYPE
> && TREE_CODE (type) != VECTOR_TYPE)
> /* Simple scalar types always returned in registers. */
I guess adding && TREE_CODE (type) != BITINT_TYPE would be more in
keeping with the current code.
> @@ -6618,6 +6618,10 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type,
>
> gcc_assert (TYPE_MODE (type) == mode);
>
> + if (TREE_CODE (type) == BITINT_TYPE
> + && int_size_in_bytes (type) > 16)
> + return GET_MODE_ALIGNMENT (TImode);
> +
Does the type have a different alignment from this? I think a comment
would help.
> if (!AGGREGATE_TYPE_P (type))
> {
> /* The ABI alignment is the natural alignment of the type, without
> @@ -21793,6 +21797,11 @@ aarch64_composite_type_p (const_tree type,
> if (type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE))
> return true;
>
> + if (type
> + && TREE_CODE (type) == BITINT_TYPE
> + && int_size_in_bytes (type) > 16)
> + return true;
> +
Just checking: does this have any practical effect as things stand?
It looks like all callers are either in big-endian code (where it
determines padding for <= 16-byte arguments) and in deciding whether
to pass something as a vector.
Seems OK to keep it on a better-safe-than-sorry basis, just wanted
to check.
It'd be good to have some tests. E.g. maybe one return test for
each of...
> if (mode == BLKmode
> || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
> || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
> @@ -28330,6 +28339,36 @@ aarch64_excess_precision (enum excess_precision_type type)
> return FLT_EVAL_METHOD_UNPREDICTABLE;
> }
>
> +/* Implement TARGET_C_BITINT_TYPE_INFO.
> + Return true if _BitInt(N) is supported and fill its details into *INFO. */
> +bool
> +aarch64_bitint_type_info (int n, struct bitint_info *info)
> +{
> + if (TARGET_BIG_END)
> + return false;
> +
> + if (n <= 8)
> + info->limb_mode = QImode;
> + else if (n <= 16)
> + info->limb_mode = HImode;
> + else if (n <= 32)
> + info->limb_mode = SImode;
> + else if (n <= 64)
> + info->limb_mode = DImode;
> + else if (n <= 128)
> + info->limb_mode = TImode;
> + else
> + info->limb_mode = DImode;
...these conditions, and one argument test in which a _BitInt(n) is
passed as a second argument after a single x0 argument, such as in:
void f(int x, _BitInt(N) y) { ... }
Same for when all argument registers are taken, again with a preceding
stack argument:
void f(int x0, int x1, int x2, int x3,
int x4, int x5, int x6, int x7,
int stack0, _BitInt(N) y)
{
...
}
It'd also be good to have tests for alignof and sizeof.
Can you add a comment explaining why we pick DImode rather than TImode
for the n > 128 case?
Thanks,
Richard
> +
> + if (n > 128)
> + info->abi_limb_mode = TImode;
> + else
> + info->abi_limb_mode = info->limb_mode;
> + info->big_endian = TARGET_BIG_END;
> + info->extended = false;
> + return true;
> +}
> +
> /* Implement TARGET_SCHED_CAN_SPECULATE_INSN. Return true if INSN can be
> scheduled for speculative execution. Reject the long-running division
> and square-root instructions. */
> @@ -30439,6 +30478,9 @@ aarch64_run_selftests (void)
> #undef TARGET_C_EXCESS_PRECISION
> #define TARGET_C_EXCESS_PRECISION aarch64_excess_precision
>
> +#undef TARGET_C_BITINT_TYPE_INFO
> +#define TARGET_C_BITINT_TYPE_INFO aarch64_bitint_type_info
> +
> #undef TARGET_EXPAND_BUILTIN
> #define TARGET_EXPAND_BUILTIN aarch64_expand_builtin
>
> diff --git a/libgcc/config/aarch64/t-softfp b/libgcc/config/aarch64/t-softfp
> index 2e32366f891..a335a34c243 100644
> --- a/libgcc/config/aarch64/t-softfp
> +++ b/libgcc/config/aarch64/t-softfp
> @@ -4,7 +4,8 @@ softfp_extensions := sftf dftf hftf bfsf
> softfp_truncations := tfsf tfdf tfhf tfbf dfbf sfbf hfbf
> softfp_exclude_libgcc2 := n
> softfp_extras += fixhfti fixunshfti floattihf floatuntihf \
> - floatdibf floatundibf floattibf floatuntibf
> + floatdibf floatundibf floattibf floatuntibf \
> + fixtfbitint floatbitinttf floatbitinthf
>
> TARGET_LIBGCC2_CFLAGS += -Wno-missing-prototypes
>
On Thu, Jan 25, 2024 at 05:45:01PM +0000, Andre Vieira wrote:
> This patch adds support for C23's _BitInt for the AArch64 port when compiling
> for little endianness. Big Endianness requires further target-agnostic
> support and we therefor disable it for now.
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
> (aarch64_bitint_type_info): New function.
> (aarch64_return_in_memory_1): Return large _BitInt's in memory.
> (aarch64_function_arg_alignment): Adapt to correctly return the ABI
> mandated alignment of _BitInt(N) where N > 128 as the alignment of
> TImode.
> (aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
>
> libgcc/ChangeLog:
>
> * config/aarch64/t-softfp: Add fixtfbitint, floatbitinttf and
> floatbitinthf to the softfp_extras variable to ensure the
> runtime support is available for _BitInt.
I think this lacks some config/aarch64/t-whatever.ver
additions.
See PR113700 for some more details.
We want the support routines for binary floating point <-> _BitInt
conversions in both libgcc.a and libgcc_s.so.1 and exported from the latter
too at GCC_14.0.0 symver, while decimal floating point <-> _BitInt solely in
libgcc.a (as with all the huge dfp/bid stuff).
Jakub
Hey,
Dropped the first patch and dealt with the comments above, hopefully I
didn't miss any this time.
----------------------------------
This patch adds support for C23's _BitInt for the AArch64 port when
compiling
for little endianness. Big Endianness requires further target-agnostic
support and we therefor disable it for now.
gcc/ChangeLog:
* config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
(aarch64_bitint_type_info): New function.
(aarch64_return_in_memory_1): Return large _BitInt's in memory.
(aarch64_function_arg_alignment): Adapt to correctly return the ABI
mandated alignment of _BitInt(N) where N > 128 as the alignment of
TImode.
(aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
libgcc/ChangeLog:
* config/aarch64/t-softfp (softfp_extras): Add floatbitinthf,
floatbitintbf, floatbitinttf and fixtfbitint.
* config/aarch64/libgcc-softfp.ver (GCC_14.0.0): Add __floatbitinthf,
__floatbitintbf, __floatbitinttf and __fixtfbitint.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/bitint-alignments.c: New test.
* gcc.target/aarch64/bitint-args.c: New test.
* gcc.target/aarch64/bitint-sizes.c: New test.
On 02/02/2024 14:46, Jakub Jelinek wrote:
> On Thu, Jan 25, 2024 at 05:45:01PM +0000, Andre Vieira wrote:
>> This patch adds support for C23's _BitInt for the AArch64 port when compiling
>> for little endianness. Big Endianness requires further target-agnostic
>> support and we therefor disable it for now.
>>
>> gcc/ChangeLog:
>>
>> * config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
>> (aarch64_bitint_type_info): New function.
>> (aarch64_return_in_memory_1): Return large _BitInt's in memory.
>> (aarch64_function_arg_alignment): Adapt to correctly return the ABI
>> mandated alignment of _BitInt(N) where N > 128 as the alignment of
>> TImode.
>> (aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
>>
>> libgcc/ChangeLog:
>>
>> * config/aarch64/t-softfp: Add fixtfbitint, floatbitinttf and
>> floatbitinthf to the softfp_extras variable to ensure the
>> runtime support is available for _BitInt.
>
> I think this lacks some config/aarch64/t-whatever.ver
> additions.
> See PR113700 for some more details.
> We want the support routines for binary floating point <-> _BitInt
> conversions in both libgcc.a and libgcc_s.so.1 and exported from the latter
> too at GCC_14.0.0 symver, while decimal floating point <-> _BitInt solely in
> libgcc.a (as with all the huge dfp/bid stuff).
>
> Jakub
>
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 16318bf925883ecedf9345e53fc0824a553b2747..9bd8d22f6edd9f6c77907ec383f9e8bf055cfb8b 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -6583,6 +6583,7 @@ aarch64_return_in_memory_1 (const_tree type)
int count;
if (!AGGREGATE_TYPE_P (type)
+ && TREE_CODE (type) != BITINT_TYPE
&& TREE_CODE (type) != COMPLEX_TYPE
&& TREE_CODE (type) != VECTOR_TYPE)
/* Simple scalar types always returned in registers. */
@@ -21895,6 +21896,11 @@ aarch64_composite_type_p (const_tree type,
if (type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE))
return true;
+ if (type
+ && TREE_CODE (type) == BITINT_TYPE
+ && int_size_in_bytes (type) > 16)
+ return true;
+
if (mode == BLKmode
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
@@ -28400,6 +28406,42 @@ aarch64_excess_precision (enum excess_precision_type type)
return FLT_EVAL_METHOD_UNPREDICTABLE;
}
+/* Implement TARGET_C_BITINT_TYPE_INFO.
+ Return true if _BitInt(N) is supported and fill its details into *INFO. */
+bool
+aarch64_bitint_type_info (int n, struct bitint_info *info)
+{
+ if (TARGET_BIG_END)
+ return false;
+
+ if (n <= 8)
+ info->limb_mode = QImode;
+ else if (n <= 16)
+ info->limb_mode = HImode;
+ else if (n <= 32)
+ info->limb_mode = SImode;
+ else if (n <= 64)
+ info->limb_mode = DImode;
+ else if (n <= 128)
+ info->limb_mode = TImode;
+ else
+ /* The AAPCS for AArch64 defines _BitInt(N > 128) as an array with
+ type {signed,unsigned} __int128[M] where M*128 >= N. However, to be
+ able to use libgcc's implementation to support large _BitInt's we need
+ to use a LIMB_MODE that is no larger than 'long long'. This is why we
+ use DImode for our internal LIMB_MODE and we define the ABI_LIMB_MODE to
+ be TImode to ensure we are ABI compliant. */
+ info->limb_mode = DImode;
+
+ if (n > 128)
+ info->abi_limb_mode = TImode;
+ else
+ info->abi_limb_mode = info->limb_mode;
+ info->big_endian = TARGET_BIG_END;
+ info->extended = false;
+ return true;
+}
+
/* Implement TARGET_SCHED_CAN_SPECULATE_INSN. Return true if INSN can be
scheduled for speculative execution. Reject the long-running division
and square-root instructions. */
@@ -30524,6 +30566,9 @@ aarch64_run_selftests (void)
#undef TARGET_C_EXCESS_PRECISION
#define TARGET_C_EXCESS_PRECISION aarch64_excess_precision
+#undef TARGET_C_BITINT_TYPE_INFO
+#define TARGET_C_BITINT_TYPE_INFO aarch64_bitint_type_info
+
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN aarch64_expand_builtin
diff --git a/gcc/testsuite/gcc.target/aarch64/bitint-alignments.c b/gcc/testsuite/gcc.target/aarch64/bitint-alignments.c
new file mode 100644
index 0000000000000000000000000000000000000000..4de31fe7ebd933247911c48ace01ab520fe194a3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bitint-alignments.c
@@ -0,0 +1,58 @@
+/* { dg-do run } */
+/* { dg-options "-std=c23" } */
+
+static long unsigned int
+calc_size (int n)
+{
+ if (n > 64)
+ return alignof(__int128_t);
+ if (n > 32)
+ return alignof(long long);
+ if (n > 16)
+ return alignof(int);
+ if (n > 8)
+ return alignof(short);
+ else
+ return alignof(char);
+}
+
+#define CHECK_ALIGNMENT(N) \
+ if (alignof(_BitInt(N)) != calc_size(N)) \
+ __builtin_abort ();
+
+int main (void)
+{
+ CHECK_ALIGNMENT(2);
+ CHECK_ALIGNMENT(3);
+ CHECK_ALIGNMENT(7);
+ CHECK_ALIGNMENT(8);
+ CHECK_ALIGNMENT(9);
+ CHECK_ALIGNMENT(13);
+ CHECK_ALIGNMENT(15);
+ CHECK_ALIGNMENT(16);
+ CHECK_ALIGNMENT(17);
+ CHECK_ALIGNMENT(24);
+ CHECK_ALIGNMENT(31);
+ CHECK_ALIGNMENT(32);
+ CHECK_ALIGNMENT(33);
+ CHECK_ALIGNMENT(42);
+ CHECK_ALIGNMENT(53);
+ CHECK_ALIGNMENT(63);
+ CHECK_ALIGNMENT(64);
+ CHECK_ALIGNMENT(65);
+ CHECK_ALIGNMENT(79);
+ CHECK_ALIGNMENT(96);
+ CHECK_ALIGNMENT(113);
+ CHECK_ALIGNMENT(127);
+ CHECK_ALIGNMENT(128);
+ CHECK_ALIGNMENT(129);
+ CHECK_ALIGNMENT(153);
+ CHECK_ALIGNMENT(255);
+ CHECK_ALIGNMENT(256);
+ CHECK_ALIGNMENT(257);
+ CHECK_ALIGNMENT(353);
+ CHECK_ALIGNMENT(512);
+ CHECK_ALIGNMENT(620);
+ CHECK_ALIGNMENT(1024);
+ CHECK_ALIGNMENT(30000);
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/bitint-args.c b/gcc/testsuite/gcc.target/aarch64/bitint-args.c
new file mode 100644
index 0000000000000000000000000000000000000000..a6806ce609b3262c942e722918081ad466853910
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bitint-args.c
@@ -0,0 +1,84 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -O -fno-stack-clash-protection -g" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#define CHECK_ARG(N) \
+_BitInt(N) g##N; \
+void f##N(int x, _BitInt(N) y) \
+{ \
+ g##N = y; \
+}
+
+
+CHECK_ARG(2)
+/*
+** f2:
+** sbfiz w1, w1, 6, 2
+** asr w1, w1, 6
+** adrp x0, .*
+** strb w1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(8)
+/*
+** f8:
+** adrp x0, .*
+** strb w1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(9)
+/*
+** f9:
+** sbfiz w1, w1, 7, 9
+** asr w1, w1, 7
+** adrp x0, .*
+** strh w1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(16)
+/*
+** f16:
+** adrp x0, .*
+** strh w1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(19)
+/*
+** f19:
+** sbfx x1, x1, 0, 19
+** adrp x0, .*
+** str w1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(32)
+/*
+** f32:
+** adrp x0, .*
+** str w1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(42)
+/*
+** f42:
+** sbfx x1, x1, 0, 42
+** adrp x0, .*
+** str x1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(64)
+/*
+** f64:
+** adrp x0, .*
+** str x1, \[x0, [^\]]*\]
+** ret
+*/
+CHECK_ARG(65)
+/*
+** f65:
+** extr x3, x3, x2, 1
+** asr x3, x3, 63
+** adrp x0, .*
+** add x0, x0, .*
+** stp x2, x3, \[x0, [^\]]*\]
+** ret
+*/
diff --git a/gcc/testsuite/gcc.target/aarch64/bitint-sizes.c b/gcc/testsuite/gcc.target/aarch64/bitint-sizes.c
new file mode 100644
index 0000000000000000000000000000000000000000..bee9abfe91b0dcb1ec335ef9ed02f212f7aa34b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bitint-sizes.c
@@ -0,0 +1,60 @@
+/* { dg-do run } */
+/* { dg-options "-std=c23" } */
+
+static long unsigned int
+calc_size (int n)
+{
+ if (n > 128)
+ return ((n - 1)/128 + 1) * sizeof(__int128_t);
+ if (n > 64)
+ return sizeof(__int128_t);
+ if (n > 32)
+ return sizeof(long long);
+ if (n > 16)
+ return sizeof(int);
+ if (n > 8)
+ return sizeof(short);
+ else
+ return sizeof(char);
+}
+
+#define CHECK_SIZE(N) \
+ if (sizeof(_BitInt(N)) != calc_size(N)) \
+ __builtin_abort ();
+
+int main (void)
+{
+ CHECK_SIZE(2);
+ CHECK_SIZE(3);
+ CHECK_SIZE(7);
+ CHECK_SIZE(8);
+ CHECK_SIZE(9);
+ CHECK_SIZE(13);
+ CHECK_SIZE(15);
+ CHECK_SIZE(16);
+ CHECK_SIZE(17);
+ CHECK_SIZE(24);
+ CHECK_SIZE(31);
+ CHECK_SIZE(32);
+ CHECK_SIZE(33);
+ CHECK_SIZE(42);
+ CHECK_SIZE(53);
+ CHECK_SIZE(63);
+ CHECK_SIZE(64);
+ CHECK_SIZE(65);
+ CHECK_SIZE(79);
+ CHECK_SIZE(96);
+ CHECK_SIZE(113);
+ CHECK_SIZE(127);
+ CHECK_SIZE(128);
+ CHECK_SIZE(129);
+ CHECK_SIZE(153);
+ CHECK_SIZE(255);
+ CHECK_SIZE(256);
+ CHECK_SIZE(257);
+ CHECK_SIZE(353);
+ CHECK_SIZE(512);
+ CHECK_SIZE(620);
+ CHECK_SIZE(1024);
+ CHECK_SIZE(30000);
+}
diff --git a/libgcc/config/aarch64/libgcc-softfp.ver b/libgcc/config/aarch64/libgcc-softfp.ver
index e73f5f9129776d39eb5020ed7398dc59aba2d197..9ba857036abef99913eebe56971eaaabf5e1952e 100644
--- a/libgcc/config/aarch64/libgcc-softfp.ver
+++ b/libgcc/config/aarch64/libgcc-softfp.ver
@@ -39,3 +39,11 @@ GCC_13.0.0 {
__trunctfbf2
__trunchfbf2
}
+
+%inherit GCC_14.0.0 GCC_13.0.0
+GCC_14.0.0 {
+ __fixtfbitint
+ __floatbitintbf
+ __floatbitinthf
+ __floatbitinttf
+}
diff --git a/libgcc/config/aarch64/t-softfp b/libgcc/config/aarch64/t-softfp
index 2e32366f891361e2056c680b2e36edb1871c7670..80e7e77a545cc10eeccd84eea092871751c3e139 100644
--- a/libgcc/config/aarch64/t-softfp
+++ b/libgcc/config/aarch64/t-softfp
@@ -4,7 +4,8 @@ softfp_extensions := sftf dftf hftf bfsf
softfp_truncations := tfsf tfdf tfhf tfbf dfbf sfbf hfbf
softfp_exclude_libgcc2 := n
softfp_extras += fixhfti fixunshfti floattihf floatuntihf \
- floatdibf floatundibf floattibf floatuntibf
+ floatdibf floatundibf floattibf floatuntibf \
+ floatbitinthf floatbitintbf floatbitinttf fixtfbitint
TARGET_LIBGCC2_CFLAGS += -Wno-missing-prototypes
On Tue, Feb 27, 2024 at 01:40:09PM +0000, Andre Vieira (lists) wrote:
> Dropped the first patch and dealt with the comments above, hopefully I
> didn't miss any this time.
>
> ----------------------------------
>
> This patch adds support for C23's _BitInt for the AArch64 port when
> compiling
> for little endianness. Big Endianness requires further target-agnostic
> support and we therefor disable it for now.
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
> (aarch64_bitint_type_info): New function.
> (aarch64_return_in_memory_1): Return large _BitInt's in memory.
> (aarch64_function_arg_alignment): Adapt to correctly return the ABI
> mandated alignment of _BitInt(N) where N > 128 as the alignment of
> TImode.
> (aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
>
> libgcc/ChangeLog:
>
> * config/aarch64/t-softfp (softfp_extras): Add floatbitinthf,
> floatbitintbf, floatbitinttf and fixtfbitint.
> * config/aarch64/libgcc-softfp.ver (GCC_14.0.0): Add __floatbitinthf,
> __floatbitintbf, __floatbitinttf and __fixtfbitint.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/aarch64/bitint-alignments.c: New test.
> * gcc.target/aarch64/bitint-args.c: New test.
> * gcc.target/aarch64/bitint-sizes.c: New test.
LGTM, but as this is mostly aarch64 specific, I'll defer the final ack
to Richard or Kyrylo.
Jakub
"Andre Vieira (lists)" <andre.simoesdiasvieira@arm.com> writes:
> Hey,
>
> Dropped the first patch and dealt with the comments above, hopefully I
> didn't miss any this time.
>
> ----------------------------------
>
> This patch adds support for C23's _BitInt for the AArch64 port when
> compiling
> for little endianness. Big Endianness requires further target-agnostic
> support and we therefor disable it for now.
>
> gcc/ChangeLog:
>
> * config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
> (aarch64_bitint_type_info): New function.
> (aarch64_return_in_memory_1): Return large _BitInt's in memory.
> (aarch64_function_arg_alignment): Adapt to correctly return the ABI
> mandated alignment of _BitInt(N) where N > 128 as the alignment of
> TImode.
> (aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
>
> libgcc/ChangeLog:
>
> * config/aarch64/t-softfp (softfp_extras): Add floatbitinthf,
> floatbitintbf, floatbitinttf and fixtfbitint.
> * config/aarch64/libgcc-softfp.ver (GCC_14.0.0): Add __floatbitinthf,
> __floatbitintbf, __floatbitinttf and __fixtfbitint.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/aarch64/bitint-alignments.c: New test.
> * gcc.target/aarch64/bitint-args.c: New test.
> * gcc.target/aarch64/bitint-sizes.c: New test.
>
>
> On 02/02/2024 14:46, Jakub Jelinek wrote:
>> On Thu, Jan 25, 2024 at 05:45:01PM +0000, Andre Vieira wrote:
>>> This patch adds support for C23's _BitInt for the AArch64 port when compiling
>>> for little endianness. Big Endianness requires further target-agnostic
>>> support and we therefor disable it for now.
>>>
>>> gcc/ChangeLog:
>>>
>>> * config/aarch64/aarch64.cc (TARGET_C_BITINT_TYPE_INFO): Declare MACRO.
>>> (aarch64_bitint_type_info): New function.
>>> (aarch64_return_in_memory_1): Return large _BitInt's in memory.
>>> (aarch64_function_arg_alignment): Adapt to correctly return the ABI
>>> mandated alignment of _BitInt(N) where N > 128 as the alignment of
>>> TImode.
>>> (aarch64_composite_type_p): Return true for _BitInt(N), where N > 128.
>>>
>>> libgcc/ChangeLog:
>>>
>>> * config/aarch64/t-softfp: Add fixtfbitint, floatbitinttf and
>>> floatbitinthf to the softfp_extras variable to ensure the
>>> runtime support is available for _BitInt.
>>
>> I think this lacks some config/aarch64/t-whatever.ver
>> additions.
>> See PR113700 for some more details.
>> We want the support routines for binary floating point <-> _BitInt
>> conversions in both libgcc.a and libgcc_s.so.1 and exported from the latter
>> too at GCC_14.0.0 symver, while decimal floating point <-> _BitInt solely in
>> libgcc.a (as with all the huge dfp/bid stuff).
>>
>> Jakub
>>
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 16318bf925883ecedf9345e53fc0824a553b2747..9bd8d22f6edd9f6c77907ec383f9e8bf055cfb8b 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -6583,6 +6583,7 @@ aarch64_return_in_memory_1 (const_tree type)
> int count;
>
> if (!AGGREGATE_TYPE_P (type)
> + && TREE_CODE (type) != BITINT_TYPE
> && TREE_CODE (type) != COMPLEX_TYPE
> && TREE_CODE (type) != VECTOR_TYPE)
> /* Simple scalar types always returned in registers. */
> @@ -21895,6 +21896,11 @@ aarch64_composite_type_p (const_tree type,
> if (type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE))
> return true;
>
> + if (type
> + && TREE_CODE (type) == BITINT_TYPE
> + && int_size_in_bytes (type) > 16)
> + return true;
> +
Think I probably said this before, but for the record: I don't think
the above code has any practical effect, but I agree it's probably better
to include it for completeness.
> if (mode == BLKmode
> || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
> || GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
> @@ -28400,6 +28406,42 @@ aarch64_excess_precision (enum excess_precision_type type)
> return FLT_EVAL_METHOD_UNPREDICTABLE;
> }
>
> +/* Implement TARGET_C_BITINT_TYPE_INFO.
> + Return true if _BitInt(N) is supported and fill its details into *INFO. */
> +bool
> +aarch64_bitint_type_info (int n, struct bitint_info *info)
> +{
> + if (TARGET_BIG_END)
> + return false;
> +
> + if (n <= 8)
> + info->limb_mode = QImode;
> + else if (n <= 16)
> + info->limb_mode = HImode;
> + else if (n <= 32)
> + info->limb_mode = SImode;
> + else if (n <= 64)
> + info->limb_mode = DImode;
> + else if (n <= 128)
> + info->limb_mode = TImode;
> + else
> + /* The AAPCS for AArch64 defines _BitInt(N > 128) as an array with
> + type {signed,unsigned} __int128[M] where M*128 >= N. However, to be
> + able to use libgcc's implementation to support large _BitInt's we need
> + to use a LIMB_MODE that is no larger than 'long long'. This is why we
> + use DImode for our internal LIMB_MODE and we define the ABI_LIMB_MODE to
> + be TImode to ensure we are ABI compliant. */
> + info->limb_mode = DImode;
> +
> + if (n > 128)
> + info->abi_limb_mode = TImode;
> + else
> + info->abi_limb_mode = info->limb_mode;
> + info->big_endian = TARGET_BIG_END;
> + info->extended = false;
> + return true;
> +}
> +
> /* Implement TARGET_SCHED_CAN_SPECULATE_INSN. Return true if INSN can be
> scheduled for speculative execution. Reject the long-running division
> and square-root instructions. */
> @@ -30524,6 +30566,9 @@ aarch64_run_selftests (void)
> #undef TARGET_C_EXCESS_PRECISION
> #define TARGET_C_EXCESS_PRECISION aarch64_excess_precision
>
> +#undef TARGET_C_BITINT_TYPE_INFO
> +#define TARGET_C_BITINT_TYPE_INFO aarch64_bitint_type_info
> +
> #undef TARGET_EXPAND_BUILTIN
> #define TARGET_EXPAND_BUILTIN aarch64_expand_builtin
>
OK for code bits. I've got some comments about the tests though:
> diff --git a/gcc/testsuite/gcc.target/aarch64/bitint-alignments.c b/gcc/testsuite/gcc.target/aarch64/bitint-alignments.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..4de31fe7ebd933247911c48ace01ab520fe194a3
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/bitint-alignments.c
> @@ -0,0 +1,58 @@
> +/* { dg-do run } */
> +/* { dg-options "-std=c23" } */
> +
> +static long unsigned int
> +calc_size (int n)
> +{
> + if (n > 64)
> + return alignof(__int128_t);
> + if (n > 32)
> + return alignof(long long);
> + if (n > 16)
> + return alignof(int);
> + if (n > 8)
> + return alignof(short);
> + else
> + return alignof(char);
> +}
> +
> +#define CHECK_ALIGNMENT(N) \
> + if (alignof(_BitInt(N)) != calc_size(N)) \
> + __builtin_abort ();
> +
> +int main (void)
> +{
> + CHECK_ALIGNMENT(2);
> + CHECK_ALIGNMENT(3);
> + CHECK_ALIGNMENT(7);
> + CHECK_ALIGNMENT(8);
> + CHECK_ALIGNMENT(9);
> + CHECK_ALIGNMENT(13);
> + CHECK_ALIGNMENT(15);
> + CHECK_ALIGNMENT(16);
> + CHECK_ALIGNMENT(17);
> + CHECK_ALIGNMENT(24);
> + CHECK_ALIGNMENT(31);
> + CHECK_ALIGNMENT(32);
> + CHECK_ALIGNMENT(33);
> + CHECK_ALIGNMENT(42);
> + CHECK_ALIGNMENT(53);
> + CHECK_ALIGNMENT(63);
> + CHECK_ALIGNMENT(64);
> + CHECK_ALIGNMENT(65);
> + CHECK_ALIGNMENT(79);
> + CHECK_ALIGNMENT(96);
> + CHECK_ALIGNMENT(113);
> + CHECK_ALIGNMENT(127);
> + CHECK_ALIGNMENT(128);
> + CHECK_ALIGNMENT(129);
> + CHECK_ALIGNMENT(153);
> + CHECK_ALIGNMENT(255);
> + CHECK_ALIGNMENT(256);
> + CHECK_ALIGNMENT(257);
> + CHECK_ALIGNMENT(353);
> + CHECK_ALIGNMENT(512);
> + CHECK_ALIGNMENT(620);
> + CHECK_ALIGNMENT(1024);
> + CHECK_ALIGNMENT(30000);
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/bitint-args.c b/gcc/testsuite/gcc.target/aarch64/bitint-args.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..a6806ce609b3262c942e722918081ad466853910
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/bitint-args.c
> @@ -0,0 +1,84 @@
> +/* { dg-do compile } */
> +/* { dg-options "-std=c23 -O -fno-stack-clash-protection -g" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +#define CHECK_ARG(N) \
> +_BitInt(N) g##N; \
> +void f##N(int x, _BitInt(N) y) \
> +{ \
> + g##N = y; \
> +}
> +
> +
> +CHECK_ARG(2)
> +/*
> +** f2:
> +** sbfiz w1, w1, 6, 2
> +** asr w1, w1, 6
> +** adrp x0, .*
> +** strb w1, \[x0, [^\]]*\]
> +** ret
There's no requirement for w1 or x0 to be used as the temporaries,
so everything except the incoming w1 should be escaped and captured. E.g.:
> +** sbfiz (w[0-9]+), w1, 6, 2
> +** asr (w[0-9]+), \1, 6
> +** adrp (x[0-9]+), .*
> +** strb \2, \[\3, [^\]]*\]
> +** ret
FWIW, passing a pointer a _BitInt(N) instead of x would avoid the need
for the adrp, and so make the tests more robust against code order. E.g.:
void f##N(_BitInt(N) *ptr, _BitInt(N) y) \
{ \
*ptr = y; \
}
could be matched by:
> +** sbfiz (w[0-9]+), w1, 6, 2
> +** asr (w[0-9]+), \1, 6
> +** strb \2, \[x0\]
> +** ret
Do you know why we don't use a single SBFX? Probably worth filing a PR
if we don't have one already.
> +*/
> +CHECK_ARG(8)
> +/*
> +** f8:
> +** adrp x0, .*
> +** strb w1, \[x0, [^\]]*\]
> +** ret
> +*/
> +CHECK_ARG(9)
> +/*
> +** f9:
> +** sbfiz w1, w1, 7, 9
> +** asr w1, w1, 7
> +** adrp x0, .*
> +** strh w1, \[x0, [^\]]*\]
> +** ret
> +*/
> +CHECK_ARG(16)
> +/*
> +** f16:
> +** adrp x0, .*
> +** strh w1, \[x0, [^\]]*\]
> +** ret
> +*/
> +CHECK_ARG(19)
> +/*
> +** f19:
> +** sbfx x1, x1, 0, 19
> +** adrp x0, .*
> +** str w1, \[x0, [^\]]*\]
> +** ret
> +*/
> +CHECK_ARG(32)
> +/*
> +** f32:
> +** adrp x0, .*
> +** str w1, \[x0, [^\]]*\]
> +** ret
> +*/
> +CHECK_ARG(42)
> +/*
> +** f42:
> +** sbfx x1, x1, 0, 42
> +** adrp x0, .*
> +** str x1, \[x0, [^\]]*\]
> +** ret
> +*/
> +CHECK_ARG(64)
> +/*
> +** f64:
> +** adrp x0, .*
> +** str x1, \[x0, [^\]]*\]
> +** ret
> +*/
> +CHECK_ARG(65)
> +/*
> +** f65:
> +** extr x3, x3, x2, 1
> +** asr x3, x3, 63
> +** adrp x0, .*
> +** add x0, x0, .*
> +** stp x2, x3, \[x0, [^\]]*\]
> +** ret
> +*/
Can you add tests for 127, 128 and 129 too?
I think we should also have ABI tests for more exotic combinations, such as:
struct S1 {
_BitInt(120) x1 : 120;
_BitInt(8) x2 : 8;
};
struct S2 {
_BitInt(120) x1 : 120;
_BitInt(8) x2 : 8;
};
struct S3 {
_BitInt(125) x1 : 63;
unsigned _BitInt(125) x2 : 62;
};
struct S4 {
_BitInt(5) x1 : 5;
__attribute__((packed, aligned(2))) _BitInt(300) x2;
};
etc.
It'd also be good to have a version of
gcc.target/aarch64/bitfield-abi-warning.* that tests _BitInts rather
than plain integers --- not for the warning as such (which I guess we
shouldn't emit), but for the code generation. It took Christophe and I
a lot of effort to untangle the brokenness captured in those tests, so
it would be good to preempt something similar happening here :)
It's also be good to make sure that the alignment on things like:
typedef _BitInt(100) bi1 __attribute__((aligned(1)));
typedef _BitInt(8) bi2 __attribute__((aligned(16)));
do not change how bi1 and bi2 are passed (which might be partly
covered by the bitfield warning tests, can't remember).
Thanks,
Richard
> diff --git a/gcc/testsuite/gcc.target/aarch64/bitint-sizes.c b/gcc/testsuite/gcc.target/aarch64/bitint-sizes.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..bee9abfe91b0dcb1ec335ef9ed02f212f7aa34b7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/bitint-sizes.c
> @@ -0,0 +1,60 @@
> +/* { dg-do run } */
> +/* { dg-options "-std=c23" } */
> +
> +static long unsigned int
> +calc_size (int n)
> +{
> + if (n > 128)
> + return ((n - 1)/128 + 1) * sizeof(__int128_t);
> + if (n > 64)
> + return sizeof(__int128_t);
> + if (n > 32)
> + return sizeof(long long);
> + if (n > 16)
> + return sizeof(int);
> + if (n > 8)
> + return sizeof(short);
> + else
> + return sizeof(char);
> +}
> +
> +#define CHECK_SIZE(N) \
> + if (sizeof(_BitInt(N)) != calc_size(N)) \
> + __builtin_abort ();
> +
> +int main (void)
> +{
> + CHECK_SIZE(2);
> + CHECK_SIZE(3);
> + CHECK_SIZE(7);
> + CHECK_SIZE(8);
> + CHECK_SIZE(9);
> + CHECK_SIZE(13);
> + CHECK_SIZE(15);
> + CHECK_SIZE(16);
> + CHECK_SIZE(17);
> + CHECK_SIZE(24);
> + CHECK_SIZE(31);
> + CHECK_SIZE(32);
> + CHECK_SIZE(33);
> + CHECK_SIZE(42);
> + CHECK_SIZE(53);
> + CHECK_SIZE(63);
> + CHECK_SIZE(64);
> + CHECK_SIZE(65);
> + CHECK_SIZE(79);
> + CHECK_SIZE(96);
> + CHECK_SIZE(113);
> + CHECK_SIZE(127);
> + CHECK_SIZE(128);
> + CHECK_SIZE(129);
> + CHECK_SIZE(153);
> + CHECK_SIZE(255);
> + CHECK_SIZE(256);
> + CHECK_SIZE(257);
> + CHECK_SIZE(353);
> + CHECK_SIZE(512);
> + CHECK_SIZE(620);
> + CHECK_SIZE(1024);
> + CHECK_SIZE(30000);
> +}
> diff --git a/libgcc/config/aarch64/libgcc-softfp.ver b/libgcc/config/aarch64/libgcc-softfp.ver
> index e73f5f9129776d39eb5020ed7398dc59aba2d197..9ba857036abef99913eebe56971eaaabf5e1952e 100644
> --- a/libgcc/config/aarch64/libgcc-softfp.ver
> +++ b/libgcc/config/aarch64/libgcc-softfp.ver
> @@ -39,3 +39,11 @@ GCC_13.0.0 {
> __trunctfbf2
> __trunchfbf2
> }
> +
> +%inherit GCC_14.0.0 GCC_13.0.0
> +GCC_14.0.0 {
> + __fixtfbitint
> + __floatbitintbf
> + __floatbitinthf
> + __floatbitinttf
> +}
> diff --git a/libgcc/config/aarch64/t-softfp b/libgcc/config/aarch64/t-softfp
> index 2e32366f891361e2056c680b2e36edb1871c7670..80e7e77a545cc10eeccd84eea092871751c3e139 100644
> --- a/libgcc/config/aarch64/t-softfp
> +++ b/libgcc/config/aarch64/t-softfp
> @@ -4,7 +4,8 @@ softfp_extensions := sftf dftf hftf bfsf
> softfp_truncations := tfsf tfdf tfhf tfbf dfbf sfbf hfbf
> softfp_exclude_libgcc2 := n
> softfp_extras += fixhfti fixunshfti floattihf floatuntihf \
> - floatdibf floatundibf floattibf floatuntibf
> + floatdibf floatundibf floattibf floatuntibf \
> + floatbitinthf floatbitintbf floatbitinttf fixtfbitint
>
> TARGET_LIBGCC2_CFLAGS += -Wno-missing-prototypes
>
@@ -6534,7 +6534,7 @@ aarch64_return_in_memory_1 (const_tree type)
machine_mode ag_mode;
int count;
- if (!AGGREGATE_TYPE_P (type)
+ if (!(AGGREGATE_TYPE_P (type) || TREE_CODE (type) == BITINT_TYPE)
&& TREE_CODE (type) != COMPLEX_TYPE
&& TREE_CODE (type) != VECTOR_TYPE)
/* Simple scalar types always returned in registers. */
@@ -6618,6 +6618,10 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type,
gcc_assert (TYPE_MODE (type) == mode);
+ if (TREE_CODE (type) == BITINT_TYPE
+ && int_size_in_bytes (type) > 16)
+ return GET_MODE_ALIGNMENT (TImode);
+
if (!AGGREGATE_TYPE_P (type))
{
/* The ABI alignment is the natural alignment of the type, without
@@ -21793,6 +21797,11 @@ aarch64_composite_type_p (const_tree type,
if (type && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE))
return true;
+ if (type
+ && TREE_CODE (type) == BITINT_TYPE
+ && int_size_in_bytes (type) > 16)
+ return true;
+
if (mode == BLKmode
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
@@ -28330,6 +28339,36 @@ aarch64_excess_precision (enum excess_precision_type type)
return FLT_EVAL_METHOD_UNPREDICTABLE;
}
+/* Implement TARGET_C_BITINT_TYPE_INFO.
+ Return true if _BitInt(N) is supported and fill its details into *INFO. */
+bool
+aarch64_bitint_type_info (int n, struct bitint_info *info)
+{
+ if (TARGET_BIG_END)
+ return false;
+
+ if (n <= 8)
+ info->limb_mode = QImode;
+ else if (n <= 16)
+ info->limb_mode = HImode;
+ else if (n <= 32)
+ info->limb_mode = SImode;
+ else if (n <= 64)
+ info->limb_mode = DImode;
+ else if (n <= 128)
+ info->limb_mode = TImode;
+ else
+ info->limb_mode = DImode;
+
+ if (n > 128)
+ info->abi_limb_mode = TImode;
+ else
+ info->abi_limb_mode = info->limb_mode;
+ info->big_endian = TARGET_BIG_END;
+ info->extended = false;
+ return true;
+}
+
/* Implement TARGET_SCHED_CAN_SPECULATE_INSN. Return true if INSN can be
scheduled for speculative execution. Reject the long-running division
and square-root instructions. */
@@ -30439,6 +30478,9 @@ aarch64_run_selftests (void)
#undef TARGET_C_EXCESS_PRECISION
#define TARGET_C_EXCESS_PRECISION aarch64_excess_precision
+#undef TARGET_C_BITINT_TYPE_INFO
+#define TARGET_C_BITINT_TYPE_INFO aarch64_bitint_type_info
+
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN aarch64_expand_builtin
@@ -4,7 +4,8 @@ softfp_extensions := sftf dftf hftf bfsf
softfp_truncations := tfsf tfdf tfhf tfbf dfbf sfbf hfbf
softfp_exclude_libgcc2 := n
softfp_extras += fixhfti fixunshfti floattihf floatuntihf \
- floatdibf floatundibf floattibf floatuntibf
+ floatdibf floatundibf floattibf floatuntibf \
+ fixtfbitint floatbitinttf floatbitinthf
TARGET_LIBGCC2_CFLAGS += -Wno-missing-prototypes