[v2] aarch64: Add fp8 scalar types

Message ID 20240919130923.2657996-1-claudio.bantaloukas@arm.com
State New
Headers
Series [v2] aarch64: Add fp8 scalar types |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

Claudio Bantaloukas Sept. 19, 2024, 1:09 p.m. UTC
  The ACLE defines a new scalar type, __mfp8. This is an opaque 8bit types that
can only be used by fp8 intrinsics. Additionally, the mfloat8_t type is made
available in arm_neon.h and arm_sve.h as an alias of the same.

This implementation uses an unsigned INTEGER_TYPE, with precision 8 to
represent __mfp8. Conversions to int and other types are disabled via the
TARGET_INVALID_CONVERSION hook.
Additionally, operations that are typically available to integer types are
disabled via TARGET_INVALID_UNARY_OP and TARGET_INVALID_BINARY_OP hooks.

gcc/ChangeLog:

	* config/aarch64/aarch64-builtins.cc (aarch64_mfp8_type_node): Add node
	for __mfp8 type.
	(aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
	(aarch64_init_fp8_types): New function to initialise fp8 types and
	register with language backends.
	* config/aarch64/aarch64.cc (aarch64_mangle_type): Add ABI mangling for
	new type.
	(aarch64_invalid_conversion): Add function implementing
	TARGET_INVALID_CONVERSION hook that blocks conversion to and from the
	__mfp8 type.
	(aarch64_invalid_unary_op): Add function implementing TARGET_UNARY_OP
	hook that blocks operations on __mfp8 other than &.
	(aarch64_invalid_binary_op): Extend TARGET_BINARY_OP hook to disallow
	operations on __mfp8 type.
	(TARGET_INVALID_CONVERSION): Add define.
	(TARGET_INVALID_UNARY_OP): Likewise.
	* config/aarch64/aarch64.h (aarch64_mfp8_type_node): Add node for __mfp8
	type.
	(aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
	* config/aarch64/arm_neon.h (mfloat8_t): Add typedef.
	* config/aarch64/arm_sve.h (mfloat8_t): Likewise.

gcc/testsuite/ChangeLog:

	* g++.target/aarch64/fp8_mangling.C: New tests exercising mangling.
	* g++.target/aarch64/fp8_scalar_typecheck_2.C: New tests in C++.
	* gcc.target/aarch64/fp8_scalar_1.c: New tests in C.
	* gcc.target/aarch64/fp8_scalar_typecheck_1.c: Likewise.
---
Hi, 
Is this ok for master? I do not have commit rights yet, if ok, can someone commit it on my behalf?

Regression tested with aarch64-unknown-linux-gnu.

Compared to V1 of the patch, in version 2:
- mangling for the __mfp8 type was added along with tests
- unneeded comments were removed
- simplified type checks in hooks
- simplified initialization of aarch64_mfp8_type_node
- separated mfloat8_t define from other fp types in arm_sve.h
- C++ tests were moved to g++.target/aarch64
- added more tests around binary operations, function declaration,
  type traits
- added tests exercising loads and stores from floating point registers


Thanks,
Claudio Bantaloukas

 gcc/config/aarch64/aarch64-builtins.cc        |  20 +
 gcc/config/aarch64/aarch64.cc                 |  54 ++-
 gcc/config/aarch64/aarch64.h                  |   5 +
 gcc/config/aarch64/arm_neon.h                 |   2 +
 gcc/config/aarch64/arm_sve.h                  |   2 +
 .../g++.target/aarch64/fp8_mangling.C         |  44 ++
 .../aarch64/fp8_scalar_typecheck_2.C          | 381 ++++++++++++++++++
 .../gcc.target/aarch64/fp8_scalar_1.c         | 134 ++++++
 .../aarch64/fp8_scalar_typecheck_1.c          | 356 ++++++++++++++++
 9 files changed, 996 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_mangling.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
 create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
  

Comments

Kyrylo Tkachov Sept. 19, 2024, 1:18 p.m. UTC | #1
Hi Claudio,

> On 19 Sep 2024, at 15:09, Claudio Bantaloukas <claudio.bantaloukas@arm.com> wrote:
> 
> External email: Use caution opening links or attachments
> 
> 
> The ACLE defines a new scalar type, __mfp8. This is an opaque 8bit types that
> can only be used by fp8 intrinsics. Additionally, the mfloat8_t type is made
> available in arm_neon.h and arm_sve.h as an alias of the same.
> 
> This implementation uses an unsigned INTEGER_TYPE, with precision 8 to
> represent __mfp8. Conversions to int and other types are disabled via the
> TARGET_INVALID_CONVERSION hook.
> Additionally, operations that are typically available to integer types are
> disabled via TARGET_INVALID_UNARY_OP and TARGET_INVALID_BINARY_OP hooks.
> 
> gcc/ChangeLog:
> 
>        * config/aarch64/aarch64-builtins.cc (aarch64_mfp8_type_node): Add node
>        for __mfp8 type.
>        (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
>        (aarch64_init_fp8_types): New function to initialise fp8 types and
>        register with language backends.
>        * config/aarch64/aarch64.cc (aarch64_mangle_type): Add ABI mangling for
>        new type.
>        (aarch64_invalid_conversion): Add function implementing
>        TARGET_INVALID_CONVERSION hook that blocks conversion to and from the
>        __mfp8 type.
>        (aarch64_invalid_unary_op): Add function implementing TARGET_UNARY_OP
>        hook that blocks operations on __mfp8 other than &.
>        (aarch64_invalid_binary_op): Extend TARGET_BINARY_OP hook to disallow
>        operations on __mfp8 type.
>        (TARGET_INVALID_CONVERSION): Add define.
>        (TARGET_INVALID_UNARY_OP): Likewise.
>        * config/aarch64/aarch64.h (aarch64_mfp8_type_node): Add node for __mfp8
>        type.
>        (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
>        * config/aarch64/arm_neon.h (mfloat8_t): Add typedef.
>        * config/aarch64/arm_sve.h (mfloat8_t): Likewise.

Looks like this typedef is a good candidate to go into arm_private_fp8.h so that arm_neon.h, arm_sve.h and arm_sme.h inherit it.

Thanks,
Kyrill


> 
> gcc/testsuite/ChangeLog:
> 
>        * g++.target/aarch64/fp8_mangling.C: New tests exercising mangling.
>        * g++.target/aarch64/fp8_scalar_typecheck_2.C: New tests in C++.
>        * gcc.target/aarch64/fp8_scalar_1.c: New tests in C.
>        * gcc.target/aarch64/fp8_scalar_typecheck_1.c: Likewise.
> ---
> Hi,
> Is this ok for master? I do not have commit rights yet, if ok, can someone commit it on my behalf?
> 
> Regression tested with aarch64-unknown-linux-gnu.
> 
> Compared to V1 of the patch, in version 2:
> - mangling for the __mfp8 type was added along with tests
> - unneeded comments were removed
> - simplified type checks in hooks
> - simplified initialization of aarch64_mfp8_type_node
> - separated mfloat8_t define from other fp types in arm_sve.h
> - C++ tests were moved to g++.target/aarch64
> - added more tests around binary operations, function declaration,
>  type traits
> - added tests exercising loads and stores from floating point registers
> 
> 
> Thanks,
> Claudio Bantaloukas
> 
> gcc/config/aarch64/aarch64-builtins.cc        |  20 +
> gcc/config/aarch64/aarch64.cc                 |  54 ++-
> gcc/config/aarch64/aarch64.h                  |   5 +
> gcc/config/aarch64/arm_neon.h                 |   2 +
> gcc/config/aarch64/arm_sve.h                  |   2 +
> .../g++.target/aarch64/fp8_mangling.C         |  44 ++
> .../aarch64/fp8_scalar_typecheck_2.C          | 381 ++++++++++++++++++
> .../gcc.target/aarch64/fp8_scalar_1.c         | 134 ++++++
> .../aarch64/fp8_scalar_typecheck_1.c          | 356 ++++++++++++++++
> 9 files changed, 996 insertions(+), 2 deletions(-)
> create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_mangling.C
> create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
> create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
> 
> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
> index eb878b933fe..7d17df05a0f 100644
> --- a/gcc/config/aarch64/aarch64-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-builtins.cc
> @@ -961,6 +961,11 @@ static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE;
> static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE;
> static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE;
> 
> +/* The user-visible __mfp8 type, and a pointer to that type.  Used
> +   across the back-end.  */
> +tree aarch64_mfp8_type_node = NULL_TREE;
> +tree aarch64_mfp8_ptr_type_node = NULL_TREE;
> +
> /* The user-visible __fp16 type, and a pointer to that type.  Used
>    across the back-end.  */
> tree aarch64_fp16_type_node = NULL_TREE;
> @@ -1721,6 +1726,19 @@ aarch64_init_builtin_rsqrt (void)
>   }
> }
> 
> +/* Initialize the backend type that supports the user-visible __mfp8
> +   type and its relative pointer type.  */
> +
> +static void
> +aarch64_init_fp8_types (void)
> +{
> +  aarch64_mfp8_type_node = make_unsigned_type (8);
> +  SET_TYPE_MODE (aarch64_mfp8_type_node, QImode);
> +
> +  lang_hooks.types.register_builtin_type (aarch64_mfp8_type_node, "__mfp8");
> +  aarch64_mfp8_ptr_type_node = build_pointer_type (aarch64_mfp8_type_node);
> +}
> +
> /* Initialize the backend types that support the user-visible __fp16
>    type, also initialize a pointer to that type, to be used when
>    forming HFAs.  */
> @@ -2125,6 +2143,8 @@ aarch64_general_init_builtins (void)
> {
>   aarch64_init_fpsr_fpcr_builtins ();
> 
> +  aarch64_init_fp8_types ();
> +
>   aarch64_init_fp16_types ();
> 
>   aarch64_init_bf16_types ();
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 92763d403c7..0ac00027502 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -22467,6 +22467,10 @@ aarch64_mangle_type (const_tree type)
> return "Dh";
>     }
> 
> +  /* Modal 8 bit floating point types.  */
> +  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node)
> +    return "u6__mfp8";
> +
>   /* Mangle AArch64-specific internal types.  TYPE_NAME is non-NULL_TREE for
>      builtin types.  */
>   if (TYPE_NAME (type) != NULL)
> @@ -22481,6 +22485,29 @@ aarch64_mangle_type (const_tree type)
>   return NULL;
> }
> 
> +/* Implement TARGET_INVALID_CONVERSION.  */
> +
> +static const char *
> +aarch64_invalid_conversion (const_tree fromtype, const_tree totype)
> +{
> +  /* Do not allow conversions to/from FP8. But do allow conversions between
> +     volatile and const variants of __mfp8. */
> +  bool fromtype_is_fp8
> +      = (TYPE_MAIN_VARIANT (fromtype) == aarch64_mfp8_type_node);
> +  bool totype_is_fp8 = (TYPE_MAIN_VARIANT (totype) == aarch64_mfp8_type_node);
> +
> +  if (fromtype_is_fp8 && totype_is_fp8)
> +    return NULL;
> +
> +  if (fromtype_is_fp8)
> +    return N_ ("invalid conversion from type %<mfloat8_t%>");
> +  if (totype_is_fp8)
> +    return N_ ("invalid conversion to type %<mfloat8_t%>");
> +
> +  /* Conversion allowed.  */
> +  return NULL;
> +}
> +
> /* Implement TARGET_VERIFY_TYPE_CONTEXT.  */
> 
> static bool
> @@ -29031,8 +29058,20 @@ aarch64_stack_protect_guard (void)
>   return NULL_TREE;
> }
> 
> -/* Return the diagnostic message string if the binary operation OP is
> -   not permitted on TYPE1 and TYPE2, NULL otherwise.  */
> +/* Implement TARGET_INVALID_UNARY_OP.  */
> +
> +static const char *
> +aarch64_invalid_unary_op (int op, const_tree type)
> +{
> +  /* Reject all single-operand operations on __mfp8 except for &.  */
> +  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node && op != ADDR_EXPR)
> +    return N_ ("operation not permitted on type %<mfloat8_t%>");
> +
> +  /* Operation allowed.  */
> +  return NULL;
> +}
> +
> +/* Implement TARGET_INVALID_BINARY_OP.  */
> 
> static const char *
> aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
> @@ -29046,6 +29085,11 @@ aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
>  != aarch64_sve::builtin_type_p (type2)))
>     return N_("cannot combine GNU and SVE vectors in a binary operation");
> 
> +  /* Reject all 2-operand operations on __mfp8.  */
> +  if (TYPE_MAIN_VARIANT (type1) == aarch64_mfp8_type_node
> +      || TYPE_MAIN_VARIANT (type2) == aarch64_mfp8_type_node)
> +    return N_ ("operation not permitted on type %<mfloat8_t%>");
> +
>   /* Operation allowed.  */
>   return NULL;
> }
> @@ -30763,6 +30807,12 @@ aarch64_libgcc_floating_mode_supported_p
> #undef TARGET_MANGLE_TYPE
> #define TARGET_MANGLE_TYPE aarch64_mangle_type
> 
> +#undef TARGET_INVALID_CONVERSION
> +#define TARGET_INVALID_CONVERSION aarch64_invalid_conversion
> +
> +#undef TARGET_INVALID_UNARY_OP
> +#define TARGET_INVALID_UNARY_OP aarch64_invalid_unary_op
> +
> #undef TARGET_INVALID_BINARY_OP
> #define TARGET_INVALID_BINARY_OP aarch64_invalid_binary_op
> 
> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
> index 2dfb999bea5..7ef82ce3587 100644
> --- a/gcc/config/aarch64/aarch64.h
> +++ b/gcc/config/aarch64/aarch64.h
> @@ -1447,6 +1447,11 @@ extern const char *aarch64_rewrite_mcpu (int argc, const char **argv);
> 
> #define ASM_OUTPUT_POOL_EPILOGUE  aarch64_asm_output_pool_epilogue
> 
> +/* This type is the user-visible __mfp8, and a pointer to that type.  We
> +   need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
> +extern GTY(()) tree aarch64_mfp8_type_node;
> +extern GTY(()) tree aarch64_mfp8_ptr_type_node;
> +
> /* This type is the user-visible __fp16, and a pointer to that type.  We
>    need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
> extern GTY(()) tree aarch64_fp16_type_node;
> diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
> index e376685489d..0092314cf75 100644
> --- a/gcc/config/aarch64/arm_neon.h
> +++ b/gcc/config/aarch64/arm_neon.h
> @@ -72,6 +72,8 @@ typedef __Poly16_t poly16_t;
> typedef __Poly64_t poly64_t;
> typedef __Poly128_t poly128_t;
> 
> +typedef __mfp8 mfloat8_t;
> +
> typedef __fp16 float16_t;
> typedef float float32_t;
> typedef double float64_t;
> diff --git a/gcc/config/aarch64/arm_sve.h b/gcc/config/aarch64/arm_sve.h
> index aa0bd9909f9..dbc61650df2 100644
> --- a/gcc/config/aarch64/arm_sve.h
> +++ b/gcc/config/aarch64/arm_sve.h
> @@ -29,6 +29,8 @@
> #include <arm_private_fp8.h>
> #include <arm_bf16.h>
> 
> +typedef __mfp8 mfloat8_t;
> +
> typedef __fp16 float16_t;
> typedef float float32_t;
> typedef double float64_t;
> diff --git a/gcc/testsuite/g++.target/aarch64/fp8_mangling.C b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
> new file mode 100644
> index 00000000000..1dfcaa71f15
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
> @@ -0,0 +1,44 @@
> +/* Test that mfloat8_t mangles differently from uint8_t  */
> +/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
> +
> +int
> +foo (__mfp8)
> +{
> +  return 1;
> +}
> +
> +int
> +foo (unsigned char)
> +{
> +  return 2;
> +}
> +
> +int
> +bar (__mfp8 x)
> +{
> +  return foo (x);
> +}
> +/* { dg-final { scan-assembler-times "\n_Z3fooh:\n" 1 } } */
> +/* { dg-final { scan-assembler-times "\n_Z3foou6__mfp8:\n" 1 } } */
> +
> +constexpr __mfp8 cfp8{};
> +
> +constexpr int
> +fooc (unsigned char)
> +{
> +  return 3;
> +}
> +
> +constexpr int
> +fooc (__mfp8)
> +{
> +  return 4;
> +}
> +
> +constexpr int
> +barc (__mfp8 x)
> +{
> +  return fooc (x);
> +}
> +
> +static_assert (barc (cfp8) == 4, "constexpr selects incorrect overload");
> diff --git a/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
> new file mode 100644
> index 00000000000..61557c95663
> --- /dev/null
> +++ b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
> @@ -0,0 +1,381 @@
> +/* Test that mfloat8_t is only usable with intrinsics, thus not convertible.  */
> +/* { dg-do assemble } */
> +/* { dg-options "-O1 -march=armv9.4-a+fp8 -Wno-narrowing" } */
> +
> +#include <arm_neon.h>
> +#include <stdint.h>
> +#include <type_traits>
> +
> +mfloat8_t glob_fp8;
> +
> +int is_an_int;
> +uint8_t is_a_uint8;
> +int8_t is_an_int8;
> +short is_a_short_int;
> +float is_a_float;
> +double is_a_double;
> +
> +uint8_t *uint8_ptr;
> +
> +mfloat8_t
> +invalid_from_fp8 (uint16_t __a)
> +{
> +  mfloat8_t b = __a; /* { dg-error "invalid conversion to type 'mfloat8_t'" } */
> +  return b;
> +}
> +
> +uint16_t
> +invalid_to_fp8 (mfloat8_t __a)
> +{
> +  uint16_t b = __a; /*{ dg-error "invalid conversion from type 'mfloat8_t'" } */
> +  return b;
> +}
> +
> +mfloat8_t
> +foo1 (void)
> +{
> +  return (mfloat8_t)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +}
> +
> +mfloat8_t
> +foo2 (void)
> +{
> +  return (mfloat8_t)(short)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +}
> +
> +mfloat8_t
> +footest (mfloat8_t scalar0)
> +{
> +
> +  /* Initialisation  */
> +
> +  mfloat8_t scalar1_1;
> +  mfloat8_t scalar1_2 = glob_fp8;
> +  mfloat8_t scalar1_3
> +      = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_4
> +      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_5
> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_6
> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_8
> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_9 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_10
> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_11
> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  int initi_1_1
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  float initi_1_2
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  short initi_1_4
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  double initi_1_5
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  uint8_t initi_1_6
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  int8_t initi_1_7
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  mfloat8_t scalar2_1 = {};
> +  mfloat8_t scalar2_2 = { glob_fp8 };
> +  mfloat8_t scalar2_3
> +      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_4
> +      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_5 = {
> +    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  mfloat8_t scalar2_6 = {
> +    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  mfloat8_t scalar2_8 = {
> +    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  mfloat8_t scalar2_9 = {
> +    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  mfloat8_t scalar2_10 = {
> +    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  mfloat8_t scalar2_11 = {
> +    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +
> +  int initi_2_1 = {
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  float initi_2_2 = {
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  short initi_2_4 = {
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  double initi_2_5 = {
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  uint8_t initi_2_6 = {
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  int8_t initi_2_7 = {
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +
> +  /* Assignments.  */
> +
> +  glob_fp8 = glob_fp8;
> +  glob_fp8 = 0;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  is_an_int
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_float
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_double
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_short_int
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_uint8
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_an_int8
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Casting.  */
> +
> +  (void)glob_fp8;
> +  (mfloat8_t) glob_fp8;
> +
> +  (int)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (float)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (double)
> +      glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (short)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (uint8_t)
> +      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (int8_t)
> +      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  (mfloat8_t)
> +      is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t)
> +      is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t)
> +      is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t) is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t)
> +      is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t)
> +      is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  /* Compound literals.  */
> +
> +  (mfloat8_t){};
> +  (mfloat8_t){ glob_fp8 };
> +  (mfloat8_t){ 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){
> +    0.1 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  }; 
> +  (mfloat8_t){
> +    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  (mfloat8_t){
> +    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  (mfloat8_t){
> +    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  (mfloat8_t){
> +    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  (mfloat8_t){
> +    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +  (mfloat8_t){
> +    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  };
> +
> +  (int){
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  (float){
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  (double){
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  (short){
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  (uint8_t){
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +  (int8_t){
> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  };
> +
> +  /* Arrays and Structs.  */
> +
> +  typedef mfloat8_t array_type[2];
> +  extern mfloat8_t extern_array[];
> +
> +  mfloat8_t array[2];
> +  mfloat8_t zero_length_array[0];
> +  mfloat8_t empty_init_array[] = {};
> +  typedef mfloat8_t some_other_type[is_an_int];
> +
> +  struct struct1
> +  {
> +    mfloat8_t a;
> +  };
> +
> +  union union1
> +  {
> +    mfloat8_t a;
> +  };
> +
> +  /* Addressing and dereferencing.  */
> +
> +  mfloat8_t *fp8_ptr = &scalar0;
> +  scalar0 = *fp8_ptr;
> +
> +  /* Pointer assignment.  */
> +
> +  mfloat8_t *fp8_ptr2 = fp8_ptr;
> +  mfloat8_t *fp8_ptr3 = array;
> +
> +  /* Pointer arithmetic.  */
> +
> +  ++fp8_ptr;
> +  --fp8_ptr;
> +  fp8_ptr++;
> +  fp8_ptr--;
> +  fp8_ptr += 1;
> +  fp8_ptr -= 1;
> +  fp8_ptr - fp8_ptr2;
> +  fp8_ptr = &fp8_ptr3[0];
> +  fp8_ptr = &fp8_ptr3[1];
> +
> +  /* Simple comparison.  */
> +  scalar0
> +      > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8
> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_float
> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 > 0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 == scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0
> +      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_an_int
> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Pointer comparison.  */
> +
> +  fp8_ptr == &scalar0;
> +  fp8_ptr != &scalar0;
> +  fp8_ptr < &scalar0;
> +  fp8_ptr <= &scalar0;
> +  fp8_ptr > &scalar0;
> +  fp8_ptr >= &scalar0;
> +  fp8_ptr == fp8_ptr2;
> +  fp8_ptr != fp8_ptr2;
> +  fp8_ptr < fp8_ptr2;
> +  fp8_ptr <= fp8_ptr2;
> +  fp8_ptr > fp8_ptr2;
> +  fp8_ptr >= fp8_ptr2;
> +
> +  /* Conditional expressions.  */
> +
> +  0 ? scalar0 : scalar0;
> +  0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +    : is_a_float;
> +  0 ? is_a_float
> +    : scalar0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? scalar0 : 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? 0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? 0.1
> +    : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? scalar0  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +    : 0.1;
> +  0 ? fp8_ptr : fp8_ptr2;
> +  0 ? fp8_ptr : uint8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
> +  0 ? uint8_ptr : fp8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
> +
> +  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +      ? scalar0
> +      : scalar0;
> +  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +      ? is_a_float
> +      : scalar0;
> +  scalar0 ? scalar0 : is_a_float;    /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Unary operators.  */
> +
> +  +scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  -scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  ~scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  !scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  *scalar0; /* { dg-error {invalid type argument of unary} } */
> +  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  ++scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  --scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  scalar0++; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  scalar0--; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +
> +  /* Binary arithmetic operations.  */
> +
> +  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 = glob_fp8 + *fp8_ptr;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 = glob_fp8
> +    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 = glob_fp8
> +    + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 = glob_fp8 + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 && glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  glob_fp8 || glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +
> +  return scalar0;
> +}
> +
> +/* Check that function decls for mfloat8_t and unsigned char differ */
> +
> +mfloat8_t extern_fn1(void);
> +unsigned char extern_fn1(void); /* { dg-error {ambiguating new declaration of 'unsigned char extern_fn1\(\)'} } */
> +
> +mfloat8_t extern_fn2(void);
> +uint8_t extern_fn2(void); /* { dg-error {ambiguating new declaration of 'uint8_t extern_fn2\(\)} } */
> +
> +unsigned char extern_fn3(void);
> +mfloat8_t extern_fn3(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn3\(\)} } */
> +
> +uint8_t extern_fn4(void);
> +mfloat8_t extern_fn4(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn4\(\)} } */
> +
> +/* Check that the type conforms to the contract */
> +static_assert(!std::is_integral<__mfp8>(), "not integral");
> +static_assert(!std::is_signed<__mfp8>(), "not signed");
> +static_assert(!std::is_unsigned<__mfp8>(), "not unsigned");
> diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
> new file mode 100644
> index 00000000000..1bc2ac26b2a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
> @@ -0,0 +1,134 @@
> +/* Test the fp8 ACLE intrinsics family.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -march=armv9.4-a+fp8" } */
> +/* { dg-final { check-function-bodies "**" "" "" } } */
> +
> +#include <arm_neon.h>
> +
> +/*
> +**stacktest1:
> +** sub sp, sp, #16
> +** and w0, w0, 255
> +** strb w0, \[sp, 15\]
> +** ldrb w0, \[sp, 15\]
> +** add sp, sp, 16
> +** ret
> +*/
> +mfloat8_t
> +stacktest1 (mfloat8_t __a)
> +{
> +  volatile mfloat8_t b = __a;
> +  return b;
> +}
> +
> +/*
> +**fp8_mov_ww:
> +** dup b1, v2.b\[0\]
> +** ret
> +*/
> +void
> +fp8_mov_ww (void)
> +{
> +  register mfloat8_t x asm ("h2");
> +  register mfloat8_t y asm ("h1");
> +  asm volatile ("" : "=w"(x));
> +  y = x;
> +  asm volatile ("" ::"w"(y));
> +}
> +
> +/*
> +**fp8_mov_rw:
> +** dup v1.8b, w1
> +** ret
> +*/
> +void
> +fp8_mov_rw (void)
> +{
> +  register mfloat8_t x asm ("w1");
> +  register mfloat8_t y asm ("h1");
> +  asm volatile ("" : "=r"(x));
> +  y = x;
> +  asm volatile ("" ::"w"(y));
> +}
> +
> +/*
> +**fp8_mov_wr:
> +** umov w1, v1.b\[0\]
> +** ret
> +*/
> +void
> +fp8_mov_wr (void)
> +{
> +  register mfloat8_t x asm ("h1");
> +  register mfloat8_t y asm ("w1");
> +  asm volatile ("" : "=w"(x));
> +  y = x;
> +  asm volatile ("" ::"r"(y));
> +}
> +
> +/*
> +**fp8_mov_rr:
> +** mov w1, w2
> +** ret
> +*/
> +void
> +fp8_mov_rr (void)
> +{
> +  register mfloat8_t x asm ("w2");
> +  register mfloat8_t y asm ("w1");
> +  asm volatile ("" : "=r"(x));
> +  y = x;
> +  asm volatile ("" ::"r"(y));
> +}
> +
> +/*
> +**fp8_mov_rm:
> +** strb w2, \[x0\]
> +** ret
> +*/
> +void
> +fp8_mov_rm (mfloat8_t *ptr)
> +{
> +  register mfloat8_t x asm ("w2");
> +  asm volatile ("" : "=r"(x));
> +  *ptr = x;
> +}
> +
> +/*
> +**fp8_mov_mr:
> +** ldrb w2, \[x0\]
> +** ret
> +*/
> +void
> +fp8_mov_mr (mfloat8_t *ptr)
> +{
> +  register mfloat8_t y asm ("w2");
> +  y = *ptr;
> +  asm volatile ("" ::"r"(y));
> +}
> +
> +/*
> +**fp8_str_r:
> +** str b2, \[x0\]
> +** ret
> +*/
> +void
> +fp8_str_r (mfloat8_t *ptr)
> +{
> +  register mfloat8_t x asm ("v2");
> +  asm volatile ("" : "=w"(x));
> +  *ptr = x;
> +}
> +
> +/*
> +**fp8_ldr_r:
> +** ldr b2, \[x0\]
> +** ret
> +*/
> +void
> +fp8_ldr_r (mfloat8_t *ptr)
> +{
> +  register mfloat8_t y asm ("v2");
> +  y = *ptr;
> +  asm volatile ("" ::"w"(y));
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
> new file mode 100644
> index 00000000000..9169f40c4b7
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
> @@ -0,0 +1,356 @@
> +/* Test that there is no conversion between ints and mfloat8_t.  */
> +/* { dg-do assemble } */
> +/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
> +
> +#include <arm_neon.h>
> +#include <stdint.h>
> +
> +mfloat8_t glob_fp8;
> +
> +int is_an_int;
> +uint8_t is_a_uint8;
> +int8_t is_an_int8;
> +short is_a_short_int;
> +float is_a_float;
> +double is_a_double;
> +
> +uint8_t *uint8_ptr;
> +
> +mfloat8_t
> +invalid_from_fp8 (uint16_t __a)
> +{
> +  mfloat8_t b = __a; // { dg-error "invalid conversion to type 'mfloat8_t'" }
> +  return b;
> +}
> +
> +uint16_t
> +invalid_to_fp8 (mfloat8_t __a)
> +{
> +  uint16_t b = __a; // { dg-error "invalid conversion from type 'mfloat8_t'" }
> +  return b;
> +}
> +
> +mfloat8_t
> +foo1 (void)
> +{
> +  return (mfloat8_t)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
> +}
> +mfloat8_t
> +foo2 (void)
> +{
> +  return (mfloat8_t)(short)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
> +}
> +
> +mfloat8_t
> +footest (mfloat8_t scalar0)
> +{
> +
> +  /* Initialisation  */
> +
> +  mfloat8_t scalar1_1;
> +  mfloat8_t scalar1_2 = glob_fp8;
> +  mfloat8_t scalar1_3 = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_4
> +      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_5
> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_6
> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_8
> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_9
> +      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_10
> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar1_11
> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  int initi_1_1
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  float initi_1_2
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  short initi_1_4
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  double initi_1_5
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  uint8_t initi_1_6
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  int8_t initi_1_7
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  mfloat8_t scalar2_1 = {};
> +  mfloat8_t scalar2_2 = { glob_fp8 };
> +  mfloat8_t scalar2_3
> +      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_4
> +      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_5
> +      = { is_a_float }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_6
> +      = { is_an_int }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_8 = {
> +    is_a_double
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_9 = {
> +    is_a_short_int
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_10
> +      = { is_a_uint8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  mfloat8_t scalar2_11
> +      = { is_an_int8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  int initi_2_1
> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  float initi_2_2
> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  short initi_2_4
> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  double initi_2_5
> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  uint8_t initi_2_6
> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  int8_t initi_2_7
> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Assignments.  */
> +
> +  glob_fp8 = glob_fp8;
> +  glob_fp8 = 0;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8 = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  glob_fp8
> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  is_an_int
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_float
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_double
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_short_int
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_uint8
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_an_int8
> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Casting.  */
> +
> +  (void)glob_fp8;
> +  (mfloat8_t) glob_fp8;
> +
> +  (int)glob_fp8;     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (float)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (double)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (short)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (uint8_t)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (int8_t)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  (mfloat8_t) is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t) is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t) is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t)
> +      is_a_short_int;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t) is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t) is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  /* Compound literals.  */
> +
> +  (mfloat8_t){};
> +  (mfloat8_t){ glob_fp8 };
> +  (mfloat8_t){ 0 };   /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){ 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){
> +    is_a_float
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){
> +    is_an_int
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){
> +    is_a_double
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){
> +    is_a_short_int
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){
> +    is_a_uint8
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +  (mfloat8_t){
> +    is_an_int8
> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
> +
> +  (int){ glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (float){
> +    glob_fp8
> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (double){
> +    glob_fp8
> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (short){
> +    glob_fp8
> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (uint8_t){
> +    glob_fp8
> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  (int8_t){
> +    glob_fp8
> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Arrays and Structs.  */
> +
> +  typedef mfloat8_t array_type[2];
> +  extern mfloat8_t extern_array[];
> +
> +  mfloat8_t array[2];
> +  mfloat8_t zero_length_array[0];
> +  mfloat8_t empty_init_array[] = {};
> +  typedef mfloat8_t some_other_type[is_an_int];
> +
> +  struct struct1
> +  {
> +    mfloat8_t a;
> +  };
> +
> +  union union1
> +  {
> +    mfloat8_t a;
> +  };
> +
> +  /* Addressing and dereferencing.  */
> +
> +  mfloat8_t *fp8_ptr = &scalar0;
> +  scalar0 = *fp8_ptr;
> +
> +  /* Pointer assignment.  */
> +
> +  mfloat8_t *fp8_ptr2 = fp8_ptr;
> +  mfloat8_t *fp8_ptr3 = array;
> +
> +  /* Pointer arithmetic.  */
> +
> +  ++fp8_ptr;
> +  --fp8_ptr;
> +  fp8_ptr++;
> +  fp8_ptr--;
> +  fp8_ptr += 1;
> +  fp8_ptr -= 1;
> +  fp8_ptr - fp8_ptr2;
> +  fp8_ptr = &fp8_ptr3[0];
> +  fp8_ptr = &fp8_ptr3[1];
> +
> +  /* Simple comparison.  */
> +  scalar0 > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8
> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_a_float
> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 > 0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 == scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0
> +      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  is_an_int
> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Pointer comparison.  */
> +
> +  fp8_ptr == &scalar0;
> +  fp8_ptr != &scalar0;
> +  fp8_ptr < &scalar0;
> +  fp8_ptr <= &scalar0;
> +  fp8_ptr > &scalar0;
> +  fp8_ptr >= &scalar0;
> +  fp8_ptr == fp8_ptr2;
> +  fp8_ptr != fp8_ptr2;
> +  fp8_ptr < fp8_ptr2;
> +  fp8_ptr <= fp8_ptr2;
> +  fp8_ptr > fp8_ptr2;
> +  fp8_ptr >= fp8_ptr2;
> +
> +  /* Conditional expressions.  */
> +
> +  0 ? scalar0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? scalar0
> +    : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? is_a_float
> +    : scalar0;     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? scalar0 : 0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? 0 : scalar0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? 0.1 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? scalar0 : 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  0 ? fp8_ptr : fp8_ptr2;
> +  0 ? fp8_ptr : uint8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
> +  0 ? uint8_ptr : fp8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
> +
> +  scalar0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 ? is_a_float /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 ? scalar0 : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  /* Unary operators.  */
> +
> +  +scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  -scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  ~scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  !scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  *scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  ++scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  --scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  scalar0++;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +  scalar0--;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
> +
> +  /* Binary arithmetic operations.  */
> +
> +  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 = glob_fp8 + *fp8_ptr; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0 = glob_fp8
> +    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0
> +      = glob_fp8 + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  scalar0
> +      = glob_fp8
> + + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 && glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +  glob_fp8 || glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
> +
> +  return scalar0;
> +}
> +
> +/* Check that function decls for mfloat8_t and unsigned char differ */
> +
> +mfloat8_t extern_fn1(void);
> +unsigned char extern_fn1(void); /* { dg-error {conflicting types for 'extern_fn1'; have 'unsigned char\(void\)'} } */
> +
> +mfloat8_t extern_fn2(void);
> +uint8_t extern_fn2(void); /* { dg-error {conflicting types for 'extern_fn2'; have 'uint8_t\(void\)'} } */
> +
> +unsigned char extern_fn3(void);
> +mfloat8_t extern_fn3(void); /* { dg-error {conflicting types for 'extern_fn3'; have 'mfloat8_t\(void\)'} } */
> +
> +uint8_t extern_fn4(void);
> +mfloat8_t extern_fn4(void); /* { dg-error {conflicting types for 'extern_fn4'; have 'mfloat8_t\(void\)'} } */
> +
> +void extern_fn5(mfloat8_t);
> +void extern_fn5(unsigned char); /* { dg-error {conflicting types for 'extern_fn5'; have 'void\(unsigned char\)'} } */
> +
> +void extern_fn6(mfloat8_t);
> +void extern_fn6(uint8_t); /* { dg-error {conflicting types for 'extern_fn6'; have 'void\(uint8_t\)'} } */
  
Claudio Bantaloukas Sept. 19, 2024, 1:39 p.m. UTC | #2
On 9/19/2024 2:18 PM, Kyrylo Tkachov wrote:
> Hi Claudio,
> 
>> On 19 Sep 2024, at 15:09, Claudio Bantaloukas <claudio.bantaloukas@arm.com> wrote:
>>
>> External email: Use caution opening links or attachments
>>
>>
>> The ACLE defines a new scalar type, __mfp8. This is an opaque 8bit types that
>> can only be used by fp8 intrinsics. Additionally, the mfloat8_t type is made
>> available in arm_neon.h and arm_sve.h as an alias of the same.
>>
>> This implementation uses an unsigned INTEGER_TYPE, with precision 8 to
>> represent __mfp8. Conversions to int and other types are disabled via the
>> TARGET_INVALID_CONVERSION hook.
>> Additionally, operations that are typically available to integer types are
>> disabled via TARGET_INVALID_UNARY_OP and TARGET_INVALID_BINARY_OP hooks.
>>
>> gcc/ChangeLog:
>>
>>         * config/aarch64/aarch64-builtins.cc (aarch64_mfp8_type_node): Add node
>>         for __mfp8 type.
>>         (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
>>         (aarch64_init_fp8_types): New function to initialise fp8 types and
>>         register with language backends.
>>         * config/aarch64/aarch64.cc (aarch64_mangle_type): Add ABI mangling for
>>         new type.
>>         (aarch64_invalid_conversion): Add function implementing
>>         TARGET_INVALID_CONVERSION hook that blocks conversion to and from the
>>         __mfp8 type.
>>         (aarch64_invalid_unary_op): Add function implementing TARGET_UNARY_OP
>>         hook that blocks operations on __mfp8 other than &.
>>         (aarch64_invalid_binary_op): Extend TARGET_BINARY_OP hook to disallow
>>         operations on __mfp8 type.
>>         (TARGET_INVALID_CONVERSION): Add define.
>>         (TARGET_INVALID_UNARY_OP): Likewise.
>>         * config/aarch64/aarch64.h (aarch64_mfp8_type_node): Add node for __mfp8
>>         type.
>>         (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
>>         * config/aarch64/arm_neon.h (mfloat8_t): Add typedef.
>>         * config/aarch64/arm_sve.h (mfloat8_t): Likewise.
> 
> Looks like this typedef is a good candidate to go into arm_private_fp8.h so that arm_neon.h, arm_sve.h and arm_sme.h inherit it.

Hi Kyrill,
thanks for the quick review. The thought of using arm_private_fp8.h 
crossed my mind but I thought that ultimately it made more sense to 
follow existing practice and place the typedef near existing ones for 
bfloat types.
If you feel strongly about this, I'll make the suggested change, but I'd 
rather keep it as is. As you can see, the rest of the patch borrows 
heavily in style from the bfloat implementation and my hope is that the 
closeness in code will aid in maintainability.

Let me know :)

Cheers,
Claudio

> 
> Thanks,
> Kyrill
> 
> 
>>
>> gcc/testsuite/ChangeLog:
>>
>>         * g++.target/aarch64/fp8_mangling.C: New tests exercising mangling.
>>         * g++.target/aarch64/fp8_scalar_typecheck_2.C: New tests in C++.
>>         * gcc.target/aarch64/fp8_scalar_1.c: New tests in C.
>>         * gcc.target/aarch64/fp8_scalar_typecheck_1.c: Likewise.
>> ---
>> Hi,
>> Is this ok for master? I do not have commit rights yet, if ok, can someone commit it on my behalf?
>>
>> Regression tested with aarch64-unknown-linux-gnu.
>>
>> Compared to V1 of the patch, in version 2:
>> - mangling for the __mfp8 type was added along with tests
>> - unneeded comments were removed
>> - simplified type checks in hooks
>> - simplified initialization of aarch64_mfp8_type_node
>> - separated mfloat8_t define from other fp types in arm_sve.h
>> - C++ tests were moved to g++.target/aarch64
>> - added more tests around binary operations, function declaration,
>>   type traits
>> - added tests exercising loads and stores from floating point registers
>>
>>
>> Thanks,
>> Claudio Bantaloukas
>>
>> gcc/config/aarch64/aarch64-builtins.cc        |  20 +
>> gcc/config/aarch64/aarch64.cc                 |  54 ++-
>> gcc/config/aarch64/aarch64.h                  |   5 +
>> gcc/config/aarch64/arm_neon.h                 |   2 +
>> gcc/config/aarch64/arm_sve.h                  |   2 +
>> .../g++.target/aarch64/fp8_mangling.C         |  44 ++
>> .../aarch64/fp8_scalar_typecheck_2.C          | 381 ++++++++++++++++++
>> .../gcc.target/aarch64/fp8_scalar_1.c         | 134 ++++++
>> .../aarch64/fp8_scalar_typecheck_1.c          | 356 ++++++++++++++++
>> 9 files changed, 996 insertions(+), 2 deletions(-)
>> create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_mangling.C
>> create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
>> create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
>> create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
>>
>> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
>> index eb878b933fe..7d17df05a0f 100644
>> --- a/gcc/config/aarch64/aarch64-builtins.cc
>> +++ b/gcc/config/aarch64/aarch64-builtins.cc
>> @@ -961,6 +961,11 @@ static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE;
>> static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE;
>> static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE;
>>
>> +/* The user-visible __mfp8 type, and a pointer to that type.  Used
>> +   across the back-end.  */
>> +tree aarch64_mfp8_type_node = NULL_TREE;
>> +tree aarch64_mfp8_ptr_type_node = NULL_TREE;
>> +
>> /* The user-visible __fp16 type, and a pointer to that type.  Used
>>     across the back-end.  */
>> tree aarch64_fp16_type_node = NULL_TREE;
>> @@ -1721,6 +1726,19 @@ aarch64_init_builtin_rsqrt (void)
>>    }
>> }
>>
>> +/* Initialize the backend type that supports the user-visible __mfp8
>> +   type and its relative pointer type.  */
>> +
>> +static void
>> +aarch64_init_fp8_types (void)
>> +{
>> +  aarch64_mfp8_type_node = make_unsigned_type (8);
>> +  SET_TYPE_MODE (aarch64_mfp8_type_node, QImode);
>> +
>> +  lang_hooks.types.register_builtin_type (aarch64_mfp8_type_node, "__mfp8");
>> +  aarch64_mfp8_ptr_type_node = build_pointer_type (aarch64_mfp8_type_node);
>> +}
>> +
>> /* Initialize the backend types that support the user-visible __fp16
>>     type, also initialize a pointer to that type, to be used when
>>     forming HFAs.  */
>> @@ -2125,6 +2143,8 @@ aarch64_general_init_builtins (void)
>> {
>>    aarch64_init_fpsr_fpcr_builtins ();
>>
>> +  aarch64_init_fp8_types ();
>> +
>>    aarch64_init_fp16_types ();
>>
>>    aarch64_init_bf16_types ();
>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
>> index 92763d403c7..0ac00027502 100644
>> --- a/gcc/config/aarch64/aarch64.cc
>> +++ b/gcc/config/aarch64/aarch64.cc
>> @@ -22467,6 +22467,10 @@ aarch64_mangle_type (const_tree type)
>> return "Dh";
>>      }
>>
>> +  /* Modal 8 bit floating point types.  */
>> +  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node)
>> +    return "u6__mfp8";
>> +
>>    /* Mangle AArch64-specific internal types.  TYPE_NAME is non-NULL_TREE for
>>       builtin types.  */
>>    if (TYPE_NAME (type) != NULL)
>> @@ -22481,6 +22485,29 @@ aarch64_mangle_type (const_tree type)
>>    return NULL;
>> }
>>
>> +/* Implement TARGET_INVALID_CONVERSION.  */
>> +
>> +static const char *
>> +aarch64_invalid_conversion (const_tree fromtype, const_tree totype)
>> +{
>> +  /* Do not allow conversions to/from FP8. But do allow conversions between
>> +     volatile and const variants of __mfp8. */
>> +  bool fromtype_is_fp8
>> +      = (TYPE_MAIN_VARIANT (fromtype) == aarch64_mfp8_type_node);
>> +  bool totype_is_fp8 = (TYPE_MAIN_VARIANT (totype) == aarch64_mfp8_type_node);
>> +
>> +  if (fromtype_is_fp8 && totype_is_fp8)
>> +    return NULL;
>> +
>> +  if (fromtype_is_fp8)
>> +    return N_ ("invalid conversion from type %<mfloat8_t%>");
>> +  if (totype_is_fp8)
>> +    return N_ ("invalid conversion to type %<mfloat8_t%>");
>> +
>> +  /* Conversion allowed.  */
>> +  return NULL;
>> +}
>> +
>> /* Implement TARGET_VERIFY_TYPE_CONTEXT.  */
>>
>> static bool
>> @@ -29031,8 +29058,20 @@ aarch64_stack_protect_guard (void)
>>    return NULL_TREE;
>> }
>>
>> -/* Return the diagnostic message string if the binary operation OP is
>> -   not permitted on TYPE1 and TYPE2, NULL otherwise.  */
>> +/* Implement TARGET_INVALID_UNARY_OP.  */
>> +
>> +static const char *
>> +aarch64_invalid_unary_op (int op, const_tree type)
>> +{
>> +  /* Reject all single-operand operations on __mfp8 except for &.  */
>> +  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node && op != ADDR_EXPR)
>> +    return N_ ("operation not permitted on type %<mfloat8_t%>");
>> +
>> +  /* Operation allowed.  */
>> +  return NULL;
>> +}
>> +
>> +/* Implement TARGET_INVALID_BINARY_OP.  */
>>
>> static const char *
>> aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
>> @@ -29046,6 +29085,11 @@ aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
>>   != aarch64_sve::builtin_type_p (type2)))
>>      return N_("cannot combine GNU and SVE vectors in a binary operation");
>>
>> +  /* Reject all 2-operand operations on __mfp8.  */
>> +  if (TYPE_MAIN_VARIANT (type1) == aarch64_mfp8_type_node
>> +      || TYPE_MAIN_VARIANT (type2) == aarch64_mfp8_type_node)
>> +    return N_ ("operation not permitted on type %<mfloat8_t%>");
>> +
>>    /* Operation allowed.  */
>>    return NULL;
>> }
>> @@ -30763,6 +30807,12 @@ aarch64_libgcc_floating_mode_supported_p
>> #undef TARGET_MANGLE_TYPE
>> #define TARGET_MANGLE_TYPE aarch64_mangle_type
>>
>> +#undef TARGET_INVALID_CONVERSION
>> +#define TARGET_INVALID_CONVERSION aarch64_invalid_conversion
>> +
>> +#undef TARGET_INVALID_UNARY_OP
>> +#define TARGET_INVALID_UNARY_OP aarch64_invalid_unary_op
>> +
>> #undef TARGET_INVALID_BINARY_OP
>> #define TARGET_INVALID_BINARY_OP aarch64_invalid_binary_op
>>
>> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
>> index 2dfb999bea5..7ef82ce3587 100644
>> --- a/gcc/config/aarch64/aarch64.h
>> +++ b/gcc/config/aarch64/aarch64.h
>> @@ -1447,6 +1447,11 @@ extern const char *aarch64_rewrite_mcpu (int argc, const char **argv);
>>
>> #define ASM_OUTPUT_POOL_EPILOGUE  aarch64_asm_output_pool_epilogue
>>
>> +/* This type is the user-visible __mfp8, and a pointer to that type.  We
>> +   need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
>> +extern GTY(()) tree aarch64_mfp8_type_node;
>> +extern GTY(()) tree aarch64_mfp8_ptr_type_node;
>> +
>> /* This type is the user-visible __fp16, and a pointer to that type.  We
>>     need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
>> extern GTY(()) tree aarch64_fp16_type_node;
>> diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
>> index e376685489d..0092314cf75 100644
>> --- a/gcc/config/aarch64/arm_neon.h
>> +++ b/gcc/config/aarch64/arm_neon.h
>> @@ -72,6 +72,8 @@ typedef __Poly16_t poly16_t;
>> typedef __Poly64_t poly64_t;
>> typedef __Poly128_t poly128_t;
>>
>> +typedef __mfp8 mfloat8_t;
>> +
>> typedef __fp16 float16_t;
>> typedef float float32_t;
>> typedef double float64_t;
>> diff --git a/gcc/config/aarch64/arm_sve.h b/gcc/config/aarch64/arm_sve.h
>> index aa0bd9909f9..dbc61650df2 100644
>> --- a/gcc/config/aarch64/arm_sve.h
>> +++ b/gcc/config/aarch64/arm_sve.h
>> @@ -29,6 +29,8 @@
>> #include <arm_private_fp8.h>
>> #include <arm_bf16.h>
>>
>> +typedef __mfp8 mfloat8_t;
>> +
>> typedef __fp16 float16_t;
>> typedef float float32_t;
>> typedef double float64_t;
>> diff --git a/gcc/testsuite/g++.target/aarch64/fp8_mangling.C b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
>> new file mode 100644
>> index 00000000000..1dfcaa71f15
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
>> @@ -0,0 +1,44 @@
>> +/* Test that mfloat8_t mangles differently from uint8_t  */
>> +/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
>> +
>> +int
>> +foo (__mfp8)
>> +{
>> +  return 1;
>> +}
>> +
>> +int
>> +foo (unsigned char)
>> +{
>> +  return 2;
>> +}
>> +
>> +int
>> +bar (__mfp8 x)
>> +{
>> +  return foo (x);
>> +}
>> +/* { dg-final { scan-assembler-times "\n_Z3fooh:\n" 1 } } */
>> +/* { dg-final { scan-assembler-times "\n_Z3foou6__mfp8:\n" 1 } } */
>> +
>> +constexpr __mfp8 cfp8{};
>> +
>> +constexpr int
>> +fooc (unsigned char)
>> +{
>> +  return 3;
>> +}
>> +
>> +constexpr int
>> +fooc (__mfp8)
>> +{
>> +  return 4;
>> +}
>> +
>> +constexpr int
>> +barc (__mfp8 x)
>> +{
>> +  return fooc (x);
>> +}
>> +
>> +static_assert (barc (cfp8) == 4, "constexpr selects incorrect overload");
>> diff --git a/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
>> new file mode 100644
>> index 00000000000..61557c95663
>> --- /dev/null
>> +++ b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
>> @@ -0,0 +1,381 @@
>> +/* Test that mfloat8_t is only usable with intrinsics, thus not convertible.  */
>> +/* { dg-do assemble } */
>> +/* { dg-options "-O1 -march=armv9.4-a+fp8 -Wno-narrowing" } */
>> +
>> +#include <arm_neon.h>
>> +#include <stdint.h>
>> +#include <type_traits>
>> +
>> +mfloat8_t glob_fp8;
>> +
>> +int is_an_int;
>> +uint8_t is_a_uint8;
>> +int8_t is_an_int8;
>> +short is_a_short_int;
>> +float is_a_float;
>> +double is_a_double;
>> +
>> +uint8_t *uint8_ptr;
>> +
>> +mfloat8_t
>> +invalid_from_fp8 (uint16_t __a)
>> +{
>> +  mfloat8_t b = __a; /* { dg-error "invalid conversion to type 'mfloat8_t'" } */
>> +  return b;
>> +}
>> +
>> +uint16_t
>> +invalid_to_fp8 (mfloat8_t __a)
>> +{
>> +  uint16_t b = __a; /*{ dg-error "invalid conversion from type 'mfloat8_t'" } */
>> +  return b;
>> +}
>> +
>> +mfloat8_t
>> +foo1 (void)
>> +{
>> +  return (mfloat8_t)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +}
>> +
>> +mfloat8_t
>> +foo2 (void)
>> +{
>> +  return (mfloat8_t)(short)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +}
>> +
>> +mfloat8_t
>> +footest (mfloat8_t scalar0)
>> +{
>> +
>> +  /* Initialisation  */
>> +
>> +  mfloat8_t scalar1_1;
>> +  mfloat8_t scalar1_2 = glob_fp8;
>> +  mfloat8_t scalar1_3
>> +      = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_4
>> +      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_5
>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_6
>> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_8
>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_9 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_10
>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_11
>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  int initi_1_1
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  float initi_1_2
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  short initi_1_4
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  double initi_1_5
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  uint8_t initi_1_6
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  int8_t initi_1_7
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  mfloat8_t scalar2_1 = {};
>> +  mfloat8_t scalar2_2 = { glob_fp8 };
>> +  mfloat8_t scalar2_3
>> +      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_4
>> +      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_5 = {
>> +    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  mfloat8_t scalar2_6 = {
>> +    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  mfloat8_t scalar2_8 = {
>> +    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  mfloat8_t scalar2_9 = {
>> +    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  mfloat8_t scalar2_10 = {
>> +    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  mfloat8_t scalar2_11 = {
>> +    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +
>> +  int initi_2_1 = {
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  float initi_2_2 = {
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  short initi_2_4 = {
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  double initi_2_5 = {
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  uint8_t initi_2_6 = {
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  int8_t initi_2_7 = {
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +
>> +  /* Assignments.  */
>> +
>> +  glob_fp8 = glob_fp8;
>> +  glob_fp8 = 0;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  is_an_int
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_float
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_double
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_short_int
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_uint8
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_an_int8
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Casting.  */
>> +
>> +  (void)glob_fp8;
>> +  (mfloat8_t) glob_fp8;
>> +
>> +  (int)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (float)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (double)
>> +      glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (short)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (uint8_t)
>> +      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (int8_t)
>> +      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  (mfloat8_t)
>> +      is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t)
>> +      is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t)
>> +      is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t) is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t)
>> +      is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t)
>> +      is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  /* Compound literals.  */
>> +
>> +  (mfloat8_t){};
>> +  (mfloat8_t){ glob_fp8 };
>> +  (mfloat8_t){ 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){
>> +    0.1 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  (mfloat8_t){
>> +    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  (mfloat8_t){
>> +    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  (mfloat8_t){
>> +    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  (mfloat8_t){
>> +    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  (mfloat8_t){
>> +    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +  (mfloat8_t){
>> +    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  };
>> +
>> +  (int){
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  (float){
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  (double){
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  (short){
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  (uint8_t){
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +  (int8_t){
>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  };
>> +
>> +  /* Arrays and Structs.  */
>> +
>> +  typedef mfloat8_t array_type[2];
>> +  extern mfloat8_t extern_array[];
>> +
>> +  mfloat8_t array[2];
>> +  mfloat8_t zero_length_array[0];
>> +  mfloat8_t empty_init_array[] = {};
>> +  typedef mfloat8_t some_other_type[is_an_int];
>> +
>> +  struct struct1
>> +  {
>> +    mfloat8_t a;
>> +  };
>> +
>> +  union union1
>> +  {
>> +    mfloat8_t a;
>> +  };
>> +
>> +  /* Addressing and dereferencing.  */
>> +
>> +  mfloat8_t *fp8_ptr = &scalar0;
>> +  scalar0 = *fp8_ptr;
>> +
>> +  /* Pointer assignment.  */
>> +
>> +  mfloat8_t *fp8_ptr2 = fp8_ptr;
>> +  mfloat8_t *fp8_ptr3 = array;
>> +
>> +  /* Pointer arithmetic.  */
>> +
>> +  ++fp8_ptr;
>> +  --fp8_ptr;
>> +  fp8_ptr++;
>> +  fp8_ptr--;
>> +  fp8_ptr += 1;
>> +  fp8_ptr -= 1;
>> +  fp8_ptr - fp8_ptr2;
>> +  fp8_ptr = &fp8_ptr3[0];
>> +  fp8_ptr = &fp8_ptr3[1];
>> +
>> +  /* Simple comparison.  */
>> +  scalar0
>> +      > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_float
>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 > 0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 == scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0
>> +      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_an_int
>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Pointer comparison.  */
>> +
>> +  fp8_ptr == &scalar0;
>> +  fp8_ptr != &scalar0;
>> +  fp8_ptr < &scalar0;
>> +  fp8_ptr <= &scalar0;
>> +  fp8_ptr > &scalar0;
>> +  fp8_ptr >= &scalar0;
>> +  fp8_ptr == fp8_ptr2;
>> +  fp8_ptr != fp8_ptr2;
>> +  fp8_ptr < fp8_ptr2;
>> +  fp8_ptr <= fp8_ptr2;
>> +  fp8_ptr > fp8_ptr2;
>> +  fp8_ptr >= fp8_ptr2;
>> +
>> +  /* Conditional expressions.  */
>> +
>> +  0 ? scalar0 : scalar0;
>> +  0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +    : is_a_float;
>> +  0 ? is_a_float
>> +    : scalar0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? scalar0 : 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? 0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? 0.1
>> +    : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? scalar0  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +    : 0.1;
>> +  0 ? fp8_ptr : fp8_ptr2;
>> +  0 ? fp8_ptr : uint8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
>> +  0 ? uint8_ptr : fp8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
>> +
>> +  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +      ? scalar0
>> +      : scalar0;
>> +  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +      ? is_a_float
>> +      : scalar0;
>> +  scalar0 ? scalar0 : is_a_float;    /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Unary operators.  */
>> +
>> +  +scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  -scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  ~scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  !scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  *scalar0; /* { dg-error {invalid type argument of unary} } */
>> +  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  ++scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  --scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  scalar0++; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  scalar0--; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +
>> +  /* Binary arithmetic operations.  */
>> +
>> +  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 = glob_fp8 + *fp8_ptr;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 = glob_fp8
>> +    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 = glob_fp8
>> +    + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 = glob_fp8 + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 && glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  glob_fp8 || glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +
>> +  return scalar0;
>> +}
>> +
>> +/* Check that function decls for mfloat8_t and unsigned char differ */
>> +
>> +mfloat8_t extern_fn1(void);
>> +unsigned char extern_fn1(void); /* { dg-error {ambiguating new declaration of 'unsigned char extern_fn1\(\)'} } */
>> +
>> +mfloat8_t extern_fn2(void);
>> +uint8_t extern_fn2(void); /* { dg-error {ambiguating new declaration of 'uint8_t extern_fn2\(\)} } */
>> +
>> +unsigned char extern_fn3(void);
>> +mfloat8_t extern_fn3(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn3\(\)} } */
>> +
>> +uint8_t extern_fn4(void);
>> +mfloat8_t extern_fn4(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn4\(\)} } */
>> +
>> +/* Check that the type conforms to the contract */
>> +static_assert(!std::is_integral<__mfp8>(), "not integral");
>> +static_assert(!std::is_signed<__mfp8>(), "not signed");
>> +static_assert(!std::is_unsigned<__mfp8>(), "not unsigned");
>> diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
>> new file mode 100644
>> index 00000000000..1bc2ac26b2a
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
>> @@ -0,0 +1,134 @@
>> +/* Test the fp8 ACLE intrinsics family.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -march=armv9.4-a+fp8" } */
>> +/* { dg-final { check-function-bodies "**" "" "" } } */
>> +
>> +#include <arm_neon.h>
>> +
>> +/*
>> +**stacktest1:
>> +** sub sp, sp, #16
>> +** and w0, w0, 255
>> +** strb w0, \[sp, 15\]
>> +** ldrb w0, \[sp, 15\]
>> +** add sp, sp, 16
>> +** ret
>> +*/
>> +mfloat8_t
>> +stacktest1 (mfloat8_t __a)
>> +{
>> +  volatile mfloat8_t b = __a;
>> +  return b;
>> +}
>> +
>> +/*
>> +**fp8_mov_ww:
>> +** dup b1, v2.b\[0\]
>> +** ret
>> +*/
>> +void
>> +fp8_mov_ww (void)
>> +{
>> +  register mfloat8_t x asm ("h2");
>> +  register mfloat8_t y asm ("h1");
>> +  asm volatile ("" : "=w"(x));
>> +  y = x;
>> +  asm volatile ("" ::"w"(y));
>> +}
>> +
>> +/*
>> +**fp8_mov_rw:
>> +** dup v1.8b, w1
>> +** ret
>> +*/
>> +void
>> +fp8_mov_rw (void)
>> +{
>> +  register mfloat8_t x asm ("w1");
>> +  register mfloat8_t y asm ("h1");
>> +  asm volatile ("" : "=r"(x));
>> +  y = x;
>> +  asm volatile ("" ::"w"(y));
>> +}
>> +
>> +/*
>> +**fp8_mov_wr:
>> +** umov w1, v1.b\[0\]
>> +** ret
>> +*/
>> +void
>> +fp8_mov_wr (void)
>> +{
>> +  register mfloat8_t x asm ("h1");
>> +  register mfloat8_t y asm ("w1");
>> +  asm volatile ("" : "=w"(x));
>> +  y = x;
>> +  asm volatile ("" ::"r"(y));
>> +}
>> +
>> +/*
>> +**fp8_mov_rr:
>> +** mov w1, w2
>> +** ret
>> +*/
>> +void
>> +fp8_mov_rr (void)
>> +{
>> +  register mfloat8_t x asm ("w2");
>> +  register mfloat8_t y asm ("w1");
>> +  asm volatile ("" : "=r"(x));
>> +  y = x;
>> +  asm volatile ("" ::"r"(y));
>> +}
>> +
>> +/*
>> +**fp8_mov_rm:
>> +** strb w2, \[x0\]
>> +** ret
>> +*/
>> +void
>> +fp8_mov_rm (mfloat8_t *ptr)
>> +{
>> +  register mfloat8_t x asm ("w2");
>> +  asm volatile ("" : "=r"(x));
>> +  *ptr = x;
>> +}
>> +
>> +/*
>> +**fp8_mov_mr:
>> +** ldrb w2, \[x0\]
>> +** ret
>> +*/
>> +void
>> +fp8_mov_mr (mfloat8_t *ptr)
>> +{
>> +  register mfloat8_t y asm ("w2");
>> +  y = *ptr;
>> +  asm volatile ("" ::"r"(y));
>> +}
>> +
>> +/*
>> +**fp8_str_r:
>> +** str b2, \[x0\]
>> +** ret
>> +*/
>> +void
>> +fp8_str_r (mfloat8_t *ptr)
>> +{
>> +  register mfloat8_t x asm ("v2");
>> +  asm volatile ("" : "=w"(x));
>> +  *ptr = x;
>> +}
>> +
>> +/*
>> +**fp8_ldr_r:
>> +** ldr b2, \[x0\]
>> +** ret
>> +*/
>> +void
>> +fp8_ldr_r (mfloat8_t *ptr)
>> +{
>> +  register mfloat8_t y asm ("v2");
>> +  y = *ptr;
>> +  asm volatile ("" ::"w"(y));
>> +}
>> diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
>> new file mode 100644
>> index 00000000000..9169f40c4b7
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
>> @@ -0,0 +1,356 @@
>> +/* Test that there is no conversion between ints and mfloat8_t.  */
>> +/* { dg-do assemble } */
>> +/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
>> +
>> +#include <arm_neon.h>
>> +#include <stdint.h>
>> +
>> +mfloat8_t glob_fp8;
>> +
>> +int is_an_int;
>> +uint8_t is_a_uint8;
>> +int8_t is_an_int8;
>> +short is_a_short_int;
>> +float is_a_float;
>> +double is_a_double;
>> +
>> +uint8_t *uint8_ptr;
>> +
>> +mfloat8_t
>> +invalid_from_fp8 (uint16_t __a)
>> +{
>> +  mfloat8_t b = __a; // { dg-error "invalid conversion to type 'mfloat8_t'" }
>> +  return b;
>> +}
>> +
>> +uint16_t
>> +invalid_to_fp8 (mfloat8_t __a)
>> +{
>> +  uint16_t b = __a; // { dg-error "invalid conversion from type 'mfloat8_t'" }
>> +  return b;
>> +}
>> +
>> +mfloat8_t
>> +foo1 (void)
>> +{
>> +  return (mfloat8_t)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
>> +}
>> +mfloat8_t
>> +foo2 (void)
>> +{
>> +  return (mfloat8_t)(short)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
>> +}
>> +
>> +mfloat8_t
>> +footest (mfloat8_t scalar0)
>> +{
>> +
>> +  /* Initialisation  */
>> +
>> +  mfloat8_t scalar1_1;
>> +  mfloat8_t scalar1_2 = glob_fp8;
>> +  mfloat8_t scalar1_3 = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_4
>> +      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_5
>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_6
>> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_8
>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_9
>> +      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_10
>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar1_11
>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  int initi_1_1
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  float initi_1_2
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  short initi_1_4
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  double initi_1_5
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  uint8_t initi_1_6
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  int8_t initi_1_7
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  mfloat8_t scalar2_1 = {};
>> +  mfloat8_t scalar2_2 = { glob_fp8 };
>> +  mfloat8_t scalar2_3
>> +      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_4
>> +      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_5
>> +      = { is_a_float }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_6
>> +      = { is_an_int }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_8 = {
>> +    is_a_double
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_9 = {
>> +    is_a_short_int
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_10
>> +      = { is_a_uint8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  mfloat8_t scalar2_11
>> +      = { is_an_int8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  int initi_2_1
>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  float initi_2_2
>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  short initi_2_4
>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  double initi_2_5
>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  uint8_t initi_2_6
>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  int8_t initi_2_7
>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Assignments.  */
>> +
>> +  glob_fp8 = glob_fp8;
>> +  glob_fp8 = 0;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8 = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  is_an_int
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_float
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_double
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_short_int
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_uint8
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_an_int8
>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Casting.  */
>> +
>> +  (void)glob_fp8;
>> +  (mfloat8_t) glob_fp8;
>> +
>> +  (int)glob_fp8;     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (float)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (double)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (short)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (uint8_t)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (int8_t)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  (mfloat8_t) is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t) is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t) is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t)
>> +      is_a_short_int;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t) is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t) is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  /* Compound literals.  */
>> +
>> +  (mfloat8_t){};
>> +  (mfloat8_t){ glob_fp8 };
>> +  (mfloat8_t){ 0 };   /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){ 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){
>> +    is_a_float
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){
>> +    is_an_int
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){
>> +    is_a_double
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){
>> +    is_a_short_int
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){
>> +    is_a_uint8
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +  (mfloat8_t){
>> +    is_an_int8
>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>> +
>> +  (int){ glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (float){
>> +    glob_fp8
>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (double){
>> +    glob_fp8
>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (short){
>> +    glob_fp8
>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (uint8_t){
>> +    glob_fp8
>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  (int8_t){
>> +    glob_fp8
>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Arrays and Structs.  */
>> +
>> +  typedef mfloat8_t array_type[2];
>> +  extern mfloat8_t extern_array[];
>> +
>> +  mfloat8_t array[2];
>> +  mfloat8_t zero_length_array[0];
>> +  mfloat8_t empty_init_array[] = {};
>> +  typedef mfloat8_t some_other_type[is_an_int];
>> +
>> +  struct struct1
>> +  {
>> +    mfloat8_t a;
>> +  };
>> +
>> +  union union1
>> +  {
>> +    mfloat8_t a;
>> +  };
>> +
>> +  /* Addressing and dereferencing.  */
>> +
>> +  mfloat8_t *fp8_ptr = &scalar0;
>> +  scalar0 = *fp8_ptr;
>> +
>> +  /* Pointer assignment.  */
>> +
>> +  mfloat8_t *fp8_ptr2 = fp8_ptr;
>> +  mfloat8_t *fp8_ptr3 = array;
>> +
>> +  /* Pointer arithmetic.  */
>> +
>> +  ++fp8_ptr;
>> +  --fp8_ptr;
>> +  fp8_ptr++;
>> +  fp8_ptr--;
>> +  fp8_ptr += 1;
>> +  fp8_ptr -= 1;
>> +  fp8_ptr - fp8_ptr2;
>> +  fp8_ptr = &fp8_ptr3[0];
>> +  fp8_ptr = &fp8_ptr3[1];
>> +
>> +  /* Simple comparison.  */
>> +  scalar0 > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8
>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_a_float
>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 > 0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 == scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0
>> +      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  is_an_int
>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Pointer comparison.  */
>> +
>> +  fp8_ptr == &scalar0;
>> +  fp8_ptr != &scalar0;
>> +  fp8_ptr < &scalar0;
>> +  fp8_ptr <= &scalar0;
>> +  fp8_ptr > &scalar0;
>> +  fp8_ptr >= &scalar0;
>> +  fp8_ptr == fp8_ptr2;
>> +  fp8_ptr != fp8_ptr2;
>> +  fp8_ptr < fp8_ptr2;
>> +  fp8_ptr <= fp8_ptr2;
>> +  fp8_ptr > fp8_ptr2;
>> +  fp8_ptr >= fp8_ptr2;
>> +
>> +  /* Conditional expressions.  */
>> +
>> +  0 ? scalar0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? scalar0
>> +    : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? is_a_float
>> +    : scalar0;     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? scalar0 : 0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? 0 : scalar0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? 0.1 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? scalar0 : 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  0 ? fp8_ptr : fp8_ptr2;
>> +  0 ? fp8_ptr : uint8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
>> +  0 ? uint8_ptr : fp8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
>> +
>> +  scalar0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 ? is_a_float /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 ? scalar0 : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  /* Unary operators.  */
>> +
>> +  +scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  -scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  ~scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  !scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  *scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  ++scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  --scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  scalar0++;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +  scalar0--;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>> +
>> +  /* Binary arithmetic operations.  */
>> +
>> +  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 = glob_fp8 + *fp8_ptr; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0 = glob_fp8
>> +    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0
>> +      = glob_fp8 + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  scalar0
>> +      = glob_fp8
>> + + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 && glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +  glob_fp8 || glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>> +
>> +  return scalar0;
>> +}
>> +
>> +/* Check that function decls for mfloat8_t and unsigned char differ */
>> +
>> +mfloat8_t extern_fn1(void);
>> +unsigned char extern_fn1(void); /* { dg-error {conflicting types for 'extern_fn1'; have 'unsigned char\(void\)'} } */
>> +
>> +mfloat8_t extern_fn2(void);
>> +uint8_t extern_fn2(void); /* { dg-error {conflicting types for 'extern_fn2'; have 'uint8_t\(void\)'} } */
>> +
>> +unsigned char extern_fn3(void);
>> +mfloat8_t extern_fn3(void); /* { dg-error {conflicting types for 'extern_fn3'; have 'mfloat8_t\(void\)'} } */
>> +
>> +uint8_t extern_fn4(void);
>> +mfloat8_t extern_fn4(void); /* { dg-error {conflicting types for 'extern_fn4'; have 'mfloat8_t\(void\)'} } */
>> +
>> +void extern_fn5(mfloat8_t);
>> +void extern_fn5(unsigned char); /* { dg-error {conflicting types for 'extern_fn5'; have 'void\(unsigned char\)'} } */
>> +
>> +void extern_fn6(mfloat8_t);
>> +void extern_fn6(uint8_t); /* { dg-error {conflicting types for 'extern_fn6'; have 'void\(uint8_t\)'} } */
>
  
Kyrylo Tkachov Sept. 20, 2024, 8 a.m. UTC | #3
> On 19 Sep 2024, at 15:39, Claudio Bantaloukas <claudio.bantaloukas@arm.com> wrote:
> 
> External email: Use caution opening links or attachments
> 
> 
> On 9/19/2024 2:18 PM, Kyrylo Tkachov wrote:
>> Hi Claudio,
>> 
>>> On 19 Sep 2024, at 15:09, Claudio Bantaloukas <claudio.bantaloukas@arm.com> wrote:
>>> 
>>> External email: Use caution opening links or attachments
>>> 
>>> 
>>> The ACLE defines a new scalar type, __mfp8. This is an opaque 8bit types that
>>> can only be used by fp8 intrinsics. Additionally, the mfloat8_t type is made
>>> available in arm_neon.h and arm_sve.h as an alias of the same.
>>> 
>>> This implementation uses an unsigned INTEGER_TYPE, with precision 8 to
>>> represent __mfp8. Conversions to int and other types are disabled via the
>>> TARGET_INVALID_CONVERSION hook.
>>> Additionally, operations that are typically available to integer types are
>>> disabled via TARGET_INVALID_UNARY_OP and TARGET_INVALID_BINARY_OP hooks.
>>> 
>>> gcc/ChangeLog:
>>> 
>>>        * config/aarch64/aarch64-builtins.cc (aarch64_mfp8_type_node): Add node
>>>        for __mfp8 type.
>>>        (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
>>>        (aarch64_init_fp8_types): New function to initialise fp8 types and
>>>        register with language backends.
>>>        * config/aarch64/aarch64.cc (aarch64_mangle_type): Add ABI mangling for
>>>        new type.
>>>        (aarch64_invalid_conversion): Add function implementing
>>>        TARGET_INVALID_CONVERSION hook that blocks conversion to and from the
>>>        __mfp8 type.
>>>        (aarch64_invalid_unary_op): Add function implementing TARGET_UNARY_OP
>>>        hook that blocks operations on __mfp8 other than &.
>>>        (aarch64_invalid_binary_op): Extend TARGET_BINARY_OP hook to disallow
>>>        operations on __mfp8 type.
>>>        (TARGET_INVALID_CONVERSION): Add define.
>>>        (TARGET_INVALID_UNARY_OP): Likewise.
>>>        * config/aarch64/aarch64.h (aarch64_mfp8_type_node): Add node for __mfp8
>>>        type.
>>>        (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type.
>>>        * config/aarch64/arm_neon.h (mfloat8_t): Add typedef.
>>>        * config/aarch64/arm_sve.h (mfloat8_t): Likewise.
>> 
>> Looks like this typedef is a good candidate to go into arm_private_fp8.h so that arm_neon.h, arm_sve.h and arm_sme.h inherit it.
> 
> Hi Kyrill,
> thanks for the quick review. The thought of using arm_private_fp8.h
> crossed my mind but I thought that ultimately it made more sense to
> follow existing practice and place the typedef near existing ones for
> bfloat types.
> If you feel strongly about this, I'll make the suggested change, but I'd
> rather keep it as is. As you can see, the rest of the patch borrows
> heavily in style from the bfloat implementation and my hope is that the
> closeness in code will aid in maintainability.

I see. It’s not an unreasonable argument.  But the bfloat16 implementation does exactly that :)
The "typedef __bf16 bfloat16_t” is defined in arm_bf16.h and that is in turn included in arm_neon.h, arm_sve.h (and therefore arm_sme.h) so arm_bfp16.h performs the same role as arm_private_fp8.h so it seems consistent to define the fp8 typedefs in arm_private_fp8.h
The rest of the patch looks reasonable to me but I think Richard should give the final okay as he’s done the initial review.

Thanks,
Kyrill

> 
> Let me know :)
> 
> Cheers,
> Claudio
> 
>> 
>> Thanks,
>> Kyrill
>> 
>> 
>>> 
>>> gcc/testsuite/ChangeLog:
>>> 
>>>        * g++.target/aarch64/fp8_mangling.C: New tests exercising mangling.
>>>        * g++.target/aarch64/fp8_scalar_typecheck_2.C: New tests in C++.
>>>        * gcc.target/aarch64/fp8_scalar_1.c: New tests in C.
>>>        * gcc.target/aarch64/fp8_scalar_typecheck_1.c: Likewise.
>>> ---
>>> Hi,
>>> Is this ok for master? I do not have commit rights yet, if ok, can someone commit it on my behalf?
>>> 
>>> Regression tested with aarch64-unknown-linux-gnu.
>>> 
>>> Compared to V1 of the patch, in version 2:
>>> - mangling for the __mfp8 type was added along with tests
>>> - unneeded comments were removed
>>> - simplified type checks in hooks
>>> - simplified initialization of aarch64_mfp8_type_node
>>> - separated mfloat8_t define from other fp types in arm_sve.h
>>> - C++ tests were moved to g++.target/aarch64
>>> - added more tests around binary operations, function declaration,
>>>  type traits
>>> - added tests exercising loads and stores from floating point registers
>>> 
>>> 
>>> Thanks,
>>> Claudio Bantaloukas
>>> 
>>> gcc/config/aarch64/aarch64-builtins.cc        |  20 +
>>> gcc/config/aarch64/aarch64.cc                 |  54 ++-
>>> gcc/config/aarch64/aarch64.h                  |   5 +
>>> gcc/config/aarch64/arm_neon.h                 |   2 +
>>> gcc/config/aarch64/arm_sve.h                  |   2 +
>>> .../g++.target/aarch64/fp8_mangling.C         |  44 ++
>>> .../aarch64/fp8_scalar_typecheck_2.C          | 381 ++++++++++++++++++
>>> .../gcc.target/aarch64/fp8_scalar_1.c         | 134 ++++++
>>> .../aarch64/fp8_scalar_typecheck_1.c          | 356 ++++++++++++++++
>>> 9 files changed, 996 insertions(+), 2 deletions(-)
>>> create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_mangling.C
>>> create mode 100644 gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
>>> create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
>>> create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
>>> 
>>> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
>>> index eb878b933fe..7d17df05a0f 100644
>>> --- a/gcc/config/aarch64/aarch64-builtins.cc
>>> +++ b/gcc/config/aarch64/aarch64-builtins.cc
>>> @@ -961,6 +961,11 @@ static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE;
>>> static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE;
>>> static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE;
>>> 
>>> +/* The user-visible __mfp8 type, and a pointer to that type.  Used
>>> +   across the back-end.  */
>>> +tree aarch64_mfp8_type_node = NULL_TREE;
>>> +tree aarch64_mfp8_ptr_type_node = NULL_TREE;
>>> +
>>> /* The user-visible __fp16 type, and a pointer to that type.  Used
>>>    across the back-end.  */
>>> tree aarch64_fp16_type_node = NULL_TREE;
>>> @@ -1721,6 +1726,19 @@ aarch64_init_builtin_rsqrt (void)
>>>   }
>>> }
>>> 
>>> +/* Initialize the backend type that supports the user-visible __mfp8
>>> +   type and its relative pointer type.  */
>>> +
>>> +static void
>>> +aarch64_init_fp8_types (void)
>>> +{
>>> +  aarch64_mfp8_type_node = make_unsigned_type (8);
>>> +  SET_TYPE_MODE (aarch64_mfp8_type_node, QImode);
>>> +
>>> +  lang_hooks.types.register_builtin_type (aarch64_mfp8_type_node, "__mfp8");
>>> +  aarch64_mfp8_ptr_type_node = build_pointer_type (aarch64_mfp8_type_node);
>>> +}
>>> +
>>> /* Initialize the backend types that support the user-visible __fp16
>>>    type, also initialize a pointer to that type, to be used when
>>>    forming HFAs.  */
>>> @@ -2125,6 +2143,8 @@ aarch64_general_init_builtins (void)
>>> {
>>>   aarch64_init_fpsr_fpcr_builtins ();
>>> 
>>> +  aarch64_init_fp8_types ();
>>> +
>>>   aarch64_init_fp16_types ();
>>> 
>>>   aarch64_init_bf16_types ();
>>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
>>> index 92763d403c7..0ac00027502 100644
>>> --- a/gcc/config/aarch64/aarch64.cc
>>> +++ b/gcc/config/aarch64/aarch64.cc
>>> @@ -22467,6 +22467,10 @@ aarch64_mangle_type (const_tree type)
>>> return "Dh";
>>>     }
>>> 
>>> +  /* Modal 8 bit floating point types.  */
>>> +  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node)
>>> +    return "u6__mfp8";
>>> +
>>>   /* Mangle AArch64-specific internal types.  TYPE_NAME is non-NULL_TREE for
>>>      builtin types.  */
>>>   if (TYPE_NAME (type) != NULL)
>>> @@ -22481,6 +22485,29 @@ aarch64_mangle_type (const_tree type)
>>>   return NULL;
>>> }
>>> 
>>> +/* Implement TARGET_INVALID_CONVERSION.  */
>>> +
>>> +static const char *
>>> +aarch64_invalid_conversion (const_tree fromtype, const_tree totype)
>>> +{
>>> +  /* Do not allow conversions to/from FP8. But do allow conversions between
>>> +     volatile and const variants of __mfp8. */
>>> +  bool fromtype_is_fp8
>>> +      = (TYPE_MAIN_VARIANT (fromtype) == aarch64_mfp8_type_node);
>>> +  bool totype_is_fp8 = (TYPE_MAIN_VARIANT (totype) == aarch64_mfp8_type_node);
>>> +
>>> +  if (fromtype_is_fp8 && totype_is_fp8)
>>> +    return NULL;
>>> +
>>> +  if (fromtype_is_fp8)
>>> +    return N_ ("invalid conversion from type %<mfloat8_t%>");
>>> +  if (totype_is_fp8)
>>> +    return N_ ("invalid conversion to type %<mfloat8_t%>");
>>> +
>>> +  /* Conversion allowed.  */
>>> +  return NULL;
>>> +}
>>> +
>>> /* Implement TARGET_VERIFY_TYPE_CONTEXT.  */
>>> 
>>> static bool
>>> @@ -29031,8 +29058,20 @@ aarch64_stack_protect_guard (void)
>>>   return NULL_TREE;
>>> }
>>> 
>>> -/* Return the diagnostic message string if the binary operation OP is
>>> -   not permitted on TYPE1 and TYPE2, NULL otherwise.  */
>>> +/* Implement TARGET_INVALID_UNARY_OP.  */
>>> +
>>> +static const char *
>>> +aarch64_invalid_unary_op (int op, const_tree type)
>>> +{
>>> +  /* Reject all single-operand operations on __mfp8 except for &.  */
>>> +  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node && op != ADDR_EXPR)
>>> +    return N_ ("operation not permitted on type %<mfloat8_t%>");
>>> +
>>> +  /* Operation allowed.  */
>>> +  return NULL;
>>> +}
>>> +
>>> +/* Implement TARGET_INVALID_BINARY_OP.  */
>>> 
>>> static const char *
>>> aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
>>> @@ -29046,6 +29085,11 @@ aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
>>>  != aarch64_sve::builtin_type_p (type2)))
>>>     return N_("cannot combine GNU and SVE vectors in a binary operation");
>>> 
>>> +  /* Reject all 2-operand operations on __mfp8.  */
>>> +  if (TYPE_MAIN_VARIANT (type1) == aarch64_mfp8_type_node
>>> +      || TYPE_MAIN_VARIANT (type2) == aarch64_mfp8_type_node)
>>> +    return N_ ("operation not permitted on type %<mfloat8_t%>");
>>> +
>>>   /* Operation allowed.  */
>>>   return NULL;
>>> }
>>> @@ -30763,6 +30807,12 @@ aarch64_libgcc_floating_mode_supported_p
>>> #undef TARGET_MANGLE_TYPE
>>> #define TARGET_MANGLE_TYPE aarch64_mangle_type
>>> 
>>> +#undef TARGET_INVALID_CONVERSION
>>> +#define TARGET_INVALID_CONVERSION aarch64_invalid_conversion
>>> +
>>> +#undef TARGET_INVALID_UNARY_OP
>>> +#define TARGET_INVALID_UNARY_OP aarch64_invalid_unary_op
>>> +
>>> #undef TARGET_INVALID_BINARY_OP
>>> #define TARGET_INVALID_BINARY_OP aarch64_invalid_binary_op
>>> 
>>> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
>>> index 2dfb999bea5..7ef82ce3587 100644
>>> --- a/gcc/config/aarch64/aarch64.h
>>> +++ b/gcc/config/aarch64/aarch64.h
>>> @@ -1447,6 +1447,11 @@ extern const char *aarch64_rewrite_mcpu (int argc, const char **argv);
>>> 
>>> #define ASM_OUTPUT_POOL_EPILOGUE  aarch64_asm_output_pool_epilogue
>>> 
>>> +/* This type is the user-visible __mfp8, and a pointer to that type.  We
>>> +   need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
>>> +extern GTY(()) tree aarch64_mfp8_type_node;
>>> +extern GTY(()) tree aarch64_mfp8_ptr_type_node;
>>> +
>>> /* This type is the user-visible __fp16, and a pointer to that type.  We
>>>    need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
>>> extern GTY(()) tree aarch64_fp16_type_node;
>>> diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
>>> index e376685489d..0092314cf75 100644
>>> --- a/gcc/config/aarch64/arm_neon.h
>>> +++ b/gcc/config/aarch64/arm_neon.h
>>> @@ -72,6 +72,8 @@ typedef __Poly16_t poly16_t;
>>> typedef __Poly64_t poly64_t;
>>> typedef __Poly128_t poly128_t;
>>> 
>>> +typedef __mfp8 mfloat8_t;
>>> +
>>> typedef __fp16 float16_t;
>>> typedef float float32_t;
>>> typedef double float64_t;
>>> diff --git a/gcc/config/aarch64/arm_sve.h b/gcc/config/aarch64/arm_sve.h
>>> index aa0bd9909f9..dbc61650df2 100644
>>> --- a/gcc/config/aarch64/arm_sve.h
>>> +++ b/gcc/config/aarch64/arm_sve.h
>>> @@ -29,6 +29,8 @@
>>> #include <arm_private_fp8.h>
>>> #include <arm_bf16.h>
>>> 
>>> +typedef __mfp8 mfloat8_t;
>>> +
>>> typedef __fp16 float16_t;
>>> typedef float float32_t;
>>> typedef double float64_t;
>>> diff --git a/gcc/testsuite/g++.target/aarch64/fp8_mangling.C b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
>>> new file mode 100644
>>> index 00000000000..1dfcaa71f15
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
>>> @@ -0,0 +1,44 @@
>>> +/* Test that mfloat8_t mangles differently from uint8_t  */
>>> +/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
>>> +
>>> +int
>>> +foo (__mfp8)
>>> +{
>>> +  return 1;
>>> +}
>>> +
>>> +int
>>> +foo (unsigned char)
>>> +{
>>> +  return 2;
>>> +}
>>> +
>>> +int
>>> +bar (__mfp8 x)
>>> +{
>>> +  return foo (x);
>>> +}
>>> +/* { dg-final { scan-assembler-times "\n_Z3fooh:\n" 1 } } */
>>> +/* { dg-final { scan-assembler-times "\n_Z3foou6__mfp8:\n" 1 } } */
>>> +
>>> +constexpr __mfp8 cfp8{};
>>> +
>>> +constexpr int
>>> +fooc (unsigned char)
>>> +{
>>> +  return 3;
>>> +}
>>> +
>>> +constexpr int
>>> +fooc (__mfp8)
>>> +{
>>> +  return 4;
>>> +}
>>> +
>>> +constexpr int
>>> +barc (__mfp8 x)
>>> +{
>>> +  return fooc (x);
>>> +}
>>> +
>>> +static_assert (barc (cfp8) == 4, "constexpr selects incorrect overload");
>>> diff --git a/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
>>> new file mode 100644
>>> index 00000000000..61557c95663
>>> --- /dev/null
>>> +++ b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
>>> @@ -0,0 +1,381 @@
>>> +/* Test that mfloat8_t is only usable with intrinsics, thus not convertible.  */
>>> +/* { dg-do assemble } */
>>> +/* { dg-options "-O1 -march=armv9.4-a+fp8 -Wno-narrowing" } */
>>> +
>>> +#include <arm_neon.h>
>>> +#include <stdint.h>
>>> +#include <type_traits>
>>> +
>>> +mfloat8_t glob_fp8;
>>> +
>>> +int is_an_int;
>>> +uint8_t is_a_uint8;
>>> +int8_t is_an_int8;
>>> +short is_a_short_int;
>>> +float is_a_float;
>>> +double is_a_double;
>>> +
>>> +uint8_t *uint8_ptr;
>>> +
>>> +mfloat8_t
>>> +invalid_from_fp8 (uint16_t __a)
>>> +{
>>> +  mfloat8_t b = __a; /* { dg-error "invalid conversion to type 'mfloat8_t'" } */
>>> +  return b;
>>> +}
>>> +
>>> +uint16_t
>>> +invalid_to_fp8 (mfloat8_t __a)
>>> +{
>>> +  uint16_t b = __a; /*{ dg-error "invalid conversion from type 'mfloat8_t'" } */
>>> +  return b;
>>> +}
>>> +
>>> +mfloat8_t
>>> +foo1 (void)
>>> +{
>>> +  return (mfloat8_t)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +}
>>> +
>>> +mfloat8_t
>>> +foo2 (void)
>>> +{
>>> +  return (mfloat8_t)(short)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +}
>>> +
>>> +mfloat8_t
>>> +footest (mfloat8_t scalar0)
>>> +{
>>> +
>>> +  /* Initialisation  */
>>> +
>>> +  mfloat8_t scalar1_1;
>>> +  mfloat8_t scalar1_2 = glob_fp8;
>>> +  mfloat8_t scalar1_3
>>> +      = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_4
>>> +      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_5
>>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_6
>>> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_8
>>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_9 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_10
>>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_11
>>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  int initi_1_1
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  float initi_1_2
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  short initi_1_4
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  double initi_1_5
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  uint8_t initi_1_6
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  int8_t initi_1_7
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  mfloat8_t scalar2_1 = {};
>>> +  mfloat8_t scalar2_2 = { glob_fp8 };
>>> +  mfloat8_t scalar2_3
>>> +      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_4
>>> +      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_5 = {
>>> +    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  mfloat8_t scalar2_6 = {
>>> +    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  mfloat8_t scalar2_8 = {
>>> +    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  mfloat8_t scalar2_9 = {
>>> +    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  mfloat8_t scalar2_10 = {
>>> +    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  mfloat8_t scalar2_11 = {
>>> +    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +
>>> +  int initi_2_1 = {
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  float initi_2_2 = {
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  short initi_2_4 = {
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  double initi_2_5 = {
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  uint8_t initi_2_6 = {
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  int8_t initi_2_7 = {
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +
>>> +  /* Assignments.  */
>>> +
>>> +  glob_fp8 = glob_fp8;
>>> +  glob_fp8 = 0;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  is_an_int
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_float
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_double
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_short_int
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_uint8
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_an_int8
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Casting.  */
>>> +
>>> +  (void)glob_fp8;
>>> +  (mfloat8_t) glob_fp8;
>>> +
>>> +  (int)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (float)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (double)
>>> +      glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (short)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (uint8_t)
>>> +      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (int8_t)
>>> +      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  (mfloat8_t)
>>> +      is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t)
>>> +      is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t)
>>> +      is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t) is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t)
>>> +      is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t)
>>> +      is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  /* Compound literals.  */
>>> +
>>> +  (mfloat8_t){};
>>> +  (mfloat8_t){ glob_fp8 };
>>> +  (mfloat8_t){ 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){
>>> +    0.1 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  (mfloat8_t){
>>> +    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  (mfloat8_t){
>>> +    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  (mfloat8_t){
>>> +    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  (mfloat8_t){
>>> +    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  (mfloat8_t){
>>> +    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +  (mfloat8_t){
>>> +    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  };
>>> +
>>> +  (int){
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  (float){
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  (double){
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  (short){
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  (uint8_t){
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +  (int8_t){
>>> +    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  };
>>> +
>>> +  /* Arrays and Structs.  */
>>> +
>>> +  typedef mfloat8_t array_type[2];
>>> +  extern mfloat8_t extern_array[];
>>> +
>>> +  mfloat8_t array[2];
>>> +  mfloat8_t zero_length_array[0];
>>> +  mfloat8_t empty_init_array[] = {};
>>> +  typedef mfloat8_t some_other_type[is_an_int];
>>> +
>>> +  struct struct1
>>> +  {
>>> +    mfloat8_t a;
>>> +  };
>>> +
>>> +  union union1
>>> +  {
>>> +    mfloat8_t a;
>>> +  };
>>> +
>>> +  /* Addressing and dereferencing.  */
>>> +
>>> +  mfloat8_t *fp8_ptr = &scalar0;
>>> +  scalar0 = *fp8_ptr;
>>> +
>>> +  /* Pointer assignment.  */
>>> +
>>> +  mfloat8_t *fp8_ptr2 = fp8_ptr;
>>> +  mfloat8_t *fp8_ptr3 = array;
>>> +
>>> +  /* Pointer arithmetic.  */
>>> +
>>> +  ++fp8_ptr;
>>> +  --fp8_ptr;
>>> +  fp8_ptr++;
>>> +  fp8_ptr--;
>>> +  fp8_ptr += 1;
>>> +  fp8_ptr -= 1;
>>> +  fp8_ptr - fp8_ptr2;
>>> +  fp8_ptr = &fp8_ptr3[0];
>>> +  fp8_ptr = &fp8_ptr3[1];
>>> +
>>> +  /* Simple comparison.  */
>>> +  scalar0
>>> +      > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_float
>>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 > 0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 == scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0
>>> +      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_an_int
>>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Pointer comparison.  */
>>> +
>>> +  fp8_ptr == &scalar0;
>>> +  fp8_ptr != &scalar0;
>>> +  fp8_ptr < &scalar0;
>>> +  fp8_ptr <= &scalar0;
>>> +  fp8_ptr > &scalar0;
>>> +  fp8_ptr >= &scalar0;
>>> +  fp8_ptr == fp8_ptr2;
>>> +  fp8_ptr != fp8_ptr2;
>>> +  fp8_ptr < fp8_ptr2;
>>> +  fp8_ptr <= fp8_ptr2;
>>> +  fp8_ptr > fp8_ptr2;
>>> +  fp8_ptr >= fp8_ptr2;
>>> +
>>> +  /* Conditional expressions.  */
>>> +
>>> +  0 ? scalar0 : scalar0;
>>> +  0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +    : is_a_float;
>>> +  0 ? is_a_float
>>> +    : scalar0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? scalar0 : 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? 0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? 0.1
>>> +    : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? scalar0  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +    : 0.1;
>>> +  0 ? fp8_ptr : fp8_ptr2;
>>> +  0 ? fp8_ptr : uint8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
>>> +  0 ? uint8_ptr : fp8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
>>> +
>>> +  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +      ? scalar0
>>> +      : scalar0;
>>> +  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +      ? is_a_float
>>> +      : scalar0;
>>> +  scalar0 ? scalar0 : is_a_float;    /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Unary operators.  */
>>> +
>>> +  +scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  -scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  ~scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  !scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  *scalar0; /* { dg-error {invalid type argument of unary} } */
>>> +  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  ++scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  --scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  scalar0++; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  scalar0--; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +
>>> +  /* Binary arithmetic operations.  */
>>> +
>>> +  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 = glob_fp8 + *fp8_ptr;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 = glob_fp8
>>> +    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 = glob_fp8
>>> +    + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 = glob_fp8 + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 && glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  glob_fp8 || glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +
>>> +  return scalar0;
>>> +}
>>> +
>>> +/* Check that function decls for mfloat8_t and unsigned char differ */
>>> +
>>> +mfloat8_t extern_fn1(void);
>>> +unsigned char extern_fn1(void); /* { dg-error {ambiguating new declaration of 'unsigned char extern_fn1\(\)'} } */
>>> +
>>> +mfloat8_t extern_fn2(void);
>>> +uint8_t extern_fn2(void); /* { dg-error {ambiguating new declaration of 'uint8_t extern_fn2\(\)} } */
>>> +
>>> +unsigned char extern_fn3(void);
>>> +mfloat8_t extern_fn3(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn3\(\)} } */
>>> +
>>> +uint8_t extern_fn4(void);
>>> +mfloat8_t extern_fn4(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn4\(\)} } */
>>> +
>>> +/* Check that the type conforms to the contract */
>>> +static_assert(!std::is_integral<__mfp8>(), "not integral");
>>> +static_assert(!std::is_signed<__mfp8>(), "not signed");
>>> +static_assert(!std::is_unsigned<__mfp8>(), "not unsigned");
>>> diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
>>> new file mode 100644
>>> index 00000000000..1bc2ac26b2a
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
>>> @@ -0,0 +1,134 @@
>>> +/* Test the fp8 ACLE intrinsics family.  */
>>> +/* { dg-do compile } */
>>> +/* { dg-options "-O2 -march=armv9.4-a+fp8" } */
>>> +/* { dg-final { check-function-bodies "**" "" "" } } */
>>> +
>>> +#include <arm_neon.h>
>>> +
>>> +/*
>>> +**stacktest1:
>>> +** sub sp, sp, #16
>>> +** and w0, w0, 255
>>> +** strb w0, \[sp, 15\]
>>> +** ldrb w0, \[sp, 15\]
>>> +** add sp, sp, 16
>>> +** ret
>>> +*/
>>> +mfloat8_t
>>> +stacktest1 (mfloat8_t __a)
>>> +{
>>> +  volatile mfloat8_t b = __a;
>>> +  return b;
>>> +}
>>> +
>>> +/*
>>> +**fp8_mov_ww:
>>> +** dup b1, v2.b\[0\]
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_mov_ww (void)
>>> +{
>>> +  register mfloat8_t x asm ("h2");
>>> +  register mfloat8_t y asm ("h1");
>>> +  asm volatile ("" : "=w"(x));
>>> +  y = x;
>>> +  asm volatile ("" ::"w"(y));
>>> +}
>>> +
>>> +/*
>>> +**fp8_mov_rw:
>>> +** dup v1.8b, w1
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_mov_rw (void)
>>> +{
>>> +  register mfloat8_t x asm ("w1");
>>> +  register mfloat8_t y asm ("h1");
>>> +  asm volatile ("" : "=r"(x));
>>> +  y = x;
>>> +  asm volatile ("" ::"w"(y));
>>> +}
>>> +
>>> +/*
>>> +**fp8_mov_wr:
>>> +** umov w1, v1.b\[0\]
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_mov_wr (void)
>>> +{
>>> +  register mfloat8_t x asm ("h1");
>>> +  register mfloat8_t y asm ("w1");
>>> +  asm volatile ("" : "=w"(x));
>>> +  y = x;
>>> +  asm volatile ("" ::"r"(y));
>>> +}
>>> +
>>> +/*
>>> +**fp8_mov_rr:
>>> +** mov w1, w2
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_mov_rr (void)
>>> +{
>>> +  register mfloat8_t x asm ("w2");
>>> +  register mfloat8_t y asm ("w1");
>>> +  asm volatile ("" : "=r"(x));
>>> +  y = x;
>>> +  asm volatile ("" ::"r"(y));
>>> +}
>>> +
>>> +/*
>>> +**fp8_mov_rm:
>>> +** strb w2, \[x0\]
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_mov_rm (mfloat8_t *ptr)
>>> +{
>>> +  register mfloat8_t x asm ("w2");
>>> +  asm volatile ("" : "=r"(x));
>>> +  *ptr = x;
>>> +}
>>> +
>>> +/*
>>> +**fp8_mov_mr:
>>> +** ldrb w2, \[x0\]
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_mov_mr (mfloat8_t *ptr)
>>> +{
>>> +  register mfloat8_t y asm ("w2");
>>> +  y = *ptr;
>>> +  asm volatile ("" ::"r"(y));
>>> +}
>>> +
>>> +/*
>>> +**fp8_str_r:
>>> +** str b2, \[x0\]
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_str_r (mfloat8_t *ptr)
>>> +{
>>> +  register mfloat8_t x asm ("v2");
>>> +  asm volatile ("" : "=w"(x));
>>> +  *ptr = x;
>>> +}
>>> +
>>> +/*
>>> +**fp8_ldr_r:
>>> +** ldr b2, \[x0\]
>>> +** ret
>>> +*/
>>> +void
>>> +fp8_ldr_r (mfloat8_t *ptr)
>>> +{
>>> +  register mfloat8_t y asm ("v2");
>>> +  y = *ptr;
>>> +  asm volatile ("" ::"w"(y));
>>> +}
>>> diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
>>> new file mode 100644
>>> index 00000000000..9169f40c4b7
>>> --- /dev/null
>>> +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
>>> @@ -0,0 +1,356 @@
>>> +/* Test that there is no conversion between ints and mfloat8_t.  */
>>> +/* { dg-do assemble } */
>>> +/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
>>> +
>>> +#include <arm_neon.h>
>>> +#include <stdint.h>
>>> +
>>> +mfloat8_t glob_fp8;
>>> +
>>> +int is_an_int;
>>> +uint8_t is_a_uint8;
>>> +int8_t is_an_int8;
>>> +short is_a_short_int;
>>> +float is_a_float;
>>> +double is_a_double;
>>> +
>>> +uint8_t *uint8_ptr;
>>> +
>>> +mfloat8_t
>>> +invalid_from_fp8 (uint16_t __a)
>>> +{
>>> +  mfloat8_t b = __a; // { dg-error "invalid conversion to type 'mfloat8_t'" }
>>> +  return b;
>>> +}
>>> +
>>> +uint16_t
>>> +invalid_to_fp8 (mfloat8_t __a)
>>> +{
>>> +  uint16_t b = __a; // { dg-error "invalid conversion from type 'mfloat8_t'" }
>>> +  return b;
>>> +}
>>> +
>>> +mfloat8_t
>>> +foo1 (void)
>>> +{
>>> +  return (mfloat8_t)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
>>> +}
>>> +mfloat8_t
>>> +foo2 (void)
>>> +{
>>> +  return (mfloat8_t)(short)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
>>> +}
>>> +
>>> +mfloat8_t
>>> +footest (mfloat8_t scalar0)
>>> +{
>>> +
>>> +  /* Initialisation  */
>>> +
>>> +  mfloat8_t scalar1_1;
>>> +  mfloat8_t scalar1_2 = glob_fp8;
>>> +  mfloat8_t scalar1_3 = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_4
>>> +      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_5
>>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_6
>>> +      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_8
>>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_9
>>> +      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_10
>>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar1_11
>>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  int initi_1_1
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  float initi_1_2
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  short initi_1_4
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  double initi_1_5
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  uint8_t initi_1_6
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  int8_t initi_1_7
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  mfloat8_t scalar2_1 = {};
>>> +  mfloat8_t scalar2_2 = { glob_fp8 };
>>> +  mfloat8_t scalar2_3
>>> +      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_4
>>> +      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_5
>>> +      = { is_a_float }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_6
>>> +      = { is_an_int }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_8 = {
>>> +    is_a_double
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_9 = {
>>> +    is_a_short_int
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_10
>>> +      = { is_a_uint8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  mfloat8_t scalar2_11
>>> +      = { is_an_int8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  int initi_2_1
>>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  float initi_2_2
>>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  short initi_2_4
>>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  double initi_2_5
>>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  uint8_t initi_2_6
>>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  int8_t initi_2_7
>>> +      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Assignments.  */
>>> +
>>> +  glob_fp8 = glob_fp8;
>>> +  glob_fp8 = 0;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8 = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  is_an_int
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_float
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_double
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_short_int
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_uint8
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_an_int8
>>> +      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Casting.  */
>>> +
>>> +  (void)glob_fp8;
>>> +  (mfloat8_t) glob_fp8;
>>> +
>>> +  (int)glob_fp8;     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (float)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (double)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (short)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (uint8_t)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (int8_t)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  (mfloat8_t) is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t) is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t) is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t)
>>> +      is_a_short_int;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t) is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t) is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  /* Compound literals.  */
>>> +
>>> +  (mfloat8_t){};
>>> +  (mfloat8_t){ glob_fp8 };
>>> +  (mfloat8_t){ 0 };   /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){ 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){
>>> +    is_a_float
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){
>>> +    is_an_int
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){
>>> +    is_a_double
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){
>>> +    is_a_short_int
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){
>>> +    is_a_uint8
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +  (mfloat8_t){
>>> +    is_an_int8
>>> +  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
>>> +
>>> +  (int){ glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (float){
>>> +    glob_fp8
>>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (double){
>>> +    glob_fp8
>>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (short){
>>> +    glob_fp8
>>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (uint8_t){
>>> +    glob_fp8
>>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  (int8_t){
>>> +    glob_fp8
>>> +  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Arrays and Structs.  */
>>> +
>>> +  typedef mfloat8_t array_type[2];
>>> +  extern mfloat8_t extern_array[];
>>> +
>>> +  mfloat8_t array[2];
>>> +  mfloat8_t zero_length_array[0];
>>> +  mfloat8_t empty_init_array[] = {};
>>> +  typedef mfloat8_t some_other_type[is_an_int];
>>> +
>>> +  struct struct1
>>> +  {
>>> +    mfloat8_t a;
>>> +  };
>>> +
>>> +  union union1
>>> +  {
>>> +    mfloat8_t a;
>>> +  };
>>> +
>>> +  /* Addressing and dereferencing.  */
>>> +
>>> +  mfloat8_t *fp8_ptr = &scalar0;
>>> +  scalar0 = *fp8_ptr;
>>> +
>>> +  /* Pointer assignment.  */
>>> +
>>> +  mfloat8_t *fp8_ptr2 = fp8_ptr;
>>> +  mfloat8_t *fp8_ptr3 = array;
>>> +
>>> +  /* Pointer arithmetic.  */
>>> +
>>> +  ++fp8_ptr;
>>> +  --fp8_ptr;
>>> +  fp8_ptr++;
>>> +  fp8_ptr--;
>>> +  fp8_ptr += 1;
>>> +  fp8_ptr -= 1;
>>> +  fp8_ptr - fp8_ptr2;
>>> +  fp8_ptr = &fp8_ptr3[0];
>>> +  fp8_ptr = &fp8_ptr3[1];
>>> +
>>> +  /* Simple comparison.  */
>>> +  scalar0 > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8
>>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_a_float
>>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 > 0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 == scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0
>>> +      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  is_an_int
>>> +      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Pointer comparison.  */
>>> +
>>> +  fp8_ptr == &scalar0;
>>> +  fp8_ptr != &scalar0;
>>> +  fp8_ptr < &scalar0;
>>> +  fp8_ptr <= &scalar0;
>>> +  fp8_ptr > &scalar0;
>>> +  fp8_ptr >= &scalar0;
>>> +  fp8_ptr == fp8_ptr2;
>>> +  fp8_ptr != fp8_ptr2;
>>> +  fp8_ptr < fp8_ptr2;
>>> +  fp8_ptr <= fp8_ptr2;
>>> +  fp8_ptr > fp8_ptr2;
>>> +  fp8_ptr >= fp8_ptr2;
>>> +
>>> +  /* Conditional expressions.  */
>>> +
>>> +  0 ? scalar0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? scalar0
>>> +    : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? is_a_float
>>> +    : scalar0;     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? scalar0 : 0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? 0 : scalar0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? 0.1 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? scalar0 : 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  0 ? fp8_ptr : fp8_ptr2;
>>> +  0 ? fp8_ptr : uint8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
>>> +  0 ? uint8_ptr : fp8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
>>> +
>>> +  scalar0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 ? is_a_float /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 ? scalar0 : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  /* Unary operators.  */
>>> +
>>> +  +scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  -scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  ~scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  !scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  *scalar0;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  ++scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  --scalar0;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  scalar0++;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +  scalar0--;  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
>>> +
>>> +  /* Binary arithmetic operations.  */
>>> +
>>> +  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 = glob_fp8 + *fp8_ptr; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0 = glob_fp8
>>> +    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0
>>> +      = glob_fp8 + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  scalar0
>>> +      = glob_fp8
>>> + + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 && glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +  glob_fp8 || glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
>>> +
>>> +  return scalar0;
>>> +}
>>> +
>>> +/* Check that function decls for mfloat8_t and unsigned char differ */
>>> +
>>> +mfloat8_t extern_fn1(void);
>>> +unsigned char extern_fn1(void); /* { dg-error {conflicting types for 'extern_fn1'; have 'unsigned char\(void\)'} } */
>>> +
>>> +mfloat8_t extern_fn2(void);
>>> +uint8_t extern_fn2(void); /* { dg-error {conflicting types for 'extern_fn2'; have 'uint8_t\(void\)'} } */
>>> +
>>> +unsigned char extern_fn3(void);
>>> +mfloat8_t extern_fn3(void); /* { dg-error {conflicting types for 'extern_fn3'; have 'mfloat8_t\(void\)'} } */
>>> +
>>> +uint8_t extern_fn4(void);
>>> +mfloat8_t extern_fn4(void); /* { dg-error {conflicting types for 'extern_fn4'; have 'mfloat8_t\(void\)'} } */
>>> +
>>> +void extern_fn5(mfloat8_t);
>>> +void extern_fn5(unsigned char); /* { dg-error {conflicting types for 'extern_fn5'; have 'void\(unsigned char\)'} } */
>>> +
>>> +void extern_fn6(mfloat8_t);
>>> +void extern_fn6(uint8_t); /* { dg-error {conflicting types for 'extern_fn6'; have 'void\(uint8_t\)'} } */
>> 
> 
> --
> Claudio Bantaloukas
>
  

Patch

diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index eb878b933fe..7d17df05a0f 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -961,6 +961,11 @@  static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE;
 static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE;
 static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE;
 
+/* The user-visible __mfp8 type, and a pointer to that type.  Used
+   across the back-end.  */
+tree aarch64_mfp8_type_node = NULL_TREE;
+tree aarch64_mfp8_ptr_type_node = NULL_TREE;
+
 /* The user-visible __fp16 type, and a pointer to that type.  Used
    across the back-end.  */
 tree aarch64_fp16_type_node = NULL_TREE;
@@ -1721,6 +1726,19 @@  aarch64_init_builtin_rsqrt (void)
   }
 }
 
+/* Initialize the backend type that supports the user-visible __mfp8
+   type and its relative pointer type.  */
+
+static void
+aarch64_init_fp8_types (void)
+{
+  aarch64_mfp8_type_node = make_unsigned_type (8);
+  SET_TYPE_MODE (aarch64_mfp8_type_node, QImode);
+
+  lang_hooks.types.register_builtin_type (aarch64_mfp8_type_node, "__mfp8");
+  aarch64_mfp8_ptr_type_node = build_pointer_type (aarch64_mfp8_type_node);
+}
+
 /* Initialize the backend types that support the user-visible __fp16
    type, also initialize a pointer to that type, to be used when
    forming HFAs.  */
@@ -2125,6 +2143,8 @@  aarch64_general_init_builtins (void)
 {
   aarch64_init_fpsr_fpcr_builtins ();
 
+  aarch64_init_fp8_types ();
+
   aarch64_init_fp16_types ();
 
   aarch64_init_bf16_types ();
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 92763d403c7..0ac00027502 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -22467,6 +22467,10 @@  aarch64_mangle_type (const_tree type)
 	return "Dh";
     }
 
+  /* Modal 8 bit floating point types.  */
+  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node)
+    return "u6__mfp8";
+
   /* Mangle AArch64-specific internal types.  TYPE_NAME is non-NULL_TREE for
      builtin types.  */
   if (TYPE_NAME (type) != NULL)
@@ -22481,6 +22485,29 @@  aarch64_mangle_type (const_tree type)
   return NULL;
 }
 
+/* Implement TARGET_INVALID_CONVERSION.  */
+
+static const char *
+aarch64_invalid_conversion (const_tree fromtype, const_tree totype)
+{
+  /* Do not allow conversions to/from FP8. But do allow conversions between
+     volatile and const variants of __mfp8. */
+  bool fromtype_is_fp8
+      = (TYPE_MAIN_VARIANT (fromtype) == aarch64_mfp8_type_node);
+  bool totype_is_fp8 = (TYPE_MAIN_VARIANT (totype) == aarch64_mfp8_type_node);
+
+  if (fromtype_is_fp8 && totype_is_fp8)
+    return NULL;
+
+  if (fromtype_is_fp8)
+    return N_ ("invalid conversion from type %<mfloat8_t%>");
+  if (totype_is_fp8)
+    return N_ ("invalid conversion to type %<mfloat8_t%>");
+
+  /* Conversion allowed.  */
+  return NULL;
+}
+
 /* Implement TARGET_VERIFY_TYPE_CONTEXT.  */
 
 static bool
@@ -29031,8 +29058,20 @@  aarch64_stack_protect_guard (void)
   return NULL_TREE;
 }
 
-/* Return the diagnostic message string if the binary operation OP is
-   not permitted on TYPE1 and TYPE2, NULL otherwise.  */
+/* Implement TARGET_INVALID_UNARY_OP.  */
+
+static const char *
+aarch64_invalid_unary_op (int op, const_tree type)
+{
+  /* Reject all single-operand operations on __mfp8 except for &.  */
+  if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node && op != ADDR_EXPR)
+    return N_ ("operation not permitted on type %<mfloat8_t%>");
+
+  /* Operation allowed.  */
+  return NULL;
+}
+
+/* Implement TARGET_INVALID_BINARY_OP.  */
 
 static const char *
 aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
@@ -29046,6 +29085,11 @@  aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
 	  != aarch64_sve::builtin_type_p (type2)))
     return N_("cannot combine GNU and SVE vectors in a binary operation");
 
+  /* Reject all 2-operand operations on __mfp8.  */
+  if (TYPE_MAIN_VARIANT (type1) == aarch64_mfp8_type_node
+      || TYPE_MAIN_VARIANT (type2) == aarch64_mfp8_type_node)
+    return N_ ("operation not permitted on type %<mfloat8_t%>");
+
   /* Operation allowed.  */
   return NULL;
 }
@@ -30763,6 +30807,12 @@  aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE aarch64_mangle_type
 
+#undef TARGET_INVALID_CONVERSION
+#define TARGET_INVALID_CONVERSION aarch64_invalid_conversion
+
+#undef TARGET_INVALID_UNARY_OP
+#define TARGET_INVALID_UNARY_OP aarch64_invalid_unary_op
+
 #undef TARGET_INVALID_BINARY_OP
 #define TARGET_INVALID_BINARY_OP aarch64_invalid_binary_op
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 2dfb999bea5..7ef82ce3587 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -1447,6 +1447,11 @@  extern const char *aarch64_rewrite_mcpu (int argc, const char **argv);
 
 #define ASM_OUTPUT_POOL_EPILOGUE  aarch64_asm_output_pool_epilogue
 
+/* This type is the user-visible __mfp8, and a pointer to that type.  We
+   need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
+extern GTY(()) tree aarch64_mfp8_type_node;
+extern GTY(()) tree aarch64_mfp8_ptr_type_node;
+
 /* This type is the user-visible __fp16, and a pointer to that type.  We
    need it in many places in the backend.  Defined in aarch64-builtins.cc.  */
 extern GTY(()) tree aarch64_fp16_type_node;
diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
index e376685489d..0092314cf75 100644
--- a/gcc/config/aarch64/arm_neon.h
+++ b/gcc/config/aarch64/arm_neon.h
@@ -72,6 +72,8 @@  typedef __Poly16_t poly16_t;
 typedef __Poly64_t poly64_t;
 typedef __Poly128_t poly128_t;
 
+typedef __mfp8 mfloat8_t;
+
 typedef __fp16 float16_t;
 typedef float float32_t;
 typedef double float64_t;
diff --git a/gcc/config/aarch64/arm_sve.h b/gcc/config/aarch64/arm_sve.h
index aa0bd9909f9..dbc61650df2 100644
--- a/gcc/config/aarch64/arm_sve.h
+++ b/gcc/config/aarch64/arm_sve.h
@@ -29,6 +29,8 @@ 
 #include <arm_private_fp8.h>
 #include <arm_bf16.h>
 
+typedef __mfp8 mfloat8_t;
+
 typedef __fp16 float16_t;
 typedef float float32_t;
 typedef double float64_t;
diff --git a/gcc/testsuite/g++.target/aarch64/fp8_mangling.C b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
new file mode 100644
index 00000000000..1dfcaa71f15
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/fp8_mangling.C
@@ -0,0 +1,44 @@ 
+/* Test that mfloat8_t mangles differently from uint8_t  */
+/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
+
+int
+foo (__mfp8)
+{
+  return 1;
+}
+
+int
+foo (unsigned char)
+{
+  return 2;
+}
+
+int
+bar (__mfp8 x)
+{
+  return foo (x);
+}
+/* { dg-final { scan-assembler-times "\n_Z3fooh:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foou6__mfp8:\n" 1 } } */
+
+constexpr __mfp8 cfp8{};
+
+constexpr int
+fooc (unsigned char)
+{
+  return 3;
+}
+
+constexpr int
+fooc (__mfp8)
+{
+  return 4;
+}
+
+constexpr int
+barc (__mfp8 x)
+{
+  return fooc (x);
+}
+
+static_assert (barc (cfp8) == 4, "constexpr selects incorrect overload");
diff --git a/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
new file mode 100644
index 00000000000..61557c95663
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/fp8_scalar_typecheck_2.C
@@ -0,0 +1,381 @@ 
+/* Test that mfloat8_t is only usable with intrinsics, thus not convertible.  */
+/* { dg-do assemble } */
+/* { dg-options "-O1 -march=armv9.4-a+fp8 -Wno-narrowing" } */
+
+#include <arm_neon.h>
+#include <stdint.h>
+#include <type_traits>
+
+mfloat8_t glob_fp8;
+
+int is_an_int;
+uint8_t is_a_uint8;
+int8_t is_an_int8;
+short is_a_short_int;
+float is_a_float;
+double is_a_double;
+
+uint8_t *uint8_ptr;
+
+mfloat8_t
+invalid_from_fp8 (uint16_t __a)
+{
+  mfloat8_t b = __a; /* { dg-error "invalid conversion to type 'mfloat8_t'" } */
+  return b;
+}
+
+uint16_t
+invalid_to_fp8 (mfloat8_t __a)
+{
+  uint16_t b = __a; /*{ dg-error "invalid conversion from type 'mfloat8_t'" } */
+  return b;
+}
+
+mfloat8_t
+foo1 (void)
+{
+  return (mfloat8_t)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+}
+
+mfloat8_t
+foo2 (void)
+{
+  return (mfloat8_t)(short)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+}
+
+mfloat8_t
+footest (mfloat8_t scalar0)
+{
+
+  /* Initialisation  */
+
+  mfloat8_t scalar1_1;
+  mfloat8_t scalar1_2 = glob_fp8;
+  mfloat8_t scalar1_3
+      = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_4
+      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_5
+      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_6
+      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_8
+      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_9 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_10
+      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_11
+      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  int initi_1_1
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  float initi_1_2
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  short initi_1_4
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  double initi_1_5
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  uint8_t initi_1_6
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  int8_t initi_1_7
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  mfloat8_t scalar2_1 = {};
+  mfloat8_t scalar2_2 = { glob_fp8 };
+  mfloat8_t scalar2_3
+      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_4
+      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_5 = {
+    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  mfloat8_t scalar2_6 = {
+    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  mfloat8_t scalar2_8 = {
+    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  mfloat8_t scalar2_9 = {
+    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  mfloat8_t scalar2_10 = {
+    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  mfloat8_t scalar2_11 = {
+    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+
+  int initi_2_1 = {
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  float initi_2_2 = {
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  short initi_2_4 = {
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  double initi_2_5 = {
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  uint8_t initi_2_6 = {
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  int8_t initi_2_7 = {
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+
+  /* Assignments.  */
+
+  glob_fp8 = glob_fp8;
+  glob_fp8 = 0;	  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  is_an_int
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_float
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_double
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_short_int
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_uint8
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_an_int8
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Casting.  */
+
+  (void)glob_fp8;
+  (mfloat8_t) glob_fp8;
+
+  (int)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (float)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (double)
+      glob_fp8;	   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (short)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (uint8_t)
+      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (int8_t)
+      glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  (mfloat8_t)
+      is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t)
+      is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t)
+      is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t) is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t)
+      is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t)
+      is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  /* Compound literals.  */
+
+  (mfloat8_t){};
+  (mfloat8_t){ glob_fp8 };
+  (mfloat8_t){ 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){
+    0.1 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  }; 
+  (mfloat8_t){
+    is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  (mfloat8_t){
+    is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  (mfloat8_t){
+    is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  (mfloat8_t){
+    is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  (mfloat8_t){
+    is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+  (mfloat8_t){
+    is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  };
+
+  (int){
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  (float){
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  (double){
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  (short){
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  (uint8_t){
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+  (int8_t){
+    glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  };
+
+  /* Arrays and Structs.  */
+
+  typedef mfloat8_t array_type[2];
+  extern mfloat8_t extern_array[];
+
+  mfloat8_t array[2];
+  mfloat8_t zero_length_array[0];
+  mfloat8_t empty_init_array[] = {};
+  typedef mfloat8_t some_other_type[is_an_int];
+
+  struct struct1
+  {
+    mfloat8_t a;
+  };
+
+  union union1
+  {
+    mfloat8_t a;
+  };
+
+  /* Addressing and dereferencing.  */
+
+  mfloat8_t *fp8_ptr = &scalar0;
+  scalar0 = *fp8_ptr;
+
+  /* Pointer assignment.  */
+
+  mfloat8_t *fp8_ptr2 = fp8_ptr;
+  mfloat8_t *fp8_ptr3 = array;
+
+  /* Pointer arithmetic.  */
+
+  ++fp8_ptr;
+  --fp8_ptr;
+  fp8_ptr++;
+  fp8_ptr--;
+  fp8_ptr += 1;
+  fp8_ptr -= 1;
+  fp8_ptr - fp8_ptr2;
+  fp8_ptr = &fp8_ptr3[0];
+  fp8_ptr = &fp8_ptr3[1];
+
+  /* Simple comparison.  */
+  scalar0
+      > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8
+      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_float
+      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 > 0;	  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 == scalar0;	  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0
+      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_an_int
+      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Pointer comparison.  */
+
+  fp8_ptr == &scalar0;
+  fp8_ptr != &scalar0;
+  fp8_ptr < &scalar0;
+  fp8_ptr <= &scalar0;
+  fp8_ptr > &scalar0;
+  fp8_ptr >= &scalar0;
+  fp8_ptr == fp8_ptr2;
+  fp8_ptr != fp8_ptr2;
+  fp8_ptr < fp8_ptr2;
+  fp8_ptr <= fp8_ptr2;
+  fp8_ptr > fp8_ptr2;
+  fp8_ptr >= fp8_ptr2;
+
+  /* Conditional expressions.  */
+
+  0 ? scalar0 : scalar0;
+  0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+    : is_a_float;
+  0 ? is_a_float
+    : scalar0;	   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? scalar0 : 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? 0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? 0.1
+    : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? scalar0  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+    : 0.1;
+  0 ? fp8_ptr : fp8_ptr2;
+  0 ? fp8_ptr : uint8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
+  0 ? uint8_ptr : fp8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */
+
+  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+      ? scalar0
+      : scalar0;
+  scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+      ? is_a_float
+      : scalar0;
+  scalar0 ? scalar0 : is_a_float;    /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Unary operators.  */
+
+  +scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  -scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  ~scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  !scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  *scalar0; /* { dg-error {invalid type argument of unary} } */
+  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  ++scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  --scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  scalar0++; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  scalar0--; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+
+  /* Binary arithmetic operations.  */
+
+  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 = glob_fp8 + *fp8_ptr;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 = glob_fp8
+	    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 = glob_fp8
+	    + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 = glob_fp8 + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 && glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  glob_fp8 || glob_fp8; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+
+  return scalar0;
+}
+
+/* Check that function decls for mfloat8_t and unsigned char differ */
+
+mfloat8_t extern_fn1(void);
+unsigned char extern_fn1(void); /* { dg-error {ambiguating new declaration of 'unsigned char extern_fn1\(\)'} } */
+
+mfloat8_t extern_fn2(void);
+uint8_t extern_fn2(void); /* { dg-error {ambiguating new declaration of 'uint8_t extern_fn2\(\)} } */
+
+unsigned char extern_fn3(void);
+mfloat8_t extern_fn3(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn3\(\)} } */
+
+uint8_t extern_fn4(void);
+mfloat8_t extern_fn4(void); /* { dg-error {ambiguating new declaration of 'mfloat8_t extern_fn4\(\)} } */
+
+/* Check that the type conforms to the contract */
+static_assert(!std::is_integral<__mfp8>(), "not integral");
+static_assert(!std::is_signed<__mfp8>(), "not signed");
+static_assert(!std::is_unsigned<__mfp8>(), "not unsigned");
diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
new file mode 100644
index 00000000000..1bc2ac26b2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c
@@ -0,0 +1,134 @@ 
+/* Test the fp8 ACLE intrinsics family.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv9.4-a+fp8" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#include <arm_neon.h>
+
+/*
+**stacktest1:
+**	sub	sp, sp, #16
+**	and	w0, w0, 255
+**	strb	w0, \[sp, 15\]
+**	ldrb	w0, \[sp, 15\]
+**	add	sp, sp, 16
+**	ret
+*/
+mfloat8_t
+stacktest1 (mfloat8_t __a)
+{
+  volatile mfloat8_t b = __a;
+  return b;
+}
+
+/*
+**fp8_mov_ww:
+**	dup	b1, v2.b\[0\]
+**	ret
+*/
+void
+fp8_mov_ww (void)
+{
+  register mfloat8_t x asm ("h2");
+  register mfloat8_t y asm ("h1");
+  asm volatile ("" : "=w"(x));
+  y = x;
+  asm volatile ("" ::"w"(y));
+}
+
+/*
+**fp8_mov_rw:
+**	dup	v1.8b, w1
+**	ret
+*/
+void
+fp8_mov_rw (void)
+{
+  register mfloat8_t x asm ("w1");
+  register mfloat8_t y asm ("h1");
+  asm volatile ("" : "=r"(x));
+  y = x;
+  asm volatile ("" ::"w"(y));
+}
+
+/*
+**fp8_mov_wr:
+**	umov	w1, v1.b\[0\]
+**	ret
+*/
+void
+fp8_mov_wr (void)
+{
+  register mfloat8_t x asm ("h1");
+  register mfloat8_t y asm ("w1");
+  asm volatile ("" : "=w"(x));
+  y = x;
+  asm volatile ("" ::"r"(y));
+}
+
+/*
+**fp8_mov_rr:
+**	mov	w1, w2
+**	ret
+*/
+void
+fp8_mov_rr (void)
+{
+  register mfloat8_t x asm ("w2");
+  register mfloat8_t y asm ("w1");
+  asm volatile ("" : "=r"(x));
+  y = x;
+  asm volatile ("" ::"r"(y));
+}
+
+/*
+**fp8_mov_rm:
+**	strb	w2, \[x0\]
+**	ret
+*/
+void
+fp8_mov_rm (mfloat8_t *ptr)
+{
+  register mfloat8_t x asm ("w2");
+  asm volatile ("" : "=r"(x));
+  *ptr = x;
+}
+
+/*
+**fp8_mov_mr:
+**	ldrb	w2, \[x0\]
+**	ret
+*/
+void
+fp8_mov_mr (mfloat8_t *ptr)
+{
+  register mfloat8_t y asm ("w2");
+  y = *ptr;
+  asm volatile ("" ::"r"(y));
+}
+
+/*
+**fp8_str_r:
+**	str	b2, \[x0\]
+**	ret
+*/
+void
+fp8_str_r (mfloat8_t *ptr)
+{
+  register mfloat8_t x asm ("v2");
+  asm volatile ("" : "=w"(x));
+  *ptr = x;
+}
+
+/*
+**fp8_ldr_r:
+**	ldr	b2, \[x0\]
+**	ret
+*/
+void
+fp8_ldr_r (mfloat8_t *ptr)
+{
+  register mfloat8_t y asm ("v2");
+  y = *ptr;
+  asm volatile ("" ::"w"(y));
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
new file mode 100644
index 00000000000..9169f40c4b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c
@@ -0,0 +1,356 @@ 
+/* Test that there is no conversion between ints and mfloat8_t.  */
+/* { dg-do assemble } */
+/* { dg-options "-O1 -march=armv9.4-a+fp8" } */
+
+#include <arm_neon.h>
+#include <stdint.h>
+
+mfloat8_t glob_fp8;
+
+int is_an_int;
+uint8_t is_a_uint8;
+int8_t is_an_int8;
+short is_a_short_int;
+float is_a_float;
+double is_a_double;
+
+uint8_t *uint8_ptr;
+
+mfloat8_t
+invalid_from_fp8 (uint16_t __a)
+{
+  mfloat8_t b = __a; // { dg-error "invalid conversion to type 'mfloat8_t'" }
+  return b;
+}
+
+uint16_t
+invalid_to_fp8 (mfloat8_t __a)
+{
+  uint16_t b = __a; // { dg-error "invalid conversion from type 'mfloat8_t'" }
+  return b;
+}
+
+mfloat8_t
+foo1 (void)
+{
+  return (mfloat8_t)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
+}
+mfloat8_t
+foo2 (void)
+{
+  return (mfloat8_t)(short)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} }
+}
+
+mfloat8_t
+footest (mfloat8_t scalar0)
+{
+
+  /* Initialisation  */
+
+  mfloat8_t scalar1_1;
+  mfloat8_t scalar1_2 = glob_fp8;
+  mfloat8_t scalar1_3 = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_4
+      = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_5
+      = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_6
+      = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_8
+      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_9
+      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_10
+      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar1_11
+      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  int initi_1_1
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  float initi_1_2
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  short initi_1_4
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  double initi_1_5
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  uint8_t initi_1_6
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  int8_t initi_1_7
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  mfloat8_t scalar2_1 = {};
+  mfloat8_t scalar2_2 = { glob_fp8 };
+  mfloat8_t scalar2_3
+      = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_4
+      = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_5
+      = { is_a_float }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_6
+      = { is_an_int }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_8 = {
+    is_a_double
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_9 = {
+    is_a_short_int
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_10
+      = { is_a_uint8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  mfloat8_t scalar2_11
+      = { is_an_int8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  int initi_2_1
+      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  float initi_2_2
+      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  short initi_2_4
+      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  double initi_2_5
+      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  uint8_t initi_2_6
+      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  int8_t initi_2_7
+      = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Assignments.  */
+
+  glob_fp8 = glob_fp8;
+  glob_fp8 = 0;	  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_a_float;	/* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8 = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  glob_fp8
+      = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  is_an_int
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_float
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_double
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_short_int
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_uint8
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_an_int8
+      = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Casting.  */
+
+  (void)glob_fp8;
+  (mfloat8_t) glob_fp8;
+
+  (int)glob_fp8;     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (float)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (double)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (short)glob_fp8;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (uint8_t)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (int8_t)glob_fp8;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  (mfloat8_t) is_an_int;	/* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t) is_a_float;	/* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t) is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t)
+      is_a_short_int;  /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t) is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t) is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  /* Compound literals.  */
+
+  (mfloat8_t){};
+  (mfloat8_t){ glob_fp8 };
+  (mfloat8_t){ 0 };   /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){ 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){
+    is_a_float
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){
+    is_an_int
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){
+    is_a_double
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){
+    is_a_short_int
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){
+    is_a_uint8
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+  (mfloat8_t){
+    is_an_int8
+  }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */
+
+  (int){ glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (float){
+    glob_fp8
+  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (double){
+    glob_fp8
+  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (short){
+    glob_fp8
+  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (uint8_t){
+    glob_fp8
+  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  (int8_t){
+    glob_fp8
+  }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Arrays and Structs.  */
+
+  typedef mfloat8_t array_type[2];
+  extern mfloat8_t extern_array[];
+
+  mfloat8_t array[2];
+  mfloat8_t zero_length_array[0];
+  mfloat8_t empty_init_array[] = {};
+  typedef mfloat8_t some_other_type[is_an_int];
+
+  struct struct1
+  {
+    mfloat8_t a;
+  };
+
+  union union1
+  {
+    mfloat8_t a;
+  };
+
+  /* Addressing and dereferencing.  */
+
+  mfloat8_t *fp8_ptr = &scalar0;
+  scalar0 = *fp8_ptr;
+
+  /* Pointer assignment.  */
+
+  mfloat8_t *fp8_ptr2 = fp8_ptr;
+  mfloat8_t *fp8_ptr3 = array;
+
+  /* Pointer arithmetic.  */
+
+  ++fp8_ptr;
+  --fp8_ptr;
+  fp8_ptr++;
+  fp8_ptr--;
+  fp8_ptr += 1;
+  fp8_ptr -= 1;
+  fp8_ptr - fp8_ptr2;
+  fp8_ptr = &fp8_ptr3[0];
+  fp8_ptr = &fp8_ptr3[1];
+
+  /* Simple comparison.  */
+  scalar0 > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8
+      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_a_float
+      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 > 0;	  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 == scalar0;	  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 > 0.1;  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0
+      > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  is_an_int
+      == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Pointer comparison.  */
+
+  fp8_ptr == &scalar0;
+  fp8_ptr != &scalar0;
+  fp8_ptr < &scalar0;
+  fp8_ptr <= &scalar0;
+  fp8_ptr > &scalar0;
+  fp8_ptr >= &scalar0;
+  fp8_ptr == fp8_ptr2;
+  fp8_ptr != fp8_ptr2;
+  fp8_ptr < fp8_ptr2;
+  fp8_ptr <= fp8_ptr2;
+  fp8_ptr > fp8_ptr2;
+  fp8_ptr >= fp8_ptr2;
+
+  /* Conditional expressions.  */
+
+  0 ? scalar0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? scalar0
+    : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? is_a_float
+    : scalar0;	     /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? scalar0 : 0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? 0 : scalar0;   /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? 0.1 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? scalar0 : 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  0 ? fp8_ptr : fp8_ptr2;
+  0 ? fp8_ptr : uint8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
+  0 ? uint8_ptr : fp8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */
+
+  scalar0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+	  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 ? is_a_float /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+	  : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 ? scalar0 : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  /* Unary operators.  */
+
+  +scalar0;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  -scalar0;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  ~scalar0;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  !scalar0;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  *scalar0;	  /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  ++scalar0;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  --scalar0;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  scalar0++;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+  scalar0--;	  /* { dg-error {operation not permitted on type 'mfloat8_t'} } */
+
+  /* Binary arithmetic operations.  */
+
+  scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 = glob_fp8 + *fp8_ptr; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0 = glob_fp8
+	    + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0
+      = glob_fp8 + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  scalar0
+      = glob_fp8
+	+ is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  glob_fp8 + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 - glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 * glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 / glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 && glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+  glob_fp8 || glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */
+
+  return scalar0;
+}
+
+/* Check that function decls for mfloat8_t and unsigned char differ */
+
+mfloat8_t extern_fn1(void);
+unsigned char extern_fn1(void); /* { dg-error {conflicting types for 'extern_fn1'; have 'unsigned char\(void\)'} } */
+
+mfloat8_t extern_fn2(void);
+uint8_t extern_fn2(void); /* { dg-error {conflicting types for 'extern_fn2'; have 'uint8_t\(void\)'} } */
+
+unsigned char extern_fn3(void);
+mfloat8_t extern_fn3(void); /* { dg-error {conflicting types for 'extern_fn3'; have 'mfloat8_t\(void\)'} } */
+
+uint8_t extern_fn4(void);
+mfloat8_t extern_fn4(void); /* { dg-error {conflicting types for 'extern_fn4'; have 'mfloat8_t\(void\)'} } */
+
+void extern_fn5(mfloat8_t);
+void extern_fn5(unsigned char); /* { dg-error {conflicting types for 'extern_fn5'; have 'void\(unsigned char\)'} } */
+
+void extern_fn6(mfloat8_t);
+void extern_fn6(uint8_t); /* { dg-error {conflicting types for 'extern_fn6'; have 'void\(uint8_t\)'} } */