POSIX says that sin and cos should set errno to EDOM when infinity is passed to
them. Make sure this is accounted for in builtins.def.

When sin/cos are called with values that set errno (like INFINITY), GCC was
incorrectly optimizing the code by assuming these functions never modify errno.
This caused incorrect behavior at -O2 where errno reads could be moved relative
to the sin/cos calls.

pass_cse_sincos also needs to be disabled when errno matters.
GCC internally optimizes separate sin() and cos() calls to a call to
the cexpi builtin, and then that builtin "evaluates" to sincos later (for
targets which have it), otherwise cexpi is used (which does not set errno).
Guarding this transformation behind -fno-math-errno works, but it
unnecessarily pessimizes code into separate sin and cos calls.

Fixing this properly might require expanding the sincos builtin to be able to 
emit
separate sin and cos calls for targets which don't have sincos, and then
optimizing to sincos for the case of -fmath-errno. For now, we preserve the
individual sin/cos calls when errno matters to maintain correct behavior.

gcc/ChangeLog:

        PR middle-end/80042
        * builtins.def (BUILT_IN_SIN, BUILT_IN_SINF, BUILT_IN_SINL): Change
        from ATTR_MATHFN_FPROUNDING to ATTR_MATHFN_FPROUNDING_ERRNO.
        (BUILT_IN_COS, BUILT_IN_COSF, BUILT_IN_COSL): Likewise.
        * tree-ssa-math-opts.cc (pass_cse_sincos::execute): Don't optimize
        sin/cos to cexpi when flag_errno_math is enabled, since cexpi
        doesn't set errno.
---
 gcc/builtins.def          | 16 ++++++++--------
 gcc/tree-ssa-math-opts.cc |  5 +++++
 2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/gcc/builtins.def b/gcc/builtins.def
index 3dc2333c6f2..cf164b92b1d 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -354,15 +354,15 @@ DEF_C99_BUILTIN        (BUILT_IN_COPYSIGNL, "copysignl", 
BT_FN_LONGDOUBLE_LONGDO
 #define COPYSIGN_TYPE(F) BT_FN_##F##_##F##_##F
 DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_COPYSIGN, "copysign", COPYSIGN_TYPE, 
ATTR_CONST_NOTHROW_LEAF_LIST)
 #undef COPYSIGN_TYPE
-DEF_LIB_BUILTIN        (BUILT_IN_COS, "cos", BT_FN_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING)
-DEF_C99_C90RES_BUILTIN (BUILT_IN_COSF, "cosf", BT_FN_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING)
+DEF_LIB_BUILTIN        (BUILT_IN_COS, "cos", BT_FN_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
+DEF_C99_C90RES_BUILTIN (BUILT_IN_COSF, "cosf", BT_FN_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_LIB_BUILTIN        (BUILT_IN_COSH, "cosh", BT_FN_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_COSHF, "coshf", BT_FN_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_COSHL, "coshl", BT_FN_LONGDOUBLE_LONGDOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 #define COSH_TYPE(F) BT_FN_##F##_##F
 DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_COSH, "cosh", COSH_TYPE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
-DEF_C99_C90RES_BUILTIN (BUILT_IN_COSL, "cosl", BT_FN_LONGDOUBLE_LONGDOUBLE, 
ATTR_MATHFN_FPROUNDING)
-DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_COS, "cos", COSH_TYPE, 
ATTR_MATHFN_FPROUNDING)
+DEF_C99_C90RES_BUILTIN (BUILT_IN_COSL, "cosl", BT_FN_LONGDOUBLE_LONGDOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
+DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_COS, "cos", COSH_TYPE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_DREM, "drem", BT_FN_DOUBLE_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_DREMF, "dremf", BT_FN_FLOAT_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_DREML, "dreml", 
BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
@@ -678,18 +678,18 @@ DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNBITD128, 
"signbitd128", BT_FN_INT_DFLOAT128
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNIFICAND, "significand", 
BT_FN_DOUBLE_DOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNIFICANDF, "significandf", 
BT_FN_FLOAT_FLOAT, ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SIGNIFICANDL, "significandl", 
BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
-DEF_LIB_BUILTIN        (BUILT_IN_SIN, "sin", BT_FN_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING)
+DEF_LIB_BUILTIN        (BUILT_IN_SIN, "sin", BT_FN_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SINCOS, "sincos", 
BT_FN_VOID_DOUBLE_DOUBLEPTR_DOUBLEPTR, ATTR_MATHFN_FPROUNDING_STORE)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SINCOSF, "sincosf", 
BT_FN_VOID_FLOAT_FLOATPTR_FLOATPTR, ATTR_MATHFN_FPROUNDING_STORE)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SINCOSL, "sincosl", 
BT_FN_VOID_LONGDOUBLE_LONGDOUBLEPTR_LONGDOUBLEPTR, ATTR_MATHFN_FPROUNDING_STORE)
-DEF_C99_C90RES_BUILTIN (BUILT_IN_SINF, "sinf", BT_FN_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING)
+DEF_C99_C90RES_BUILTIN (BUILT_IN_SINF, "sinf", BT_FN_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_LIB_BUILTIN        (BUILT_IN_SINH, "sinh", BT_FN_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_SINHF, "sinhf", BT_FN_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_SINHL, "sinhl", BT_FN_LONGDOUBLE_LONGDOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 #define SINH_TYPE(F) BT_FN_##F##_##F
 DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_SINH, "sinh", SINH_TYPE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
-DEF_C99_C90RES_BUILTIN (BUILT_IN_SINL, "sinl", BT_FN_LONGDOUBLE_LONGDOUBLE, 
ATTR_MATHFN_FPROUNDING)
-DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_SIN, "sin", SINH_TYPE, 
ATTR_MATHFN_FPROUNDING)
+DEF_C99_C90RES_BUILTIN (BUILT_IN_SINL, "sinl", BT_FN_LONGDOUBLE_LONGDOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
+DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_SIN, "sin", SINH_TYPE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 #undef SINH_TYPE
 DEF_LIB_BUILTIN        (BUILT_IN_SQRT, "sqrt", BT_FN_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_C99_C90RES_BUILTIN (BUILT_IN_SQRTF, "sqrtf", BT_FN_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index bfad4cf5c99..c736709158f 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -2239,6 +2239,11 @@ pass_cse_sincos::execute (function *fun)
                {
                CASE_CFN_COS:
                CASE_CFN_SIN:
+                 /* Don't optimize sin/cos to cexpi if errno semantics matter,
+                    since cexpi doesn't set errno like sin/cos can.  */
+                 if (flag_errno_math)
+                   break;
+                 gcc_fallthrough ();
                CASE_CFN_CEXPI:
                  arg = gimple_call_arg (stmt, 0);
                  /* Make sure we have either sincos or cexp.  */
-- 
2.39.5

Reply via email to