diff options
Diffstat (limited to 'gcc/c-family/c-cppbuiltin.c')
-rw-r--r-- | gcc/c-family/c-cppbuiltin.c | 106 |
1 files changed, 79 insertions, 27 deletions
diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index 5c88e91..e2419e8 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -728,6 +728,31 @@ cpp_atomic_builtins (cpp_reader *pfile) (have_swap[psize]? 2 : 1)); } +/* Return TRUE if the implicit excess precision in which the back-end will + compute floating-point calculations is not more than the explicit + excess precision that the front-end will apply under + -fexcess-precision=[standard|fast]. + + More intuitively, return TRUE if the excess precision proposed by the + front-end is the excess precision that will actually be used. */ + +static bool +c_cpp_flt_eval_method_iec_559 (void) +{ + enum excess_precision_type front_end_ept + = (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD + ? EXCESS_PRECISION_TYPE_STANDARD + : EXCESS_PRECISION_TYPE_FAST); + + enum flt_eval_method back_end + = targetm.c.excess_precision (EXCESS_PRECISION_TYPE_IMPLICIT); + + enum flt_eval_method front_end + = targetm.c.excess_precision (front_end_ept); + + return excess_precision_mode_join (front_end, back_end) == front_end; +} + /* Return the value for __GCC_IEC_559. */ static int cpp_iec_559_value (void) @@ -770,16 +795,17 @@ cpp_iec_559_value (void) || !dfmt->has_signed_zero) ret = 0; - /* In strict C standards conformance mode, consider unpredictable - excess precision to mean lack of IEEE 754 support. The same - applies to unpredictable contraction. For C++, and outside - strict conformance mode, do not consider these options to mean - lack of IEEE 754 support. */ + /* In strict C standards conformance mode, consider a back-end providing + more implicit excess precision than the explicit excess precision + the front-end options would require to mean a lack of IEEE 754 + support. For C++, and outside strict conformance mode, do not consider + this to mean a lack of IEEE 754 support. */ + if (flag_iso && !c_dialect_cxx () - && TARGET_FLT_EVAL_METHOD != 0 - && flag_excess_precision_cmdline != EXCESS_PRECISION_STANDARD) + && !c_cpp_flt_eval_method_iec_559 ()) ret = 0; + if (flag_iso && !c_dialect_cxx () && flag_fp_contract_mode == FP_CONTRACT_FAST) @@ -1045,9 +1071,22 @@ c_cpp_builtins (cpp_reader *pfile) builtin_define_with_int_value ("__GCC_IEC_559_COMPLEX", cpp_iec_559_complex_value ()); - /* float.h needs to know this. */ + /* float.h needs these to correctly set FLT_EVAL_METHOD + + We define two values: + + __FLT_EVAL_METHOD__ + Which, depending on the value given for + -fpermitted-flt-eval-methods, may be limited to only those values + for FLT_EVAL_METHOD defined in C99/C11. + + __FLT_EVAL_METHOD_TS_18661_3__ + Which always permits the values for FLT_EVAL_METHOD defined in + ISO/IEC TS 18661-3. */ builtin_define_with_int_value ("__FLT_EVAL_METHOD__", - TARGET_FLT_EVAL_METHOD); + c_flt_eval_method (true)); + builtin_define_with_int_value ("__FLT_EVAL_METHOD_TS_18661_3__", + c_flt_eval_method (false)); /* And decfloat.h needs this. */ builtin_define_with_int_value ("__DEC_EVAL_METHOD__", @@ -1188,25 +1227,38 @@ c_cpp_builtins (cpp_reader *pfile) gcc_assert (found_suffix); } builtin_define_with_value (macro_name, suffix, 0); + + /* The way __LIBGCC_*_EXCESS_PRECISION__ is used is about + eliminating excess precision from results assigned to + variables - meaning it should be about the implicit excess + precision only. */ bool excess_precision = false; - if (TARGET_FLT_EVAL_METHOD != 0 - && mode != TYPE_MODE (long_double_type_node) - && (mode == TYPE_MODE (float_type_node) - || mode == TYPE_MODE (double_type_node))) - switch (TARGET_FLT_EVAL_METHOD) - { - case -1: - case 2: - excess_precision = true; - break; - - case 1: - excess_precision = mode == TYPE_MODE (float_type_node); - break; - - default: - gcc_unreachable (); - } + machine_mode float16_type_mode = (float16_type_node + ? TYPE_MODE (float16_type_node) + : VOIDmode); + switch (targetm.c.excess_precision + (EXCESS_PRECISION_TYPE_IMPLICIT)) + { + case FLT_EVAL_METHOD_UNPREDICTABLE: + case FLT_EVAL_METHOD_PROMOTE_TO_LONG_DOUBLE: + excess_precision = (mode == float16_type_mode + || mode == TYPE_MODE (float_type_node) + || mode == TYPE_MODE (double_type_node)); + break; + + case FLT_EVAL_METHOD_PROMOTE_TO_DOUBLE: + excess_precision = (mode == float16_type_mode + || mode == TYPE_MODE (float_type_node)); + break; + case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT: + excess_precision = mode == float16_type_mode; + break; + case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16: + excess_precision = false; + break; + default: + gcc_unreachable (); + } macro_name = (char *) alloca (strlen (name) + sizeof ("__LIBGCC__EXCESS_" "PRECISION__")); |