From 0d4f394cbb4c9eace1d120059a1f54cac80f1cb7 Mon Sep 17 00:00:00 2001
From: Yuao Ma <c8ef@outlook.com>
Date: Fri, 27 Jun 2025 01:35:14 +0800
Subject: [PATCH] gcc: middle-end opt for trigonometric pi-based functions
 builtins

This patch partially handled PR118592.

This patch builds upon r16-710-g591d3d02664c7b and r16-711-g89935d56f768b4. It
introduces middle-end optimizations, such as constant folding, for our
trigonometric pi-based function built-ins.

gcc/ChangeLog:

	* fold-const-call.cc (fold_const_call_ss): Constant fold for
	single arg.
	(fold_const_call_sss): Constant fold for double args.
	* fold-const.cc (negate_mathfn_p): asinpi/atanpi is odd func.
	(tree_call_nonnegative_warnv_p): acospi always non-neg,
	asinpi/atanpi non-neg iff arg non-neg.
	* tree-call-cdce.cc (can_test_argument_range): Add acospi/asinpi.
	(edom_only_function): Add acospi/asinpi/cospi/sinpi.
	(get_no_error_domain): Add acospi/asinpi.

gcc/testsuite/ChangeLog:

	* gcc.dg/torture/builtin-math-9.c: New test.

Signed-off-by: Yuao Ma <c8ef@outlook.com>
---
 gcc/fold-const-call.cc                        | 36 ++++++++
 gcc/fold-const.cc                             | 14 +++
 gcc/testsuite/gcc.dg/torture/builtin-math-9.c | 92 +++++++++++++++++++
 gcc/tree-call-cdce.cc                         | 16 ++++
 4 files changed, 158 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/torture/builtin-math-9.c

diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc
index 8230b83b929..439bf8044f5 100644
--- a/gcc/fold-const-call.cc
+++ b/gcc/fold-const-call.cc
@@ -788,6 +788,36 @@ fold_const_call_ss (real_value *result, combined_fn fn,
     CASE_CFN_TANH_FN:
       return do_mpfr_arg1 (result, mpfr_tanh, arg, format);
 
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
+    CASE_CFN_ACOSPI:
+    CASE_CFN_ACOSPI_FN:
+      return (real_compare (GE_EXPR, arg, &dconstm1)
+	      && real_compare (LE_EXPR, arg, &dconst1)
+	      && do_mpfr_arg1 (result, mpfr_acospi, arg, format));
+
+    CASE_CFN_ASINPI:
+    CASE_CFN_ASINPI_FN:
+      return (real_compare (GE_EXPR, arg, &dconstm1)
+	      && real_compare (LE_EXPR, arg, &dconst1)
+	      && do_mpfr_arg1 (result, mpfr_asinpi, arg, format));
+
+    CASE_CFN_ATANPI:
+    CASE_CFN_ATANPI_FN:
+      return do_mpfr_arg1 (result, mpfr_atanpi, arg, format);
+
+    CASE_CFN_COSPI:
+    CASE_CFN_COSPI_FN:
+      return do_mpfr_arg1 (result, mpfr_cospi, arg, format);
+
+    CASE_CFN_SINPI:
+    CASE_CFN_SINPI_FN:
+      return do_mpfr_arg1 (result, mpfr_sinpi, arg, format);
+
+    CASE_CFN_TANPI:
+    CASE_CFN_TANPI_FN:
+      return do_mpfr_arg1 (result, mpfr_tanpi, arg, format);
+#endif
+
     CASE_CFN_ERF:
     CASE_CFN_ERF_FN:
       return do_mpfr_arg1 (result, mpfr_erf, arg, format);
@@ -1432,6 +1462,12 @@ fold_const_call_sss (real_value *result, combined_fn fn,
     CASE_CFN_ATAN2_FN:
       return do_mpfr_arg2 (result, mpfr_atan2, arg0, arg1, format);
 
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4, 2, 0)
+    CASE_CFN_ATAN2PI:
+    CASE_CFN_ATAN2PI_FN:
+      return do_mpfr_arg2 (result, mpfr_atan2pi, arg0, arg1, format);
+#endif
+
     CASE_CFN_FDIM:
     CASE_CFN_FDIM_FN:
       return do_mpfr_arg2 (result, mpfr_dim, arg0, arg1, format);
diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 014f4218793..47492575d00 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -395,10 +395,14 @@ negate_mathfn_p (combined_fn fn)
     CASE_CFN_ASIN_FN:
     CASE_CFN_ASINH:
     CASE_CFN_ASINH_FN:
+    CASE_CFN_ASINPI:
+    CASE_CFN_ASINPI_FN:
     CASE_CFN_ATAN:
     CASE_CFN_ATAN_FN:
     CASE_CFN_ATANH:
     CASE_CFN_ATANH_FN:
+    CASE_CFN_ATANPI:
+    CASE_CFN_ATANPI_FN:
     CASE_CFN_CASIN:
     CASE_CFN_CASIN_FN:
     CASE_CFN_CASINH:
@@ -432,10 +436,14 @@ negate_mathfn_p (combined_fn fn)
     CASE_CFN_SIN_FN:
     CASE_CFN_SINH:
     CASE_CFN_SINH_FN:
+    CASE_CFN_SINPI:
+    CASE_CFN_SINPI_FN:
     CASE_CFN_TAN:
     CASE_CFN_TAN_FN:
     CASE_CFN_TANH:
     CASE_CFN_TANH_FN:
+    CASE_CFN_TANPI:
+    CASE_CFN_TANPI_FN:
     CASE_CFN_TRUNC:
     CASE_CFN_TRUNC_FN:
       return true;
@@ -14962,6 +14970,8 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1,
     CASE_CFN_ACOS_FN:
     CASE_CFN_ACOSH:
     CASE_CFN_ACOSH_FN:
+    CASE_CFN_ACOSPI:
+    CASE_CFN_ACOSPI_FN:
     CASE_CFN_CABS:
     CASE_CFN_CABS_FN:
     CASE_CFN_COSH:
@@ -15006,10 +15016,14 @@ tree_call_nonnegative_warnv_p (tree type, combined_fn fn, tree arg0, tree arg1,
 
     CASE_CFN_ASINH:
     CASE_CFN_ASINH_FN:
+    CASE_CFN_ASINPI:
+    CASE_CFN_ASINPI_FN:
     CASE_CFN_ATAN:
     CASE_CFN_ATAN_FN:
     CASE_CFN_ATANH:
     CASE_CFN_ATANH_FN:
+    CASE_CFN_ATANPI:
+    CASE_CFN_ATANPI_FN:
     CASE_CFN_CBRT:
     CASE_CFN_CBRT_FN:
     CASE_CFN_CEIL:
diff --git a/gcc/testsuite/gcc.dg/torture/builtin-math-9.c b/gcc/testsuite/gcc.dg/torture/builtin-math-9.c
new file mode 100644
index 00000000000..201c42edc81
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/builtin-math-9.c
@@ -0,0 +1,92 @@
+/* Copyright (C) 1988-2025 Free Software Foundation, Inc.
+
+   Verify that built-in math function constant folding of constant
+   arguments is correctly performed by the compiler.  */
+
+/* { dg-do link } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+
+extern double acospi (double);
+extern double asinpi (double);
+extern double atanpi (double);
+extern double atan2pi (double, double);
+extern double cospi (double);
+extern double sinpi (double);
+extern double tanpi (double);
+
+extern int signbit (double);
+
+/* All references to link_error should go away at compile-time.  */
+extern void link_error (void);
+
+void
+test_normal ()
+{
+  if (__builtin_constant_p (acospi (0.5)))
+    {
+      if (acospi (0.5) < 0.3333 || acospi (0.5) > 0.3334
+	  || acospi (-0.5) < 0.6666 || acospi (-0.5) > 0.6667)
+	link_error ();
+
+      if (asinpi (0.5) < 0.1666 || asinpi (0.5) > 0.1667
+	  || asinpi (-0.5) < -0.1667 || asinpi (-0.5) > -0.1666)
+	link_error ();
+
+      if (atanpi (1.0) != 0.25 || atanpi (-1.0) > -0.25)
+	link_error ();
+
+      if (atan2pi (1.0, 1.0) > 0.2501 || atan2pi (1.0, 1.0) < 0.2499
+	  || atan2pi (1.0, -1.0) < 0.7499 || atan2pi (1.0, -1.0) > 0.7501)
+	link_error ();
+
+      if (cospi (1.0 / 3) > 0.5001 || cospi (-1.0 / 3) < 0.4999
+	  || cospi (4.0 / 3) > -0.4999 || cospi (4.0 / 3) < -0.5001)
+	link_error ();
+
+      if (sinpi (1.0 / 6) > 0.5001 || sinpi (-1.0 / 6) > -0.4999
+	  || sinpi (5.0 / 6) < 0.4999 || sinpi (-7.0 / 6) > 0.5001)
+	link_error ();
+
+      if (tanpi (0.25) != 1.0000 || tanpi (-0.25) != -1.0000
+	  || tanpi (1.25) != 1.0000 || tanpi (-1.25) != -1.0000)
+	link_error ();
+    }
+}
+
+void
+test_corner ()
+{
+  if (__builtin_constant_p (acospi (0.5)))
+    {
+      if (signbit (acospi (1.0)))
+	link_error ();
+
+      if (signbit (asinpi (0.0)) || !signbit (asinpi (-0.0)))
+	link_error ();
+
+      if (signbit (atanpi (0.0)) || !signbit (atanpi (-0.0)))
+	link_error ();
+
+      if (signbit (atan2pi (0.0, 0.0)) || !signbit (atan2pi (-0.0, 0.0))
+	  || atan2pi (0.0, -0.0) != 1 || atan2pi (-0.0, -0.0) != -1)
+	link_error ();
+
+      if (signbit (cospi (0.5)) || signbit (cospi (-0.5)))
+	link_error ();
+
+      if (signbit (sinpi (1)) || !signbit (sinpi (-1)))
+	link_error ();
+
+      if (signbit (tanpi (2)) || signbit (tanpi (-3)) || !signbit (tanpi (5))
+	  || !signbit (tanpi (-6)))
+	link_error ();
+    }
+}
+
+int
+main ()
+{
+  test_normal ();
+  test_corner ();
+  return 0;
+}
diff --git a/gcc/tree-call-cdce.cc b/gcc/tree-call-cdce.cc
index 712ec7c8920..649c1e2b9f9 100644
--- a/gcc/tree-call-cdce.cc
+++ b/gcc/tree-call-cdce.cc
@@ -296,8 +296,12 @@ can_test_argument_range (gcall *call)
     /* Trig functions.  */
     CASE_FLT_FN (BUILT_IN_ACOS):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_ACOS):
+    CASE_FLT_FN (BUILT_IN_ACOSPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_ACOSPI):
     CASE_FLT_FN (BUILT_IN_ASIN):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_ASIN):
+    CASE_FLT_FN (BUILT_IN_ASINPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_ASINPI):
     /* Hyperbolic functions.  */
     CASE_FLT_FN (BUILT_IN_ACOSH):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_ACOSH):
@@ -351,13 +355,21 @@ edom_only_function (gcall *call)
     {
     CASE_FLT_FN (BUILT_IN_ACOS):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_ACOS):
+    CASE_FLT_FN (BUILT_IN_ACOSPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_ACOSPI):
     CASE_FLT_FN (BUILT_IN_ASIN):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_ASIN):
+    CASE_FLT_FN (BUILT_IN_ASINPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_ASINPI):
     CASE_FLT_FN (BUILT_IN_COS):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_COS):
+    CASE_FLT_FN (BUILT_IN_COSPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_COSPI):
     CASE_FLT_FN (BUILT_IN_SIGNIFICAND):
     CASE_FLT_FN (BUILT_IN_SIN):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_SIN):
+    CASE_FLT_FN (BUILT_IN_SINPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_SINPI):
     CASE_FLT_FN (BUILT_IN_SQRT):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_SQRT):
     CASE_FLT_FN (BUILT_IN_FMOD):
@@ -692,8 +704,12 @@ get_no_error_domain (enum built_in_function fnc)
     /* Trig functions: return [-1, +1]  */
     CASE_FLT_FN (BUILT_IN_ACOS):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_ACOS):
+    CASE_FLT_FN (BUILT_IN_ACOSPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_ACOSPI):
     CASE_FLT_FN (BUILT_IN_ASIN):
     CASE_FLT_FN_FLOATN_NX (BUILT_IN_ASIN):
+    CASE_FLT_FN (BUILT_IN_ASINPI):
+    CASE_FLT_FN_FLOATN_NX (BUILT_IN_ASINPI):
       return get_domain (-1, true, true,
                          1, true, true);
     /* Hyperbolic functions.  */
-- 
2.43.0

