diff --git a/gcc/builtins.c b/gcc/builtins.c index 25e01e4092b..0b2d6bf82f9 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -2067,6 +2067,7 @@ mathfn_built_in_2 (tree type, combined_fn fn) CASE_MATHFN (REMQUO) CASE_MATHFN_FLOATN (RINT) CASE_MATHFN_FLOATN (ROUND) + CASE_MATHFN (ROUNDEVEN) CASE_MATHFN (SCALB) CASE_MATHFN (SCALBLN) CASE_MATHFN (SCALBN) diff --git a/gcc/builtins.def b/gcc/builtins.def index ef89729fd0c..e1d593a8765 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -542,6 +542,9 @@ DEF_C99_BUILTIN (BUILT_IN_RINTL, "rintl", BT_FN_LONGDOUBLE_LONGDOUBLE, AT #define RINT_TYPE(F) BT_FN_##F##_##F DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_RINT, "rint", RINT_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST) #undef RINT_TYPE +DEF_EXT_LIB_BUILTIN (BUILT_IN_ROUNDEVEN, "roundeven", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_EXT_LIB_BUILTIN (BUILT_IN_ROUNDEVENF, "roundevenf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_EXT_LIB_BUILTIN (BUILT_IN_ROUNDEVENL, "roundevenl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_ROUND, "round", BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_ROUNDF, "roundf", BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST) DEF_C99_BUILTIN (BUILT_IN_ROUNDL, "roundl", BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST) diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c index 06a420601c0..7eafd91e9a2 100644 --- a/gcc/fold-const-call.c +++ b/gcc/fold-const-call.c @@ -792,6 +792,14 @@ fold_const_call_ss (real_value *result, combined_fn fn, } return false; + case CFN_BUILT_IN_ROUNDEVEN: + if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math) + { + real_roundeven (result, format, arg); + return true; + } + return false; + CASE_CFN_LOGB: return fold_const_logb (result, arg, format); @@ -854,6 +862,9 @@ fold_const_call_ss (wide_int *result, combined_fn fn, return fold_const_conversion (result, real_round, arg, precision, format); + case CFN_BUILT_IN_ROUNDEVEN: + return fold_const_conversion (result, real_roundeven, arg, precision, format); + CASE_CFN_IRINT: CASE_CFN_LRINT: CASE_CFN_LLRINT: diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 59cedeafd71..30c409e95bf 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -329,6 +329,7 @@ negate_mathfn_p (combined_fn fn) CASE_CFN_LLROUND: CASE_CFN_LROUND: CASE_CFN_ROUND: + CASE_CFN_ROUNDEVEN: CASE_CFN_SIN: CASE_CFN_SINH: CASE_CFN_TAN: @@ -13060,6 +13061,8 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1, CASE_CFN_RINT_FN: CASE_CFN_ROUND: CASE_CFN_ROUND_FN: + CASE_CFN_ROUNDEVEN: + CASE_CFN_ROUNDEVEN_FN: CASE_CFN_SCALB: CASE_CFN_SCALBLN: CASE_CFN_SCALBN: @@ -13583,6 +13586,8 @@ integer_valued_real_call_p (combined_fn fn, tree arg0, tree arg1, int depth) CASE_CFN_RINT_FN: CASE_CFN_ROUND: CASE_CFN_ROUND_FN: + CASE_CFN_ROUNDEVEN: + CASE_CFN_ROUNDEVEN_FN: CASE_CFN_TRUNC: CASE_CFN_TRUNC_FN: return true; diff --git a/gcc/real.c b/gcc/real.c index f822ae82d61..087478841e5 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -5010,6 +5010,22 @@ real_round (REAL_VALUE_TYPE *r, format_helper fmt, real_convert (r, fmt, r); } +/* Round X to nearest even integer towards zero. */ + +void +real_roundeven (REAL_VALUE_TYPE *r, format_helper fmt, + const REAL_VALUE_TYPE *x) +{ + REAL_VALUE_TYPE t; + + do_fix_trunc (&t, x); + HOST_WIDE_INT i = real_to_integer (&t); + if(i % 2) + do_add (r, &t, &dconstm1, 0); + else + *r = t; +} + /* Set the sign of R to the sign of X. */ void diff --git a/gcc/real.h b/gcc/real.h index 0ce42565708..10898eae79e 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -499,6 +499,8 @@ extern void real_ceil (REAL_VALUE_TYPE *, format_helper, const REAL_VALUE_TYPE *); extern void real_round (REAL_VALUE_TYPE *, format_helper, const REAL_VALUE_TYPE *); +extern void real_roundeven (REAL_VALUE_TYPE *, format_helper, + const REAL_VALUE_TYPE *); /* Set the sign of R to the sign of X. */ extern void real_copysign (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);