aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family/c-cppbuiltin.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-family/c-cppbuiltin.c')
-rw-r--r--gcc/c-family/c-cppbuiltin.c106
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__"));