This patch doesn't work. But the first one is okay, despite that it pessimizes 
sin and cos calls by skipping the optimization pass.

Sep 18, 2025 11:04:16 PM Peter Damianov <peter0...@disroot.org>:

> In my previous patch, I disabled pass_cse_sincos for -fmath-errno. This was
> because it was causing ICEs when trying to replace sin/cos calls, and more
> importantly, the pass was transforming sin+cos to cexpi which doesn't set
> errno like sin/cos do. The optimization is valid when either:
> 1. We don't care about errno (-fno-math-errno), or
> 2. We can use sincos() which does set errno like sin/cos do
> 
> This patch fixes the ICE and implements a different optimization strategy
> that preserves errno semantics by directly calling sincos when available,
> and only falling back to cexpi when errno doesn't matter. The ICEs are
> resolved by properly unlinking VDEFs before statement replacement.
> 
> gcc/ChangeLog:
> 
> PR tree-optimization/80042
> * tree-ssa-math-opts.cc (execute_cse_sincos_1): Optimize to sincos
> for -fmath-errno. Fix ICE with unlink_stmt_vdef before gsi_replace.
> (pass_cse_sincos::execute): Remove errno check to allow proper
> optimization in execute_cse_sincos_1.
> 
> gcc/testsuite/ChangeLog:
> 
> PR tree-optimization/80042
> * gcc.dg/pr80042.c: New test.
> ---
> gcc/testsuite/gcc.dg/pr80042.c |  71 +++++++++++++++++++++
> gcc/tree-ssa-math-opts.cc      | 110 ++++++++++++++++++++++++++-------
> 2 files changed, 159 insertions(+), 22 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/pr80042.c
> 
> diff --git a/gcc/testsuite/gcc.dg/pr80042.c b/gcc/testsuite/gcc.dg/pr80042.c
> new file mode 100644
> index 00000000000..7843604d23c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr80042.c
> @@ -0,0 +1,71 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2 -lm -fmath-errno" } */
> +
> +#include <errno.h>
> +
> +void test_double(void)
> +{
> +  double s, c;
> +
> +  errno = 0;
> +  s = __builtin_sin(__builtin_inf());
> +  if (errno != EDOM)
> +    __builtin_abort();
> +
> +  errno = 0;
> +  c = __builtin_cos(__builtin_inf());
> +  if (errno != EDOM)
> +    __builtin_abort();
> +
> +  errno = 0;
> +  __builtin_sincos(__builtin_inf(), &s, &c);
> +  if (errno != EDOM)
> +    __builtin_abort();
> +}
> +
> +void test_float(void)
> +{
> +  float s, c;
> +
> +  errno = 0;
> +  s = __builtin_sinf(__builtin_inff());
> +  if (errno != EDOM)
> +    __builtin_abort();
> +
> +  errno = 0;
> +  c = __builtin_cosf(__builtin_inff());
> +  if (errno != EDOM)
> +    __builtin_abort();
> +
> +  errno = 0;
> +  __builtin_sincosf(__builtin_inff(), &s, &c);
> +  if (errno != EDOM)
> +    __builtin_abort();
> +}
> +
> +void test_longdouble(void)
> +{
> +  long double s, c;
> +
> +  errno = 0;
> +  s = __builtin_sinl(__builtin_infl());
> +  if (errno != EDOM)
> +    __builtin_abort();
> +
> +  errno = 0;
> +  c = __builtin_cosl(__builtin_infl());
> +  if (errno != EDOM)
> +    __builtin_abort();
> +
> +  errno = 0;
> +  __builtin_sincosl(__builtin_infl(), &s, &c);
> +  if (errno != EDOM)
> +    __builtin_abort();
> +}
> +
> +int main(void)
> +{
> +  test_double();
> +  test_float();
> +  test_longdouble();
> +}
> \ No newline at end of file
> diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
> index c736709158f..4076bcf55d5 100644
> --- a/gcc/tree-ssa-math-opts.cc
> +++ b/gcc/tree-ssa-math-opts.cc
> @@ -1253,7 +1253,7 @@ execute_cse_sincos_1 (tree name)
> {
>    gimple_stmt_iterator gsi;
>    imm_use_iterator use_iter;
> -  tree fndecl, res, type = NULL_TREE;
> +  tree res, type = NULL_TREE;
>    gimple *def_stmt, *use_stmt, *stmt;
>    int seen_cos = 0, seen_sin = 0, seen_cexpi = 0;
>    auto_vec<gimple *> stmts;
> @@ -1302,27 +1302,97 @@ execute_cse_sincos_1 (tree name)
>    if (seen_cos + seen_sin + seen_cexpi <= 1)
>      return false;
> 
> -  /* Simply insert cexpi at the beginning of top_bb but not earlier than
> -     the name def statement.  */
> -  fndecl = mathfn_built_in (type, BUILT_IN_CEXPI);
> -  if (!fndecl)
> -    return false;
> -  stmt = gimple_build_call (fndecl, 1, name);
> -  res = make_temp_ssa_name (TREE_TYPE (TREE_TYPE (fndecl)), stmt, 
> "sincostmp");
> -  gimple_call_set_lhs (stmt, res);
> +  machine_mode mode = TYPE_MODE (type);
> +  tree sincos_fndecl = builtin_decl_explicit (BUILT_IN_SINCOS);
> +  bool can_use_sincos = sincos_fndecl
> +           && (optab_handler (sincos_optab, mode)
> +               != CODE_FOR_nothing
> +               || targetm.libc_has_function (function_sincos,
> +                             type));
> 
> -  def_stmt = SSA_NAME_DEF_STMT (name);
> -  if (!SSA_NAME_IS_DEFAULT_DEF (name)
> -      && gimple_code (def_stmt) != GIMPLE_PHI
> -      && gimple_bb (def_stmt) == top_bb)
> +  if (flag_errno_math && (seen_sin || seen_cos) && !can_use_sincos)
>      {
> -      gsi = gsi_for_stmt (def_stmt);
> -      gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
> +      /* We cannot rewrite sin and cos calls to cexpi if we have
> +    flag_errno_math because cexpi does not set errno.  */
> +      return false;
> +    }
> +
> +  if (can_use_sincos)
> +    {
> +      /* Generate sincos call if sincos is available.  */
> +
> +      tree complex_type = build_complex_type (type);
> +
> +      /* Create temporary variables for sin and cos results.  */
> +      tree sin_result = create_tmp_var (type, "sincos_sin");
> +      tree cos_result = create_tmp_var (type, "sincos_cos");
> +
> +      /* Create addresses to the temporary variables.  */
> +      tree sin_addr = build_fold_addr_expr (sin_result);
> +      tree cos_addr = build_fold_addr_expr (cos_result);
> +
> +      /* Generate sincos (angle, &sin_result, &cos_result) call.  */
> +      stmt = gimple_build_call (sincos_fndecl, 3, name, sin_addr, cos_addr);
> +
> +      /* Insert the sincos call.  */
> +      def_stmt = SSA_NAME_DEF_STMT (name);
> +      if (!SSA_NAME_IS_DEFAULT_DEF (name)
> +     && gimple_code (def_stmt) != GIMPLE_PHI
> +     && gimple_bb (def_stmt) == top_bb)
> +   {
> +     gsi = gsi_for_stmt (def_stmt);
> +     gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
> +   }
> +      else
> +   {
> +     gsi = gsi_after_labels (top_bb);
> +     gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
> +   }
> +
> +      /* Create SSA names for the results and load them from temporaries.  */
> +      tree sin_ssa = make_ssa_name (type);
> +      tree cos_ssa = make_ssa_name (type);
> +
> +      gimple *sin_load = gimple_build_assign (sin_ssa, sin_result);
> +      gimple *cos_load = gimple_build_assign (cos_ssa, cos_result);
> +
> +      gsi_insert_after (&gsi, sin_load, GSI_NEW_STMT);
> +      gsi_insert_after (&gsi, cos_load, GSI_NEW_STMT);
> +
> +      /* Create a complex number from sin and cos results so the replacement
> +    logic can extract them using REALPART_EXPR (cos) and
> +    IMAGPART_EXPR (sin).  */
> +      res = make_temp_ssa_name (complex_type, NULL, "sincostmp");
> +      gimple *complex_stmt = gimple_build_assign (res, COMPLEX_EXPR, cos_ssa,
> +                         sin_ssa);
> +      gsi_insert_after (&gsi, complex_stmt, GSI_NEW_STMT);
>      }
>    else
>      {
> -      gsi = gsi_after_labels (top_bb);
> -      gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
> +      cexpi_fndecl = mathfn_built_in (type, BUILT_IN_CEXPI);
> +      if (!cexpi_fndecl)
> +   return false;
> +
> +      /* Generate a call to cexpi instead - this is fine if we don't care
> +    about errno.  */
> +      stmt = gimple_build_call (cexpi_fndecl, 1, name);
> +      res = make_temp_ssa_name (TREE_TYPE (TREE_TYPE (cexpi_fndecl)), stmt,
> +               "sincostmp");
> +      gimple_call_set_lhs (stmt, res);
> +
> +      def_stmt = SSA_NAME_DEF_STMT (name);
> +      if (!SSA_NAME_IS_DEFAULT_DEF (name)
> +     && gimple_code (def_stmt) != GIMPLE_PHI
> +     && gimple_bb (def_stmt) == top_bb)
> +   {
> +     gsi = gsi_for_stmt (def_stmt);
> +     gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
> +   }
> +      else
> +   {
> +     gsi = gsi_after_labels (top_bb);
> +     gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
> +   }
>      }
>    sincos_stats.inserted++;
> 
> @@ -1353,6 +1423,7 @@ execute_cse_sincos_1 (tree name)
>     stmt = gimple_build_assign (gimple_call_lhs (use_stmt), rhs);
> 
>     gsi = gsi_for_stmt (use_stmt);
> +   unlink_stmt_vdef (use_stmt);
>     gsi_replace (&gsi, stmt, true);
>     if (gimple_purge_dead_eh_edges (gimple_bb (stmt)))
>       cfg_changed = true;
> @@ -2239,11 +2310,6 @@ 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