On Fri, Sep 19, 2025 at 12:08 AM Peter Damianov <[email protected]> wrote:
>
> 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.
You do not add a testcase - is there any implementation that follows POSIX here?
I'll note that the C standard does not say anything about a range error and IIRC
glibc does not raise one. builtins.def is a contract between the C compiler and
it's runtime, so ideally that _ERRNO should be only active when GCC is
configured
against a runtime that does raise such an error.
Richard.
> 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
>