From: Kwok Cheung Yeung <kcye...@baylibre.com>

libgomp/

        * testsuite/libgomp.c++/target-std__cmath.C: New.
        * testsuite/libgomp.c++/target-std__complex.C: Likewise.
        * testsuite/libgomp.c++/target-std__numbers.C: Likewise.
---
 .../testsuite/libgomp.c++/target-std__cmath.C | 340 ++++++++++++++++++
 .../libgomp.c++/target-std__complex.C         | 175 +++++++++
 .../libgomp.c++/target-std__numbers.C         |  93 +++++
 3 files changed, 608 insertions(+)
 create mode 100644 libgomp/testsuite/libgomp.c++/target-std__cmath.C
 create mode 100644 libgomp/testsuite/libgomp.c++/target-std__complex.C
 create mode 100644 libgomp/testsuite/libgomp.c++/target-std__numbers.C

diff --git a/libgomp/testsuite/libgomp.c++/target-std__cmath.C 
b/libgomp/testsuite/libgomp.c++/target-std__cmath.C
new file mode 100644
index 00000000000..aaf715237a4
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-std__cmath.C
@@ -0,0 +1,340 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++20" }
+
+#include <cmath>
+#include <numbers>
+
+#define FP_EQUAL(x,y) (std::abs ((x) - (y)) < 1E-6)
+
+#pragma omp declare target
+template<typename T> bool test_basic ()
+{
+  T x = -3.456789;
+  T y = 1.234567;
+  T z = 5.678901;
+
+  if (std::abs (x) != -x)
+    return false;
+  if (!FP_EQUAL (std::trunc (x / y) * y + std::fmod (x, y), x))
+    return false;
+  if (!FP_EQUAL (x - std::round (x / y) * y, std::remainder (x, y)))
+    return false;
+  if (!FP_EQUAL (std::fma (x, y, z), x * y + z))
+    return false;
+  if (std::fmax (x, y) != (x > y ? x : y))
+    return false;
+  if (std::fmin (x, y) != (x < y ? x : y))
+    return false;
+  if (std::fdim (x, y) != std::max(x - y, (T) 0.0))
+    return false;
+  if (std::fdim (y, x) != std::max(y - x, (T) 0.0))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_exp ()
+{
+  T x = -4.567890;
+  T y = 2.345678;
+
+  if (!FP_EQUAL (std::exp (x), std::pow (std::numbers::e_v<T>, x)))
+    return false;
+  if (!FP_EQUAL (std::exp2 (y), std::pow ((T) 2.0, y)))
+    return false;
+  if (!FP_EQUAL (std::expm1 (y), std::exp (y) - (T) 1.0))
+    return false;
+  if (!FP_EQUAL (std::log (std::exp (x)), x))
+    return false;
+  if (!FP_EQUAL (std::log10 (std::pow ((T) 10.0, y)), y))
+    return false;
+  if (!FP_EQUAL (std::log2 (std::exp2 (y)), y))
+    return false;
+  if (!FP_EQUAL (std::log1p (std::expm1 (y)), y))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_power ()
+{
+  T x = 7.234251;
+  T y = 0.340128;
+
+  if (!FP_EQUAL (std::log (std::pow (x, y)) / std::log (x), y))
+    return false;
+  if (!FP_EQUAL (std::sqrt (x) * std::sqrt (x), x))
+    return false;
+  if (!FP_EQUAL (std::cbrt (x) * std::cbrt (x) * std::cbrt (x), x))
+    return false;
+  if (!FP_EQUAL (std::hypot (x, y), std::sqrt (x * x + y * y)))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_trig ()
+{
+  T theta = std::numbers::pi / 4;
+  T phi = std::numbers::pi / 6;
+
+  if (!FP_EQUAL (std::sin (theta), std::sqrt ((T) 2) / 2))
+    return false;
+  if (!FP_EQUAL (std::sin (phi), 0.5))
+    return false;
+  if (!FP_EQUAL (std::cos (theta), std::sqrt ((T) 2) / 2))
+    return false;
+  if (!FP_EQUAL (std::cos (phi), std::sqrt ((T) 3) / 2))
+    return false;
+  if (!FP_EQUAL (std::tan (theta), 1.0))
+    return false;
+  if (!FP_EQUAL (std::tan (phi), std::sqrt ((T) 3) / 3))
+    return false;
+
+  T x = 0.33245623;
+
+  if (!FP_EQUAL (std::asin (std::sin (x)), x))
+    return false;
+  if (!FP_EQUAL (std::acos (std::cos (x)), x))
+    return false;
+  if (!FP_EQUAL (std::atan (std::tan (x)), x))
+    return false;
+  if (!FP_EQUAL (std::atan2 (std::sin (x), std::cos (x)), x))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_hyperbolic ()
+{
+  T x = 0.7423532;
+
+  if (!FP_EQUAL (std::sinh (x), (std::exp (x) - std::exp (-x)) / (T) 2.0))
+    return false;
+  if (!FP_EQUAL (std::cosh (x), (std::exp (x) + std::exp (-x)) / (T) 2.0))
+    return false;
+  if (!FP_EQUAL (std::tanh (x), std::sinh (x) / std::cosh (x)))
+    return false;
+  if (!FP_EQUAL (std::asinh (std::sinh (x)), x))
+    return false;
+  if (!FP_EQUAL (std::acosh (std::cosh (x)), x))
+    return false;
+  if (!FP_EQUAL (std::atanh (std::tanh (x)), x))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_erf ()
+{
+  if (!FP_EQUAL (std::erf ((T) 0), 0))
+    return false;
+  if (!FP_EQUAL (std::erf ((T) INFINITY), 1))
+    return false;
+  if (!FP_EQUAL (std::erf ((T) -INFINITY), -1))
+    return false;
+
+  if (!FP_EQUAL (std::erfc (0), 1))
+    return false;
+  if (!FP_EQUAL (std::erfc ((T) INFINITY), 0))
+    return false;
+  if (!FP_EQUAL (std::erfc ((T) -INFINITY), 2))
+    return false;
+
+  return true;
+}
+
+template<typename T> bool test_gamma ()
+{
+  if (!FP_EQUAL (std::tgamma ((T) 5), 4*3*2*1))
+    return false;
+  if (!FP_EQUAL (std::tgamma ((T) 0.5), std::sqrt (std::numbers::pi_v<T>)))
+    return false;
+  if (!FP_EQUAL (std::tgamma ((T) -0.5), (T) -2 * std::sqrt 
(std::numbers::pi_v<T>)))
+    return false;
+  if (!FP_EQUAL (std::tgamma ((T) 2.5), (T) 0.75 * std::sqrt 
(std::numbers::pi_v<T>)))
+    return false;
+  if (!FP_EQUAL (std::tgamma ((T) -2.5), (T) -8.0/15 * std::sqrt 
(std::numbers::pi_v<T>)))
+    return false;
+
+  if (!FP_EQUAL (std::lgamma ((T) 5), std::log ((T) 4*3*2*1)))
+    return false;
+  if (!FP_EQUAL (std::lgamma ((T) 0.5), std::log (std::sqrt 
(std::numbers::pi_v<T>))))
+    return false;
+  if (!FP_EQUAL (std::lgamma ((T) 2.5),
+                std::log ((T) 0.75 * std::sqrt (std::numbers::pi_v<T>))))
+    return false;
+
+  return true;
+}
+
+template<typename T> bool test_rounding ()
+{
+  T x = -2.5678;
+  T y = 3.6789;
+
+  if (std::ceil (x) != -2)
+    return false;
+  if (std::floor (x) != -3)
+    return false;
+  if (std::trunc (x) != -2)
+    return false;
+  if (std::round (x) != -3)
+    return false;
+
+  if (std::ceil (y) != 4)
+    return false;
+  if (std::floor (y) != 3)
+    return false;
+  if (std::trunc (y) != 3)
+    return false;
+  if (std::round (y) != 4)
+    return false;
+
+  /* Not testing std::rint and std::nearbyint due to dependence on
+     floating-point environment.  */
+
+  return true;
+}
+
+template<typename T> bool test_fpmanip ()
+{
+  T x = -2.3456789;
+  T y = 3.6789012;
+  int exp;
+
+  T mantissa = std::frexp (x, &exp);
+  if (std::ldexp (mantissa, exp) != x)
+    return false;
+  if (std::logb (x) + 1 != exp)
+    return false;
+  if (std::ilogb (x) + 1 != exp)
+    return false;
+  if (std::scalbn (x, -exp) != mantissa)
+    return false;
+
+  T next = std::nextafter (x, y);
+  if (!(next > x && next < y))
+    return false;
+
+#if 0
+  /* TODO Due to 'std::nexttoward' using 'long double to', this triggers a
+     '80-bit-precision floating-point numbers unsupported (mode ‘XF’)' error
+     with x86_64 host and nvptx, GCN offload compilers, or
+     '128-bit-precision floating-point numbers unsupported (mode ‘TF’)' error
+     with powerpc64le host and nvptx offload compiler, for example;
+     PR71064 'nvptx offloading: "long double" data type'.
+     It ought to work on systems where the host's 'long double' is the same as
+     'double' ('DF'): aarch64, for example?  */
+  next = std::nexttoward (x, y);
+  if (!(next > x && next < y))
+    return false;
+#endif
+
+  if (std::copysign (x, y) != std::abs (x))
+    return false;
+  if (std::copysign (y, x) != -y)
+    return false;
+
+  return true;
+}
+
+template<typename T> bool test_classify ()
+{
+  T x = -2.3456789;
+  T y = 3.6789012;
+
+  if (std::fpclassify (x) != FP_NORMAL || std::fpclassify (y) != FP_NORMAL)
+    return false;
+  if (std::fpclassify ((T) INFINITY) != FP_INFINITE
+      || std::fpclassify ((T) -INFINITY) != FP_INFINITE)
+    return false;
+  if (std::fpclassify ((T) 0.0) != FP_ZERO)
+    return false;
+  if (std::fpclassify ((T) NAN) != FP_NAN)
+    return false;
+  if (!std::isfinite (x) || !std::isfinite (y))
+    return false;
+  if (std::isfinite ((T) INFINITY) || std::isfinite ((T) -INFINITY))
+    return false;
+  if (std::isinf (x) || std::isinf (y))
+    return false;
+  if (!std::isinf ((T) INFINITY) || !std::isinf ((T) -INFINITY))
+    return false;
+  if (std::isnan (x) || std::isnan (y))
+    return false;
+  if (!std::isnan ((T) 0.0 / (T) 0.0))
+    return false;
+  if (std::isnan (x) || std::isnan (y))
+    return false;
+  if (!std::isnormal (x) || !std::isnormal (y))
+    return false;
+  if (std::isnormal ((T) 0.0) || std::isnormal ((T) INFINITY) || std::isnormal 
((T) NAN))
+    return false;
+  if (!std::signbit (x) || std::signbit (y))
+    return false;
+
+  return true;
+}
+
+template<typename T> bool test_compare ()
+{
+  T x = 5.6789012;
+  T y = 8.9012345;
+
+  if (std::isgreater (x, y))
+    return false;
+  if (std::isgreater (x, x))
+    return false;
+  if (std::isgreaterequal (x, y))
+    return false;
+  if (!std::isgreaterequal (x, x))
+    return false;
+  if (!std::isless (x, y))
+    return false;
+  if (std::isless (x, x))
+    return false;
+  if (!std::islessequal (x, y))
+    return false;
+  if (!std::islessequal (x, x))
+    return false;
+  if (!std::islessgreater (x, y))
+    return false;
+  if (std::islessgreater (x, x))
+    return false;
+  if (std::isunordered (x, y))
+    return false;
+  if (!std::isunordered (x, NAN))
+    return false;
+  return true;
+}
+#pragma omp end declare target
+
+#define RUN_TEST(func) \
+{ \
+  pass++; \
+  bool ok = test_##func<float> (); \
+  if (!ok) { result = pass; break; } \
+  pass++; \
+  ok = test_##func<double> (); \
+  if (!ok) { result = pass; break; } \
+}
+
+int main (void)
+{
+  int result = 0;
+
+  #pragma omp target map (tofrom: result)
+    do {
+      int pass = 0;
+
+      RUN_TEST (basic);
+      RUN_TEST (exp);
+      RUN_TEST (power);
+      RUN_TEST (trig);
+      RUN_TEST (hyperbolic);
+      RUN_TEST (erf);
+      RUN_TEST (gamma);
+      RUN_TEST (rounding);
+      RUN_TEST (fpmanip);
+      RUN_TEST (classify);
+      RUN_TEST (compare);
+    } while (false);
+
+  return result;
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-std__complex.C 
b/libgomp/testsuite/libgomp.c++/target-std__complex.C
new file mode 100644
index 00000000000..e392d17a303
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-std__complex.C
@@ -0,0 +1,175 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++20" }
+
+#include <cmath>
+#include <complex>
+#include <numbers>
+
+using namespace std::complex_literals;
+
+#define FP_EQUAL(x,y) (std::abs ((x) - (y)) < 1E-6)
+#define COMPLEX_EQUAL(x,y) (FP_EQUAL ((x).real (), (y).real ()) \
+                           && FP_EQUAL ((x).imag (), (y).imag ()))
+
+#pragma omp declare target
+template<typename T> bool test_complex ()
+{
+  std::complex<T> z (-1.334, 5.763);
+
+  if (!FP_EQUAL (z.real (), (T) -1.334))
+    return false;
+  if (!FP_EQUAL (z.imag (), (T) 5.763))
+    return false;
+  if (!FP_EQUAL (std::abs (z),
+                std::sqrt (z.real () * z.real () + z.imag () * z.imag ())))
+    return false;
+  if (!FP_EQUAL (std::arg (z), std::atan2 (z.imag (), z.real ())))
+    return false;
+  if (!FP_EQUAL (std::norm (z), z.real () * z.real () + z.imag () * z.imag ()))
+    return false;
+
+  auto conj = std::conj (z);
+  if (!FP_EQUAL (conj.real (), z.real ())
+      || !FP_EQUAL (conj.imag (), -z.imag ()))
+    return false;
+
+  if (std::proj (z) != z)
+    return false;
+
+  auto infz1 = std::proj (std::complex<float> (INFINITY, -1));
+  if (infz1.real () != INFINITY || infz1.imag () != (T) -0.0)
+    return false;
+  auto infz2 = std::proj (std::complex<float> (0, -INFINITY));
+  if (infz2.real () != INFINITY || infz2.imag () != (T) -0.0)
+    return false;
+
+  auto polarz = std::polar ((T) 1.5, std::numbers::pi_v<T> / 4);
+  if (!FP_EQUAL (polarz.real (), (T) 1.5 * std::cos (std::numbers::pi_v<T> / 
4))
+      || !FP_EQUAL (polarz.imag (),
+                   (T) 1.5* std::sin (std::numbers::pi_v<T> / 4)))
+    return false;
+
+  return true;
+}
+
+template<typename T> bool test_complex_exp_log ()
+{
+  std::complex<T> z (-1.724, -3.763);
+
+  // Euler's identity
+  auto eulerz = std::exp (std::complex<T> (0, std::numbers::pi));
+  eulerz += 1.0;
+  if (!COMPLEX_EQUAL (eulerz, std::complex<T> ()))
+    return false;
+
+  auto my_exp_z
+    = std::complex<T> (std::exp (z.real ()) * std::cos (z.imag ()),
+                      std::exp (z.real ()) * std::sin (z.imag ()));
+  if (!COMPLEX_EQUAL (std::exp (z), my_exp_z))
+    return false;
+
+  if (!COMPLEX_EQUAL (std::log10 (z),
+                     std::log (z) / std::log (std::complex<T> (10))))
+    return false;
+
+  return true;
+}
+
+template<typename T> bool test_complex_trig ()
+{
+  std::complex<T> z (std::numbers::pi / 8, std::numbers::pi / 10);
+  const std::complex<T> i (0, 1);
+
+  auto my_sin_z
+    = std::complex<T> (std::sin (z.real ()) * std::cosh (z.imag ()),
+                      std::cos (z.real ()) * std::sinh (z.imag ()));
+  if (!COMPLEX_EQUAL (std::sin (z), my_sin_z))
+    return false;
+
+  auto my_cos_z
+    = std::complex<T> (std::cos (z.real ()) * std::cosh (z.imag ()),
+                      -std::sin (z.real ()) * std::sinh (z.imag ()));
+  if (!COMPLEX_EQUAL (std::cos (z), my_cos_z))
+    return false;
+
+  auto my_tan_z
+    = std::complex<T> (std::sin (2*z.real ()), std::sinh (2*z.imag ()))
+      / (std::cos (2*z.real ()) + std::cosh (2*z.imag ()));
+  if (!COMPLEX_EQUAL (std::tan (z), my_tan_z))
+    return false;
+
+  auto my_sinh_z
+    = std::complex<T> (std::sinh (z.real ()) * std::cos (z.imag ()),
+                      std::cosh (z.real ()) * std::sin (z.imag ()));
+  if (!COMPLEX_EQUAL (std::sinh (z), my_sinh_z))
+    return false;
+
+  auto my_cosh_z
+    = std::complex<T> (std::cosh (z.real ()) * std::cos (z.imag ()),
+                      std::sinh (z.real ()) * std::sin (z.imag ()));
+  if (!COMPLEX_EQUAL (std::cosh (z), my_cosh_z))
+    return false;
+
+  auto my_tanh_z
+    = std::complex<T> (std::sinh (2*z.real ()),
+                      std::sin (2*z.imag ()))
+                      / (std::cosh (2*z.real ()) + std::cos (2*z.imag ()));
+  if (!COMPLEX_EQUAL (std::tanh (z), my_tanh_z))
+    return false;
+
+  auto my_asin_z = -i * std::log (i * z + std::sqrt ((T) 1.0 - z*z));
+  if (!COMPLEX_EQUAL (std::asin (z), my_asin_z))
+    return false;
+
+  auto my_acos_z
+    = std::complex<T> (std::numbers::pi / 2)
+                      + i * std::log (i * z + std::sqrt ((T) 1.0 - z*z));
+  if (!COMPLEX_EQUAL (std::acos (z), my_acos_z))
+    return false;
+
+  auto my_atan_z = std::complex<T> (0, -0.5) * (std::log ((i - z) / (i + z)));
+  if (!COMPLEX_EQUAL (std::atan (z), my_atan_z))
+    return false;
+
+  auto my_asinh_z = std::log (z + std::sqrt (z*z + (T) 1.0));
+  if (!COMPLEX_EQUAL (std::asinh (z), my_asinh_z))
+    return false;
+
+  auto my_acosh_z = std::log (z + std::sqrt (z*z - (T) 1.0));
+  if (!COMPLEX_EQUAL (std::acosh (z), my_acosh_z))
+    return false;
+
+  auto my_atanh_z
+    = std::complex<T> (0.5) * (std::log ((T) 1.0 + z) - std::log ((T) 1.0 - 
z));
+  if (!COMPLEX_EQUAL (std::atanh (z), my_atanh_z))
+    return false;
+
+  return true;
+}
+#pragma omp end declare target
+
+#define RUN_TEST(func) \
+{ \
+  pass++; \
+  bool ok = test_##func<float> (); \
+  if (!ok) { result = pass; break; } \
+  pass++; \
+  ok = test_##func<double> (); \
+  if (!ok) { result = pass; break; } \
+}
+
+int main (void)
+{
+  int result = 0;
+
+  #pragma omp target map (tofrom: result)
+    do {
+      int pass = 0;
+
+      RUN_TEST (complex);
+      RUN_TEST (complex_exp_log);
+      RUN_TEST (complex_trig);
+    } while (false);
+
+  return result;
+}
diff --git a/libgomp/testsuite/libgomp.c++/target-std__numbers.C 
b/libgomp/testsuite/libgomp.c++/target-std__numbers.C
new file mode 100644
index 00000000000..a6b3665663b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/target-std__numbers.C
@@ -0,0 +1,93 @@
+// { dg-do run }
+// { dg-additional-options "-std=c++20" }
+
+#include <cmath>
+#include <numbers>
+
+#define FP_EQUAL(x,y) (std::abs ((x) - (y)) < 1E-6)
+
+#pragma omp declare target
+template<typename T> bool test_pi ()
+{
+  if (!FP_EQUAL (std::sin (std::numbers::pi_v<T>), (T) 0.0))
+    return false;
+  if (!FP_EQUAL (std::cos (std::numbers::pi_v<T>), (T) -1.0))
+    return false;
+  if (!FP_EQUAL (std::numbers::pi_v<T> * std::numbers::inv_pi_v<T>, (T) 1.0))
+    return false;
+  if (!FP_EQUAL (std::numbers::pi_v<T> * std::numbers::inv_sqrtpi_v<T>
+                * std::numbers::inv_sqrtpi_v<T>, (T) 1.0))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_sqrt ()
+{
+  if (!FP_EQUAL (std::numbers::sqrt2_v<T> * std::numbers::sqrt2_v<T>, (T) 2.0))
+    return false;
+  if (!FP_EQUAL (std::numbers::sqrt3_v<T> * std::numbers::sqrt3_v<T>, (T) 3.0))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_phi ()
+{
+  T myphi = ((T) 1.0 + std::sqrt ((T) 5.0)) / (T) 2.0;
+  if (!FP_EQUAL (myphi, std::numbers::phi_v<T>))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_log ()
+{
+  if (!FP_EQUAL (std::log ((T) 2.0), std::numbers::ln2_v<T>))
+    return false;
+  if (!FP_EQUAL (std::log ((T) 10.0), std::numbers::ln10_v<T>))
+    return false;
+  if (!FP_EQUAL (std::log2 ((T) std::numbers::e), std::numbers::log2e_v<T>))
+    return false;
+  if (!FP_EQUAL (std::log10 ((T) std::numbers::e), std::numbers::log10e_v<T>))
+    return false;
+  return true;
+}
+
+template<typename T> bool test_egamma ()
+{
+  T myegamma = 0.0;
+  #pragma omp parallel for reduction(+:myegamma)
+    for (int k = 2; k < 100000; ++k)
+      myegamma += (std::riemann_zeta (k) - 1) / k;
+  myegamma = (T) 1 - myegamma;
+  if (!FP_EQUAL (myegamma, std::numbers::egamma_v<T>))
+    return false;
+  return true;
+}
+#pragma omp end declare target
+
+#define RUN_TEST(func) \
+{ \
+  pass++; \
+  bool ok = test_##func<float> (); \
+  if (!ok) { result = pass; break; } \
+  pass++; \
+  ok = test_##func<double> (); \
+  if (!ok) { result = pass; break; } \
+}
+
+int main (void)
+{
+  int result = 0;
+
+  #pragma omp target map (tofrom: result)
+    do {
+      int pass = 0;
+
+      RUN_TEST (pi);
+      RUN_TEST (sqrt);
+      RUN_TEST (phi);
+      RUN_TEST (log);
+      RUN_TEST (egamma);
+    } while (false);
+
+  return result;
+}
-- 
2.34.1

Reply via email to