From 9a19fa8b616f83474c35cc5b34a3865073ced829 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 18 Apr 2023 14:53:04 +0800 Subject: [PATCH] Support type _Float16/__bf16 independent of SSE2. Enable _Float16 and __bf16 all the time but issue errors when the types are used in conversion, unary operation, binary operation, parameter passing or value return when TARGET_SSE2 is not available. Also undef macros which are used by libgcc/libstdc++ to check the backend support of the _Float16/__bf16 types when TARGET_SSE2 is not available. gcc/ChangeLog: PR target/109504 * config/i386/i386-builtins.cc (ix86_register_float16_builtin_type): Remove TARGET_SSE2. (ix86_register_bf16_builtin_type): Ditto. * config/i386/i386-c.cc (ix86_target_macros): When TARGET_SSE2 isn't available, undef the macros which are used to check the backend support of the _Float16/__bf16 types when building libstdc++ and libgcc. * config/i386/i386.cc (construct_container): Issue errors for HFmode/BFmode when TARGET_SSE2 is not available. (function_value_32): Ditto. (ix86_scalar_mode_supported_p): Remove TARGET_SSE2 for HFmode/BFmode. (ix86_libgcc_floating_mode_supported_p): Ditto. (ix86_emit_support_tinfos): Adjust codes. (ix86_invalid_conversion): Return diagnostic message string when there's conversion from/to BF/HFmode w/o TARGET_SSE2. (ix86_invalid_unary_op): New function. (ix86_invalid_binary_op): Ditto. (TARGET_INVALID_UNARY_OP): Define. (TARGET_INVALID_BINARY_OP): Define. * config/i386/immintrin.h [__SSE2__]: Remove for fp16/bf16 related instrinsics header files. * config/i386/i386.h (VALID_SSE2_TYPE_MODE): New macro. gcc/testsuite/ChangeLog: * gcc.target/i386/pr109504.c: New test. * gcc.target/i386/sse2-bfloat16-1.c: Adjust error info. * gcc.target/i386/sse2-float16-1.c: Ditto. * gcc.target/i386/sse2-float16-4.c: New test. * gcc.target/i386/sse2-float16-5.c: New test. * g++.target/i386/float16-1.C: Adjust error info. libgcc/ChangeLog: * config/i386/t-softfp: Add -msse2 to libbid HFtype related files. --- gcc/config/i386/i386-builtins.cc | 4 +- gcc/config/i386/i386-c.cc | 15 +++ gcc/config/i386/i386.cc | 125 ++++++++++++++++-- gcc/config/i386/i386.h | 4 + gcc/config/i386/immintrin.h | 4 - gcc/testsuite/g++.target/i386/float16-1.C | 8 +- gcc/testsuite/gcc.target/i386/pr109504.c | 6 + .../gcc.target/i386/sse2-bfloat16-1.c | 8 +- .../gcc.target/i386/sse2-float16-1.c | 8 +- .../gcc.target/i386/sse2-float16-4.c | 25 ++++ .../gcc.target/i386/sse2-float16-5.c | 24 ++++ libgcc/config/i386/t-softfp | 7 + 12 files changed, 206 insertions(+), 32 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr109504.c create mode 100644 gcc/testsuite/gcc.target/i386/sse2-float16-4.c create mode 100644 gcc/testsuite/gcc.target/i386/sse2-float16-5.c diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc index e436ca4e5b15..6c9033485482 100644 --- a/gcc/config/i386/i386-builtins.cc +++ b/gcc/config/i386/i386-builtins.cc @@ -1376,7 +1376,7 @@ ix86_register_float16_builtin_type (void) else ix86_float16_type_node = float16_type_node; - if (!maybe_get_identifier ("_Float16") && TARGET_SSE2) + if (!maybe_get_identifier ("_Float16")) lang_hooks.types.register_builtin_type (ix86_float16_type_node, "_Float16"); } @@ -1394,7 +1394,7 @@ ix86_register_bf16_builtin_type (void) else ix86_bf16_type_node = bfloat16_type_node; - if (!maybe_get_identifier ("__bf16") && TARGET_SSE2) + if (!maybe_get_identifier ("__bf16")) lang_hooks.types.register_builtin_type (ix86_bf16_type_node, "__bf16"); } diff --git a/gcc/config/i386/i386-c.cc b/gcc/config/i386/i386-c.cc index 808fc42a0ae2..257950582c28 100644 --- a/gcc/config/i386/i386-c.cc +++ b/gcc/config/i386/i386-c.cc @@ -832,6 +832,21 @@ ix86_target_macros (void) if (!TARGET_80387) cpp_define (parse_in, "_SOFT_FLOAT"); + /* HFmode/BFmode is supported without depending any isa + in scalar_mode_supported_p and libgcc_floating_mode_supported_p, + but according to psABI, they're really supported w/ SSE2 and above. + Since libstdc++ uses __STDCPP_FLOAT16_T__ and __STDCPP_BFLOAT16_T__ + for backend support of the types, undef the macros to avoid + build failure, see PR109504. */ + if (!TARGET_SSE2) + { + if (c_dialect_cxx () && cxx_dialect > cxx20) + { + cpp_undef (parse_in, "__STDCPP_FLOAT16_T__"); + cpp_undef (parse_in, "__STDCPP_BFLOAT16_T__"); + } + } + if (TARGET_LONG_DOUBLE_64) cpp_define (parse_in, "__LONG_DOUBLE_64__"); diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index f0d6167e667f..eabc70011ea5 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -2661,7 +2661,8 @@ construct_container (machine_mode mode, machine_mode orig_mode, /* We allowed the user to turn off SSE for kernel mode. Don't crash if some less clueful developer tries to use floating-point anyway. */ - if (needed_sseregs && !TARGET_SSE) + if (needed_sseregs + && (!TARGET_SSE || (VALID_SSE2_TYPE_MODE (mode) && !TARGET_SSE2))) { /* Return early if we shouldn't raise an error for invalid calls. */ @@ -2671,13 +2672,19 @@ construct_container (machine_mode mode, machine_mode orig_mode, { if (!issued_sse_ret_error) { - error ("SSE register return with SSE disabled"); + if (VALID_SSE2_TYPE_MODE (mode)) + error ("SSE register return with SSE2 disabled"); + else + error ("SSE register return with SSE disabled"); issued_sse_ret_error = true; } } else if (!issued_sse_arg_error) { - error ("SSE register argument with SSE disabled"); + if (VALID_SSE2_TYPE_MODE (mode)) + error ("SSE register argument with SSE2 disabled"); + else + error ("SSE register argument with SSE disabled"); issued_sse_arg_error = true; } return NULL; @@ -4032,13 +4039,26 @@ function_value_32 (machine_mode orig_mode, machine_mode mode, /* Return __bf16/ _Float16/_Complex _Foat16 by sse register. */ if (mode == HFmode || mode == BFmode) - regno = FIRST_SSE_REG; + { + if (!TARGET_SSE2) + { + error ("SSE register return with SSE2 disabled"); + regno = AX_REG; + } + else + regno = FIRST_SSE_REG; + } + if (mode == HCmode) { + if (!TARGET_SSE2) + error ("SSE register return with SSE2 disabled"); + rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc(1)); XVECEXP (ret, 0, 0) = gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (SImode, FIRST_SSE_REG), + gen_rtx_REG (SImode, + TARGET_SSE2 ? FIRST_SSE_REG : AX_REG), GEN_INT (0)); return ret; } @@ -22786,14 +22806,35 @@ x86_emit_floatuns (rtx operands[2]) } /* Return the diagnostic message string if conversion from FROMTYPE to - TOTYPE is not allowed, NULL otherwise. - Currently it's used to warn for silent implicit conversion between __bf16 - and short, since __bfloat16 is refined as real __bf16 instead of short - since GCC13. */ + TOTYPE is not allowed, NULL otherwise. */ static const char * ix86_invalid_conversion (const_tree fromtype, const_tree totype) { + machine_mode from_mode = element_mode (fromtype); + machine_mode to_mode = element_mode (totype); + + if (!TARGET_SSE2 && from_mode != to_mode) + { + /* Do no allow conversions to/from BFmode/HFmode scalar types + when TARGET_SSE2 is not available. */ + if (from_mode == BFmode) + return N_("invalid conversion from type %<__bf16%> " + "without option %<-msse2%>"); + if (from_mode == HFmode) + return N_("invalid conversion from type %<_Float16%> " + "without option %<-msse2%>"); + if (to_mode == BFmode) + return N_("invalid conversion to type %<__bf16%> " + "without option %<-msse2%>"); + if (to_mode == HFmode) + return N_("invalid conversion to type %<_Float16%> " + "without option %<-msse2%>"); + } + + /* Warn for silent implicit conversion between __bf16 and short, + since __bfloat16 is refined as real __bf16 instead of short + since GCC13. */ if (element_mode (fromtype) != element_mode (totype) && (TARGET_AVX512BF16 || TARGET_AVXNECONVERT)) { @@ -22813,6 +22854,55 @@ ix86_invalid_conversion (const_tree fromtype, const_tree totype) return NULL; } +/* Return the diagnostic message string if the unary operation OP is + not permitted on TYPE, NULL otherwise. */ + +static const char * +ix86_invalid_unary_op (int op, const_tree type) +{ + machine_mode mmode = element_mode (type); + /* Reject all single-operand operations on BFmode/HFmode except for & + when TARGET_SSE2 is not available. */ + if (!TARGET_SSE2 && op != ADDR_EXPR) + { + if (mmode == BFmode) + return N_("operation not permitted on type %<__bf16%> " + "without option %<-msse2%>"); + if (mmode == HFmode) + return N_("operation not permitted on type %<_Float16%> " + "without option %<-msse2%>"); + } + + /* Operation allowed. */ + return NULL; +} + +/* Return the diagnostic message string if the binary operation OP is + not permitted on TYPE1 and TYPE2, NULL otherwise. */ + +static const char * +ix86_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1, + const_tree type2) +{ + machine_mode type1_mode = element_mode (type1); + machine_mode type2_mode = element_mode (type2); + /* Reject all 2-operand operations on BFmode or HFmode + when TARGET_SSE2 is not available. */ + if (!TARGET_SSE2) + { + if (type1_mode == BFmode || type2_mode == BFmode) + return N_("operation not permitted on type %<__bf16%> " + "without option %<-msse2%>"); + + if (type1_mode == HFmode || type2_mode == HFmode) + return N_("operation not permitted on type %<_Float16%> " + "without option %<-msse2%>"); + } + + /* Operation allowed. */ + return NULL; +} + /* Target hook for scalar_mode_supported_p. */ static bool @@ -22822,7 +22912,7 @@ ix86_scalar_mode_supported_p (scalar_mode mode) return default_decimal_float_supported_p (); else if (mode == TFmode) return true; - else if ((mode == HFmode || mode == BFmode) && TARGET_SSE2) + else if (mode == HFmode || mode == BFmode) return true; else return default_scalar_mode_supported_p (mode); @@ -22838,7 +22928,7 @@ ix86_libgcc_floating_mode_supported_p (scalar_float_mode mode) be defined by the C front-end for AVX512FP16 intrinsics. We will issue an error in ix86_expand_move for HFmode if AVX512FP16 isn't enabled. */ - return (((mode == HFmode || mode == BFmode) && TARGET_SSE2) + return ((mode == HFmode || mode == BFmode) ? true : default_libgcc_floating_mode_supported_p (mode)); } @@ -23168,9 +23258,10 @@ ix86_emit_support_tinfos (emit_support_tinfos_callback callback) if (!TARGET_SSE2) { - gcc_checking_assert (!float16_type_node && !bfloat16_type_node); - float16_type_node = ix86_float16_type_node; - bfloat16_type_node = ix86_bf16_type_node; + if (!float16_type_node) + float16_type_node = ix86_float16_type_node; + if (!bfloat16_type_node) + bfloat16_type_node = ix86_bf16_type_node; callback (float16_type_node); callback (bfloat16_type_node); float16_type_node = NULL_TREE; @@ -25107,6 +25198,12 @@ ix86_run_selftests (void) #undef TARGET_INVALID_CONVERSION #define TARGET_INVALID_CONVERSION ix86_invalid_conversion +#undef TARGET_INVALID_UNARY_OP +#define TARGET_INVALID_UNARY_OP ix86_invalid_unary_op + +#undef TARGET_INVALID_BINARY_OP +#define TARGET_INVALID_BINARY_OP ix86_invalid_binary_op + #undef TARGET_COMP_TYPE_ATTRIBUTES #define TARGET_COMP_TYPE_ATTRIBUTES ix86_comp_type_attributes diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index d8adfa230051..ef342fcee9b3 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1047,6 +1047,10 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #define VALID_AVX512FP16_REG_MODE(MODE) \ ((MODE) == V8HFmode || (MODE) == V16HFmode || (MODE) == V32HFmode) +#define VALID_SSE2_TYPE_MODE(MODE) \ + ((MODE) == HFmode || (MODE) == BFmode \ + || (MODE) == HCmode || (MODE) == BCmode) + #define VALID_SSE2_REG_MODE(MODE) \ ((MODE) == V16QImode || (MODE) == V8HImode || (MODE) == V2DFmode \ || (MODE) == V8HFmode || (MODE) == V4HFmode || (MODE) == V2HFmode \ diff --git a/gcc/config/i386/immintrin.h b/gcc/config/i386/immintrin.h index ea14354efbcb..29b4dbbda249 100644 --- a/gcc/config/i386/immintrin.h +++ b/gcc/config/i386/immintrin.h @@ -100,11 +100,9 @@ #include -#ifdef __SSE2__ #include #include -#endif #include @@ -126,13 +124,11 @@ #include -#ifdef __SSE2__ #include #include #include -#endif #include diff --git a/gcc/testsuite/g++.target/i386/float16-1.C b/gcc/testsuite/g++.target/i386/float16-1.C index f96b932b6984..938852ee9ad2 100644 --- a/gcc/testsuite/g++.target/i386/float16-1.C +++ b/gcc/testsuite/g++.target/i386/float16-1.C @@ -1,8 +1,8 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-sse2" } */ -_Float16 /* { dg-error "expected unqualified-id before '_Float16'" } */ -foo (_Float16 x) +_Float16 +foo (_Float16 x)/* { dg-error "SSE register return with SSE2 disabled" } */ { - return x; -} /* { dg-error "'_Float16' is not supported on this target" } */ + return x;/* { dg-error "SSE register return with SSE2 disabled" "" { target ia32 } } */ +} diff --git a/gcc/testsuite/gcc.target/i386/pr109504.c b/gcc/testsuite/gcc.target/i386/pr109504.c new file mode 100644 index 000000000000..fe5bcda10adb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr109504.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-sse" } */ + +#pragma GCC target("sse4.1") +#include +int main(){return 0;} diff --git a/gcc/testsuite/gcc.target/i386/sse2-bfloat16-1.c b/gcc/testsuite/gcc.target/i386/sse2-bfloat16-1.c index 612d55be826b..717055bc9ad4 100644 --- a/gcc/testsuite/gcc.target/i386/sse2-bfloat16-1.c +++ b/gcc/testsuite/gcc.target/i386/sse2-bfloat16-1.c @@ -1,8 +1,8 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-sse2" } */ -__bf16/* { dg-error "unknown type name '__bf16'" } */ -foo (__bf16 x) /* { dg-error "unknown type name '__bf16'" } */ -{ - return x; +__bf16 +foo (__bf16 x) /* { dg-error "SSE register return with SSE2 disabled" } */ +{ /* { dg-error "SSE register return with SSE2 disabled" "" { target ia32 } } */ + return x; /* { dg-error "SSE register return with SSE2 disabled" "" { target ia32} } */ } diff --git a/gcc/testsuite/gcc.target/i386/sse2-float16-1.c b/gcc/testsuite/gcc.target/i386/sse2-float16-1.c index 1b645eb499da..faf818df75fa 100644 --- a/gcc/testsuite/gcc.target/i386/sse2-float16-1.c +++ b/gcc/testsuite/gcc.target/i386/sse2-float16-1.c @@ -1,8 +1,8 @@ /* { dg-do compile } */ /* { dg-options "-O2 -mno-sse2" } */ -_Float16/* { dg-error "is not supported on this target" } */ -foo (_Float16 x) /* { dg-error "is not supported on this target" } */ -{ - return x; +_Float16 +foo (_Float16 x) /* { dg-error "SSE register return with SSE2 disabled" } */ +{ /* { dg-error "SSE register return with SSE2 disabled" "" { target ia32 } } */ + return x; /* { dg-error "SSE register return with SSE2 disabled" "" { target ia32} } */ } diff --git a/gcc/testsuite/gcc.target/i386/sse2-float16-4.c b/gcc/testsuite/gcc.target/i386/sse2-float16-4.c new file mode 100644 index 000000000000..64baf92ff568 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse2-float16-4.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-sse2" } */ + +_Float16 a; +__bf16 c; +_Complex _Float16 ac; + +void +foo (_Float16* p) +{ + a = *p; +} + +void +foo1 (__bf16 *p) +{ + c = *p; +} + + +void +foo2 (_Complex _Float16* p) +{ + ac = *p; +} diff --git a/gcc/testsuite/gcc.target/i386/sse2-float16-5.c b/gcc/testsuite/gcc.target/i386/sse2-float16-5.c new file mode 100644 index 000000000000..c3ed23b8ab3c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse2-float16-5.c @@ -0,0 +1,24 @@ +/* { dg-do compile { target ia32} } */ +/* { dg-options "-O2 -mno-sse2" } */ + +_Float16 a; +__bf16 c; +_Complex ac; +void +foo (_Float16 p) +{ + a = p; +} + +void +foo1 (__bf16 p) +{ + c = p; +} + + +void +foo2 (_Complex p) +{ + ac = p; +} diff --git a/libgcc/config/i386/t-softfp b/libgcc/config/i386/t-softfp index 69d0f8198229..80d1fac121bf 100644 --- a/libgcc/config/i386/t-softfp +++ b/libgcc/config/i386/t-softfp @@ -31,3 +31,10 @@ CFLAGS-trunchfbf2.c += -msse2 CFLAGS-eqhf2.c += -msse2 CFLAGS-_divhc3.c += -msse2 CFLAGS-_mulhc3.c += -msse2 + +CFLAGS-_hf_to_sd.c += -msse2 +CFLAGS-_hf_to_dd.c += -msse2 +CFLAGS-_hf_to_td.c += -msse2 +CFLAGS-_sd_to_hf.c += -msse2 +CFLAGS-_dd_to_hf.c += -msse2 +CFLAGS-_td_to_hf.c += -msse2 -- 2.43.5