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
>

Reply via email to