@@ -735,10 +735,13 @@ cpp_iec_559_value (void)
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. */
+ lack of IEEE 754 support. FLT_EVAL_METHOD_PROMOTE_TO_FLOAT and
+ FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 both give predictable excess
+ precision. */
if (flag_iso
&& !c_dialect_cxx ()
- && TARGET_FLT_EVAL_METHOD != 0
+ && TARGET_FLT_EVAL_METHOD != FLT_EVAL_METHOD_PROMOTE_TO_FLOAT
+ && TARGET_FLT_EVAL_METHOD != FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16
&& flag_excess_precision_cmdline != EXCESS_PRECISION_STANDARD)
ret = 0;
if (flag_iso
@@ -1118,24 +1121,28 @@ c_cpp_builtins (cpp_reader *pfile)
}
builtin_define_with_value (macro_name, suffix, 0);
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 = (FLOATN_TYPE_NODE (0)
+ ? TYPE_MODE (FLOATN_TYPE_NODE (0))
+ : VOIDmode);
+ switch (TARGET_FLT_EVAL_METHOD)
+ {
+ 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;
+ default:
+ gcc_unreachable ();
+ }
macro_name = (char *) alloca (strlen (name)
+ sizeof ("__LIBGCC__EXCESS_"
"PRECISION__"));
@@ -158,6 +158,16 @@ enum excess_precision
EXCESS_PRECISION_STANDARD
};
+/* The possible values for FLT_EVAL_METHOD. */
+enum flt_eval_method
+{
+ FLT_EVAL_METHOD_UNPREDICTABLE = -1,
+ FLT_EVAL_METHOD_PROMOTE_TO_FLOAT = 0,
+ FLT_EVAL_METHOD_PROMOTE_TO_DOUBLE = 1,
+ FLT_EVAL_METHOD_PROMOTE_TO_LONG_DOUBLE = 2,
+ FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 = 16
+};
+
/* Type of stack check. */
enum stack_check_type
{
@@ -1700,15 +1700,23 @@ init_excess_precision (void)
int flt_eval_method = TARGET_FLT_EVAL_METHOD;
switch (flt_eval_method)
{
- case -1:
- case 0:
- /* Either the target acts unpredictably (-1) or has all the
- operations required not to have excess precision (0). */
+ case FLT_EVAL_METHOD_UNPREDICTABLE:
+ case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16:
+ /* Either the target acts unpredictably (-1) or has the required
+ operations for any type we support. */
flag_excess_precision = EXCESS_PRECISION_FAST;
break;
- case 1:
- case 2:
- /* In these cases, predictable excess precision makes
+ case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT:
+ /* Most targets will be in this case (FLT_EVAL_METHOD = 0).
+ If the target supports _Float16, we need to predictably
+ calculate it in the precision of float, otherwise, we can
+ use EXCESS_PRECISION_FAST. */
+ if (targetm.floatn_mode (16, false) == VOIDmode)
+ flag_excess_precision = EXCESS_PRECISION_FAST;
+ break;
+ case FLT_EVAL_METHOD_PROMOTE_TO_DOUBLE:
+ case FLT_EVAL_METHOD_PROMOTE_TO_LONG_DOUBLE:
+ /* In these cases, predictable excess precision always makes
sense. */
break;
default:
@@ -8836,50 +8836,93 @@ build_complex_type (tree component_type)
tree
excess_precision_type (tree type)
{
+ int flt_eval_method = TARGET_FLT_EVAL_METHOD;
+ machine_mode float16_type_mode = (float16_type_node
+ ? TYPE_MODE (float16_type_node)
+ : VOIDmode);
+ machine_mode float_type_mode = TYPE_MODE (float_type_node);
+ machine_mode double_type_mode = TYPE_MODE (float_type_node);
if (flag_excess_precision != EXCESS_PRECISION_FAST)
{
- int flt_eval_method = TARGET_FLT_EVAL_METHOD;
switch (TREE_CODE (type))
{
case REAL_TYPE:
- switch (flt_eval_method)
{
- case 1:
- if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
- return double_type_node;
- break;
- case 2:
- if (TYPE_MODE (type) == TYPE_MODE (float_type_node)
- || TYPE_MODE (type) == TYPE_MODE (double_type_node))
- return long_double_type_node;
+ machine_mode type_mode = TYPE_MODE (type);
+ switch (flt_eval_method)
+ {
+ case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT:
+ if (type_mode == float16_type_mode)
+ return float_type_node;
+ break;
+ case FLT_EVAL_METHOD_PROMOTE_TO_DOUBLE:
+ if (type_mode == float16_type_mode
+ || type_mode == float_type_mode)
+ return double_type_node;
+ break;
+ case FLT_EVAL_METHOD_PROMOTE_TO_LONG_DOUBLE:
+ if (type_mode == float16_type_mode
+ || type_mode == float_type_mode
+ || type_mode == double_type_mode)
+ return long_double_type_node;
+ break;
+ default:
+ gcc_unreachable ();
+ }
break;
- default:
- gcc_unreachable ();
}
- break;
case COMPLEX_TYPE:
- if (TREE_CODE (TREE_TYPE (type)) != REAL_TYPE)
- return NULL_TREE;
- switch (flt_eval_method)
{
- case 1:
- if (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (float_type_node))
- return complex_double_type_node;
- break;
- case 2:
- if (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (float_type_node)
- || (TYPE_MODE (TREE_TYPE (type))
- == TYPE_MODE (double_type_node)))
- return complex_long_double_type_node;
+ if (TREE_CODE (TREE_TYPE (type)) != REAL_TYPE)
+ return NULL_TREE;
+ machine_mode type_mode = TYPE_MODE (TREE_TYPE (type));
+ switch (flt_eval_method)
+ {
+ case FLT_EVAL_METHOD_PROMOTE_TO_FLOAT:
+ if (type_mode == float16_type_mode)
+ return complex_float_type_node;
+ break;
+ case FLT_EVAL_METHOD_PROMOTE_TO_DOUBLE:
+ if (type_mode == float16_type_mode
+ || type_mode == float_type_mode)
+ return complex_double_type_node;
+ break;
+ case FLT_EVAL_METHOD_PROMOTE_TO_LONG_DOUBLE:
+ if (type_mode == float16_type_mode
+ || type_mode == float_type_mode
+ || type_mode == double_type_mode)
+ return complex_long_double_type_node;
+ break;
+ default:
+ gcc_unreachable ();
+ }
break;
- default:
- gcc_unreachable ();
}
- break;
default:
break;
}
}
+ else
+ {
+ /* A special case for EXCESS_PRECISION_FAST if we need to calculate in
+ at-least-float precision. If this is a _Float16
+ type, and we would calculate it in float precision
+ (FLT_EVAL_METHOD == FLT_EVAL_METHOD_AT_LEAST_FLOAT), then the target
+ probably doesn't have HFmode operations. We are therefore
+ likely to generate better code by promoting once here. If we
+ don't, we'll promote before arithmetic operations so we can use
+ their SFmode counterparts. */
+ if (flt_eval_method == FLT_EVAL_METHOD_PROMOTE_TO_FLOAT
+ && float16_type_node)
+ {
+ if (TREE_CODE (type) == REAL_TYPE
+ && TYPE_MODE (type) == float16_type_mode)
+ return float_type_node;
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ && TYPE_MODE (TREE_TYPE (type)) == float16_type_mode)
+ return complex_float_type_node;
+ }
+ }
return NULL_TREE;
}