[flang-commits] [flang] [flang][AIX] Handle more trig functions with complex argument to have consistent results in folding (PR #124203)

Kelvin Li via flang-commits flang-commits at lists.llvm.org
Mon Jan 27 10:08:26 PST 2025


https://github.com/kkwli updated https://github.com/llvm/llvm-project/pull/124203

>From ec087b0d95c4ce024ab1b594c2593c555bc14e36 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Fri, 3 Jan 2025 18:15:26 -0500
Subject: [PATCH 1/5] [flang] Handle more trig functions with complex argument
 to have consistent results in folding

---
 flang/lib/Evaluate/intrinsics-library.cpp | 178 ++++++++++++++++------
 1 file changed, 130 insertions(+), 48 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index c1b270f518c0e0..c47004b289e00c 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -278,6 +278,24 @@ static std::complex<HostT> StdPowF2B(
   return std::pow(x, y);
 }
 
+enum trigFunc {
+  Cacos,
+  Cacosh,
+  Casin,
+  Casinh,
+  Catan,
+  Catanh,
+  Ccos,
+  Ccosh,
+  Cexp,
+  Clog,
+  Csin,
+  Csinh,
+  Csqrt,
+  Ctan,
+  Ctanh
+};
+
 #ifdef _AIX
 #ifdef __clang_major__
 #pragma clang diagnostic ignored "-Wc99-extensions"
@@ -286,8 +304,34 @@ static std::complex<HostT> StdPowF2B(
 extern "C" {
 float _Complex cacosf(float _Complex);
 double _Complex cacos(double _Complex);
+float _Complex cacoshf(float _Complex);
+double _Complex cacosh(double _Complex);
+float _Complex casinf(float _Complex);
+double _Complex casin(double _Complex);
+float _Complex casinhf(float _Complex);
+double _Complex casinh(double _Complex);
+float _Complex catanf(float _Complex);
+double _Complex catan(double _Complex);
+float _Complex catanhf(float _Complex);
+double _Complex catanh(double _Complex);
+float _Complex ccosf(float _Complex);
+double _Complex ccos(double _Complex);
+float _Complex ccoshf(float _Complex);
+double _Complex ccosh(double _Complex);
+float _Complex cexpf(float _Complex);
+double _Complex cexp(double _Complex);
+float _Complex clogf(float _Complex);
+double _Complex __clog(double _Complex);
+float _Complex csinf(float _Complex);
+double _Complex csin(double _Complex);
+float _Complex csinhf(float _Complex);
+double _Complex csinh(double _Complex);
 float _Complex csqrtf(float _Complex);
 double _Complex csqrt(double _Complex);
+float _Complex ctanf(float _Complex);
+double _Complex ctan(double _Complex);
+float _Complex ctanhf(float _Complex);
+double _Complex ctanh(double _Complex);
 }
 
 enum CRI { Real, Imag };
@@ -304,49 +348,87 @@ template <typename T, typename TA> static std::complex<T> CToCpp(const TA &x) {
   TA &z{const_cast<TA &>(x)};
   return std::complex<T>(reIm<T, TA>(z, CRI::Real), reIm<T, TA>(z, CRI::Imag));
 }
-#endif
 
-template <typename HostT>
-static std::complex<HostT> CSqrt(const std::complex<HostT> &x) {
-  std::complex<HostT> res;
-#ifdef _AIX
-  // On AIX, the implementation of csqrt[f] and std::sqrt is different,
-  // use csqrt[f] in folding.
+using FTypeCmplxFlt = _Complex float (*)(_Complex float);
+using FTypeCmplxDble = _Complex double (*)(_Complex double);
+template <typename T>
+using FTypeStdCmplx = std::complex<T> (*)(const std::complex<T>&);
+
+std::map<trigFunc, std::tuple<FTypeCmplxFlt, FTypeCmplxDble>> mapLibmTrigFunc{
+    {Cacos, {&cacosf, &cacos}}, {Cacosh, {&cacoshf, &cacosh}},
+    {Casin, {&casinf, &casin}}, {Casinh, {&casinhf, &casinh}},
+    {Catan, {&catanf, &catan}}, {Catanh, {&catanhf, &catanh}},
+    {Ccos, {&ccosf, &ccos}}, {Ccosh, {&ccoshf, &ccosh}},
+    {Cexp, {&cexpf, &cexp}}, {Clog, {&clogf, &__clog}},
+    {Csin, {&csinf, &csin}}, {Csinh, {&csinhf, &csinh}},
+    {Csqrt, {&csqrtf, &csqrt}}, {Ctan, {&ctanf, &ctan}},
+    {Ctanh, {&ctanhf, &ctanh}}};
+
+template <trigFunc TF, typename HostT>
+std::complex<HostT> LibmTrigFunc(const std::complex<HostT> &x) {
   if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{csqrtf(CppToC<float _Complex, float>(x))};
-    res = CToCpp<float, float _Complex>(r);
+    float _Complex r{
+      std::get<FTypeCmplxFlt>(mapLibmTrigFunc[TF])(CppToC<float _Complex, float>(x))};
+    return CToCpp<float, float _Complex>(r);
   } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex r{csqrt(CppToC<double _Complex, double>(x))};
-    res = CToCpp<double, double _Complex>(r);
-  } else {
-    DIE("bad complex component type");
+    double _Complex r{
+      std::get<FTypeCmplxDble>(mapLibmTrigFunc[TF])(CppToC<double _Complex, double>(x))};
+    return CToCpp<double, double _Complex>(r);
   }
-#else
-  res = std::sqrt(x);
+  DIE("bad complex component type");
+}
 #endif
-  return res;
+
+template <trigFunc TF, typename HostT>
+std::complex<HostT> StdTrigFunc(const std::complex<HostT> &x) {
+  if constexpr (TF == Cacos) {
+    return std::acos(x);
+  } else if constexpr (TF == Cacosh) {
+    return std::acosh(x);
+  } else if constexpr (TF == Casin) {
+    return std::asin(x);
+  } else if constexpr (TF == Casinh) {
+    return std::asinh(x);
+  } else if constexpr (TF == Catan) {
+    return std::atan(x);
+  } else if constexpr (TF == Catanh) {
+    return std::atanh(x);
+  } else if constexpr (TF == Ccos) {
+    return std::cos(x);
+  } else if constexpr (TF == Ccosh) {
+    return std::cosh(x);
+  } else if constexpr (TF == Cexp) {
+    return std::exp(x);
+  } else if constexpr (TF == Clog) {
+    return std::log(x);
+  } else if constexpr (TF == Csin) {
+    return std::sin(x);
+  } else if constexpr (TF == Csinh) {
+    return std::sinh(x);
+  } else if constexpr (TF == Csqrt) {
+    return std::sqrt(x);
+  } else if constexpr (TF == Ctan) {
+    return std::tan(x);
+  } else if constexpr (TF == Ctanh) {
+    return std::tanh(x);
+  }
+  DIE("unknown function");
 }
 
-template <typename HostT>
-static std::complex<HostT> CAcos(const std::complex<HostT> &x) {
-  std::complex<HostT> res;
+template <trigFunc TF> struct X {
+  template <typename HostT>
+  static std::complex<HostT> f(const std::complex<HostT> &x) {
+    std::complex<HostT> res;
 #ifdef _AIX
-  // On AIX, the implementation of cacos[f] and std::acos is different,
-  // use cacos[f] in folding.
-  if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{cacosf(CppToC<float _Complex, float>(x))};
-    res = CToCpp<float, float _Complex>(r);
-  } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex r{cacos(CppToC<double _Complex, double>(x))};
-    res = CToCpp<double, double _Complex>(r);
-  } else {
-    DIE("bad complex component type");
-  }
+    // On AIX, the implementation in libm is different from that of std::
+    // routines, use the libm routines here in folding for consistent results.
+    res = LibmTrigFunc<TF>(x);
 #else
-  res = std::acos(x);
+    res = StdTrigFunc<TF, HostT>(x);
 #endif
-  return res;
-}
+    return res;
+  }
+};
 
 template <typename HostT>
 struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
@@ -358,24 +440,24 @@ struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
   using F2B = FuncPointer<std::complex<HostT>, const std::complex<HostT> &,
       const HostT &>;
   static constexpr HostRuntimeFunction table[]{
-      FolderFactory<F, F{CAcos}>::Create("acos"),
-      FolderFactory<F, F{std::acosh}>::Create("acosh"),
-      FolderFactory<F, F{std::asin}>::Create("asin"),
-      FolderFactory<F, F{std::asinh}>::Create("asinh"),
-      FolderFactory<F, F{std::atan}>::Create("atan"),
-      FolderFactory<F, F{std::atanh}>::Create("atanh"),
-      FolderFactory<F, F{std::cos}>::Create("cos"),
-      FolderFactory<F, F{std::cosh}>::Create("cosh"),
-      FolderFactory<F, F{std::exp}>::Create("exp"),
-      FolderFactory<F, F{std::log}>::Create("log"),
+      FolderFactory<F, F{X<Cacos>::f}>::Create("acos"),
+      FolderFactory<F, F{X<Cacosh>::f}>::Create("acosh"),
+      FolderFactory<F, F{X<Casin>::f}>::Create("asin"),
+      FolderFactory<F, F{X<Casinh>::f}>::Create("asinh"),
+      FolderFactory<F, F{X<Catan>::f}>::Create("atan"),
+      FolderFactory<F, F{X<Catanh>::f}>::Create("atanh"),
+      FolderFactory<F, F{X<Ccos>::f}>::Create("cos"),
+      FolderFactory<F, F{X<Ccosh>::f}>::Create("cosh"),
+      FolderFactory<F, F{X<Cexp>::f}>::Create("exp"),
+      FolderFactory<F, F{X<Clog>::f}>::Create("log"),
       FolderFactory<F2, F2{StdPowF2}>::Create("pow"),
       FolderFactory<F2A, F2A{StdPowF2A}>::Create("pow"),
       FolderFactory<F2B, F2B{StdPowF2B}>::Create("pow"),
-      FolderFactory<F, F{std::sin}>::Create("sin"),
-      FolderFactory<F, F{std::sinh}>::Create("sinh"),
-      FolderFactory<F, F{CSqrt}>::Create("sqrt"),
-      FolderFactory<F, F{std::tan}>::Create("tan"),
-      FolderFactory<F, F{std::tanh}>::Create("tanh"),
+      FolderFactory<F, F{X<Csin>::f}>::Create("sin"),
+      FolderFactory<F, F{X<Csinh>::f}>::Create("sinh"),
+      FolderFactory<F, F{X<Csqrt>::f}>::Create("sqrt"),
+      FolderFactory<F, F{X<Ctan>::f}>::Create("tan"),
+      FolderFactory<F, F{X<Ctanh>::f}>::Create("tanh"),
   };
   static constexpr HostRuntimeMap map{table};
   static_assert(map.Verify(), "map must be sorted");

>From e032bfd3b62f1f1c241fc0822d1e2185b1f34d2d Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 23 Jan 2025 17:39:18 -0500
Subject: [PATCH 2/5] add pow

---
 flang/lib/Evaluate/intrinsics-library.cpp | 80 ++++++++++++++++++-----
 1 file changed, 62 insertions(+), 18 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index c47004b289e00c..60bb2785c725fd 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -260,24 +260,6 @@ struct HostRuntimeLibrary<HostT, LibraryVersion::Libm> {
   static_assert(map.Verify(), "map must be sorted");
 };
 
-// Helpers to map complex std::pow whose resolution in F2{std::pow} is
-// ambiguous as of clang++ 20.
-template <typename HostT>
-static std::complex<HostT> StdPowF2(
-    const std::complex<HostT> &x, const std::complex<HostT> &y) {
-  return std::pow(x, y);
-}
-template <typename HostT>
-static std::complex<HostT> StdPowF2A(
-    const HostT &x, const std::complex<HostT> &y) {
-  return std::pow(x, y);
-}
-template <typename HostT>
-static std::complex<HostT> StdPowF2B(
-    const std::complex<HostT> &x, const HostT &y) {
-  return std::pow(x, y);
-}
-
 enum trigFunc {
   Cacos,
   Cacosh,
@@ -322,6 +304,8 @@ float _Complex cexpf(float _Complex);
 double _Complex cexp(double _Complex);
 float _Complex clogf(float _Complex);
 double _Complex __clog(double _Complex);
+float _Complex cpowf(float _Complex, float _Complex);
+double _Complex cpow(double _Complex, double _Complex);
 float _Complex csinf(float _Complex);
 double _Complex csin(double _Complex);
 float _Complex csinhf(float _Complex);
@@ -430,6 +414,66 @@ template <trigFunc TF> struct X {
   }
 };
 
+// Helpers to map complex std::pow whose resolution in F2{std::pow} is
+// ambiguous as of clang++ 20.
+template <typename HostT>
+static std::complex<HostT> StdPowF2(const std::complex<HostT> &x,
+                                    const std::complex<HostT> &y) {
+#ifdef _AIX
+  if constexpr (std::is_same_v<HostT, float>) {
+    float _Complex r{cpowf(CppToC<float _Complex, float>(x),
+                           CppToC<float _Complex, float>(y))};
+    return CToCpp<float, float _Complex>(r);
+  } else if constexpr (std::is_same_v<HostT, double>) {
+    double _Complex r{cpow(CppToC<double _Complex, double>(x),
+                           CppToC<double _Complex, double>(y))};
+    return CToCpp<double, double _Complex>(r);
+  }
+#else
+  return std::pow(x, y);
+#endif
+}
+
+template <typename HostT>
+static std::complex<HostT> StdPowF2A(const HostT &x,
+                                     const std::complex<HostT> &y) {
+#ifdef _AIX
+  constexpr HostT zero{0.0};
+  std::complex<HostT> z(x, zero);
+  if constexpr (std::is_same_v<HostT, float>) {
+    float _Complex r{cpowf(CppToC<float _Complex, float>(z),
+                           CppToC<float _Complex, float>(y))};
+    return CToCpp<float, float _Complex>(r);
+  } else if constexpr (std::is_same_v<HostT, double>) {
+    double _Complex r{cpow(CppToC<double _Complex, double>(z),
+                           CppToC<double _Complex, double>(y))};
+    return CToCpp<double, double _Complex>(r);
+  }
+#else
+  return std::pow(x, y);
+#endif
+}
+
+template <typename HostT>
+static std::complex<HostT> StdPowF2B(const std::complex<HostT> &x,
+                                     const HostT &y) {
+#ifdef _AIX
+  constexpr HostT zero{0.0};
+  std::complex<HostT> z(y, zero);
+  if constexpr (std::is_same_v<HostT, float>) {
+    float _Complex r{cpowf(CppToC<float _Complex, float>(x),
+                           CppToC<float _Complex, float>(z))};
+    return CToCpp<float, float _Complex>(r);
+  } else if constexpr (std::is_same_v<HostT, double>) {
+    double _Complex r{cpow(CppToC<double _Complex, double>(x),
+                           CppToC<double _Complex, double>(z))};
+    return CToCpp<double, double _Complex>(r);
+  }
+#else
+  return std::pow(x, y);
+#endif
+}
+
 template <typename HostT>
 struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
   using F = FuncPointer<std::complex<HostT>, const std::complex<HostT> &>;

>From 82970e11bf87579083d189efcc51a0aa75d149d0 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 23 Jan 2025 18:02:04 -0500
Subject: [PATCH 3/5] fix comment and format

---
 flang/lib/Evaluate/intrinsics-library.cpp | 49 +++++++++++------------
 1 file changed, 24 insertions(+), 25 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 60bb2785c725fd..c79741e82c110d 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -336,27 +336,26 @@ template <typename T, typename TA> static std::complex<T> CToCpp(const TA &x) {
 using FTypeCmplxFlt = _Complex float (*)(_Complex float);
 using FTypeCmplxDble = _Complex double (*)(_Complex double);
 template <typename T>
-using FTypeStdCmplx = std::complex<T> (*)(const std::complex<T>&);
+using FTypeStdCmplx = std::complex<T> (*)(const std::complex<T> &);
 
 std::map<trigFunc, std::tuple<FTypeCmplxFlt, FTypeCmplxDble>> mapLibmTrigFunc{
     {Cacos, {&cacosf, &cacos}}, {Cacosh, {&cacoshf, &cacosh}},
     {Casin, {&casinf, &casin}}, {Casinh, {&casinhf, &casinh}},
     {Catan, {&catanf, &catan}}, {Catanh, {&catanhf, &catanh}},
     {Ccos, {&ccosf, &ccos}}, {Ccosh, {&ccoshf, &ccosh}},
-    {Cexp, {&cexpf, &cexp}}, {Clog, {&clogf, &__clog}},
-    {Csin, {&csinf, &csin}}, {Csinh, {&csinhf, &csinh}},
-    {Csqrt, {&csqrtf, &csqrt}}, {Ctan, {&ctanf, &ctan}},
-    {Ctanh, {&ctanhf, &ctanh}}};
+    {Cexp, {&cexpf, &cexp}}, {Clog, {&clogf, &__clog}}, {Csin, {&csinf, &csin}},
+    {Csinh, {&csinhf, &csinh}}, {Csqrt, {&csqrtf, &csqrt}},
+    {Ctan, {&ctanf, &ctan}}, {Ctanh, {&ctanhf, &ctanh}}};
 
 template <trigFunc TF, typename HostT>
 std::complex<HostT> LibmTrigFunc(const std::complex<HostT> &x) {
   if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{
-      std::get<FTypeCmplxFlt>(mapLibmTrigFunc[TF])(CppToC<float _Complex, float>(x))};
+    float _Complex r{std::get<FTypeCmplxFlt>(mapLibmTrigFunc[TF])(
+        CppToC<float _Complex, float>(x))};
     return CToCpp<float, float _Complex>(r);
   } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex r{
-      std::get<FTypeCmplxDble>(mapLibmTrigFunc[TF])(CppToC<double _Complex, double>(x))};
+    double _Complex r{std::get<FTypeCmplxDble>(mapLibmTrigFunc[TF])(
+        CppToC<double _Complex, double>(x))};
     return CToCpp<double, double _Complex>(r);
   }
   DIE("bad complex component type");
@@ -404,7 +403,7 @@ template <trigFunc TF> struct X {
   static std::complex<HostT> f(const std::complex<HostT> &x) {
     std::complex<HostT> res;
 #ifdef _AIX
-    // On AIX, the implementation in libm is different from that of std::
+    // On AIX, the implementation in libm is different from that of the STL
     // routines, use the libm routines here in folding for consistent results.
     res = LibmTrigFunc<TF>(x);
 #else
@@ -417,16 +416,16 @@ template <trigFunc TF> struct X {
 // Helpers to map complex std::pow whose resolution in F2{std::pow} is
 // ambiguous as of clang++ 20.
 template <typename HostT>
-static std::complex<HostT> StdPowF2(const std::complex<HostT> &x,
-                                    const std::complex<HostT> &y) {
+static std::complex<HostT> StdPowF2(
+    const std::complex<HostT> &x, const std::complex<HostT> &y) {
 #ifdef _AIX
   if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{cpowf(CppToC<float _Complex, float>(x),
-                           CppToC<float _Complex, float>(y))};
+    float _Complex r{cpowf(
+        CppToC<float _Complex, float>(x), CppToC<float _Complex, float>(y))};
     return CToCpp<float, float _Complex>(r);
   } else if constexpr (std::is_same_v<HostT, double>) {
     double _Complex r{cpow(CppToC<double _Complex, double>(x),
-                           CppToC<double _Complex, double>(y))};
+        CppToC<double _Complex, double>(y))};
     return CToCpp<double, double _Complex>(r);
   }
 #else
@@ -435,18 +434,18 @@ static std::complex<HostT> StdPowF2(const std::complex<HostT> &x,
 }
 
 template <typename HostT>
-static std::complex<HostT> StdPowF2A(const HostT &x,
-                                     const std::complex<HostT> &y) {
+static std::complex<HostT> StdPowF2A(
+    const HostT &x, const std::complex<HostT> &y) {
 #ifdef _AIX
   constexpr HostT zero{0.0};
   std::complex<HostT> z(x, zero);
   if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{cpowf(CppToC<float _Complex, float>(z),
-                           CppToC<float _Complex, float>(y))};
+    float _Complex r{cpowf(
+        CppToC<float _Complex, float>(z), CppToC<float _Complex, float>(y))};
     return CToCpp<float, float _Complex>(r);
   } else if constexpr (std::is_same_v<HostT, double>) {
     double _Complex r{cpow(CppToC<double _Complex, double>(z),
-                           CppToC<double _Complex, double>(y))};
+        CppToC<double _Complex, double>(y))};
     return CToCpp<double, double _Complex>(r);
   }
 #else
@@ -455,18 +454,18 @@ static std::complex<HostT> StdPowF2A(const HostT &x,
 }
 
 template <typename HostT>
-static std::complex<HostT> StdPowF2B(const std::complex<HostT> &x,
-                                     const HostT &y) {
+static std::complex<HostT> StdPowF2B(
+    const std::complex<HostT> &x, const HostT &y) {
 #ifdef _AIX
   constexpr HostT zero{0.0};
   std::complex<HostT> z(y, zero);
   if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{cpowf(CppToC<float _Complex, float>(x),
-                           CppToC<float _Complex, float>(z))};
+    float _Complex r{cpowf(
+        CppToC<float _Complex, float>(x), CppToC<float _Complex, float>(z))};
     return CToCpp<float, float _Complex>(r);
   } else if constexpr (std::is_same_v<HostT, double>) {
     double _Complex r{cpow(CppToC<double _Complex, double>(x),
-                           CppToC<double _Complex, double>(z))};
+        CppToC<double _Complex, double>(z))};
     return CToCpp<double, double _Complex>(r);
   }
 #else

>From 8ce9aee0736842fdf6a95762f4145c45dc56f14e Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Sat, 25 Jan 2025 23:19:08 -0500
Subject: [PATCH 4/5] implement suggestion from the review

---
 flang/lib/Evaluate/intrinsics-library.cpp | 319 +++++++++-------------
 1 file changed, 123 insertions(+), 196 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index c79741e82c110d..c8e9f8e3f00bbd 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -260,25 +260,65 @@ struct HostRuntimeLibrary<HostT, LibraryVersion::Libm> {
   static_assert(map.Verify(), "map must be sorted");
 };
 
-enum trigFunc {
-  Cacos,
-  Cacosh,
-  Casin,
-  Casinh,
-  Catan,
-  Catanh,
-  Ccos,
-  Ccosh,
-  Cexp,
-  Clog,
-  Csin,
-  Csinh,
-  Csqrt,
-  Ctan,
-  Ctanh
-};
+#define COMPLEX_SIGNATURES(HOST_T) \
+  using F = FuncPointer<std::complex<HOST_T>, const std::complex<HOST_T> &>; \
+  using F2 = FuncPointer<std::complex<HOST_T>, const std::complex<HOST_T> &, \
+      const std::complex<HOST_T> &>; \
+  using F2A = FuncPointer<std::complex<HOST_T>, const HOST_T &, \
+      const std::complex<HOST_T> &>; \
+  using F2B = FuncPointer<std::complex<HOST_T>, const std::complex<HOST_T> &, \
+      const HOST_T &>;
+
+#ifndef _AIX
+// Helpers to map complex std::pow whose resolution in F2{std::pow} is
+// ambiguous as of clang++ 20.
+template <typename HostT>
+static std::complex<HostT> StdPowF2(
+    const std::complex<HostT> &x, const std::complex<HostT> &y) {
+  return std::pow(x, y);
+}
 
-#ifdef _AIX
+template <typename HostT>
+static std::complex<HostT> StdPowF2A(
+    const HostT &x, const std::complex<HostT> &y) {
+  return std::pow(x, y);
+}
+
+template <typename HostT>
+static std::complex<HostT> StdPowF2B(
+    const std::complex<HostT> &x, const HostT &y) {
+  return std::pow(x, y);
+}
+
+template <typename HostT>
+struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
+  COMPLEX_SIGNATURES(HostT)
+  static constexpr HostRuntimeFunction table[]{
+      FolderFactory<F, F{std::acos}>::Create("acos"),
+      FolderFactory<F, F{std::acosh}>::Create("acosh"),
+      FolderFactory<F, F{std::asin}>::Create("asin"),
+      FolderFactory<F, F{std::asinh}>::Create("asinh"),
+      FolderFactory<F, F{std::atan}>::Create("atan"),
+      FolderFactory<F, F{std::atanh}>::Create("atanh"),
+      FolderFactory<F, F{std::cos}>::Create("cos"),
+      FolderFactory<F, F{std::cosh}>::Create("cosh"),
+      FolderFactory<F, F{std::exp}>::Create("exp"),
+      FolderFactory<F, F{std::log}>::Create("log"),
+      FolderFactory<F2, F2{StdPowF2}>::Create("pow"),
+      FolderFactory<F2A, F2A{StdPowF2A}>::Create("pow"),
+      FolderFactory<F2B, F2B{StdPowF2B}>::Create("pow"),
+      FolderFactory<F, F{std::sin}>::Create("sin"),
+      FolderFactory<F, F{std::sinh}>::Create("sinh"),
+      FolderFactory<F, F{std::sqrt}>::Create("sqrt"),
+      FolderFactory<F, F{std::tan}>::Create("tan"),
+      FolderFactory<F, F{std::tanh}>::Create("tanh"),
+  };
+  static constexpr HostRuntimeMap map{table};
+  static_assert(map.Verify(), "map must be sorted");
+};
+#else
+// On AIX, call libm routines to preserve consistent value between
+// runtime and compile time evaluation.
 #ifdef __clang_major__
 #pragma clang diagnostic ignored "-Wc99-extensions"
 #endif
@@ -318,193 +358,80 @@ float _Complex ctanhf(float _Complex);
 double _Complex ctanh(double _Complex);
 }
 
-enum CRI { Real, Imag };
-template <typename TR, typename TA> static TR &reIm(TA &x, CRI n) {
-  return reinterpret_cast<TR(&)[2]>(x)[n];
-}
-template <typename TR, typename T> static TR CppToC(const std::complex<T> &x) {
-  TR r;
-  reIm<T, TR>(r, CRI::Real) = x.real();
-  reIm<T, TR>(r, CRI::Imag) = x.imag();
-  return r;
-}
-template <typename T, typename TA> static std::complex<T> CToCpp(const TA &x) {
-  TA &z{const_cast<TA &>(x)};
-  return std::complex<T>(reIm<T, TA>(z, CRI::Real), reIm<T, TA>(z, CRI::Imag));
-}
-
-using FTypeCmplxFlt = _Complex float (*)(_Complex float);
-using FTypeCmplxDble = _Complex double (*)(_Complex double);
-template <typename T>
-using FTypeStdCmplx = std::complex<T> (*)(const std::complex<T> &);
-
-std::map<trigFunc, std::tuple<FTypeCmplxFlt, FTypeCmplxDble>> mapLibmTrigFunc{
-    {Cacos, {&cacosf, &cacos}}, {Cacosh, {&cacoshf, &cacosh}},
-    {Casin, {&casinf, &casin}}, {Casinh, {&casinhf, &casinh}},
-    {Catan, {&catanf, &catan}}, {Catanh, {&catanhf, &catanh}},
-    {Ccos, {&ccosf, &ccos}}, {Ccosh, {&ccoshf, &ccosh}},
-    {Cexp, {&cexpf, &cexp}}, {Clog, {&clogf, &__clog}}, {Csin, {&csinf, &csin}},
-    {Csinh, {&csinhf, &csinh}}, {Csqrt, {&csqrtf, &csqrt}},
-    {Ctan, {&ctanf, &ctan}}, {Ctanh, {&ctanhf, &ctanh}}};
-
-template <trigFunc TF, typename HostT>
-std::complex<HostT> LibmTrigFunc(const std::complex<HostT> &x) {
-  if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{std::get<FTypeCmplxFlt>(mapLibmTrigFunc[TF])(
-        CppToC<float _Complex, float>(x))};
-    return CToCpp<float, float _Complex>(r);
-  } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex r{std::get<FTypeCmplxDble>(mapLibmTrigFunc[TF])(
-        CppToC<double _Complex, double>(x))};
-    return CToCpp<double, double _Complex>(r);
-  }
-  DIE("bad complex component type");
-}
-#endif
-
-template <trigFunc TF, typename HostT>
-std::complex<HostT> StdTrigFunc(const std::complex<HostT> &x) {
-  if constexpr (TF == Cacos) {
-    return std::acos(x);
-  } else if constexpr (TF == Cacosh) {
-    return std::acosh(x);
-  } else if constexpr (TF == Casin) {
-    return std::asin(x);
-  } else if constexpr (TF == Casinh) {
-    return std::asinh(x);
-  } else if constexpr (TF == Catan) {
-    return std::atan(x);
-  } else if constexpr (TF == Catanh) {
-    return std::atanh(x);
-  } else if constexpr (TF == Ccos) {
-    return std::cos(x);
-  } else if constexpr (TF == Ccosh) {
-    return std::cosh(x);
-  } else if constexpr (TF == Cexp) {
-    return std::exp(x);
-  } else if constexpr (TF == Clog) {
-    return std::log(x);
-  } else if constexpr (TF == Csin) {
-    return std::sin(x);
-  } else if constexpr (TF == Csinh) {
-    return std::sinh(x);
-  } else if constexpr (TF == Csqrt) {
-    return std::sqrt(x);
-  } else if constexpr (TF == Ctan) {
-    return std::tan(x);
-  } else if constexpr (TF == Ctanh) {
-    return std::tanh(x);
-  }
-  DIE("unknown function");
-}
-
-template <trigFunc TF> struct X {
-  template <typename HostT>
-  static std::complex<HostT> f(const std::complex<HostT> &x) {
-    std::complex<HostT> res;
-#ifdef _AIX
-    // On AIX, the implementation in libm is different from that of the STL
-    // routines, use the libm routines here in folding for consistent results.
-    res = LibmTrigFunc<TF>(x);
-#else
-    res = StdTrigFunc<TF, HostT>(x);
-#endif
-    return res;
-  }
+template <typename T> struct ToStdComplex {
+  using Type = T;
+  using AType = Type;
+};
+template <> struct ToStdComplex<float _Complex> {
+  using Type = std::complex<float>;
+  using AType = const Type &;
+};
+template <> struct ToStdComplex<double _Complex> {
+  using Type = std::complex<double>;
+  using AType = const Type &;
 };
 
-// Helpers to map complex std::pow whose resolution in F2{std::pow} is
-// ambiguous as of clang++ 20.
-template <typename HostT>
-static std::complex<HostT> StdPowF2(
-    const std::complex<HostT> &x, const std::complex<HostT> &y) {
-#ifdef _AIX
-  if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{cpowf(
-        CppToC<float _Complex, float>(x), CppToC<float _Complex, float>(y))};
-    return CToCpp<float, float _Complex>(r);
-  } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex r{cpow(CppToC<double _Complex, double>(x),
-        CppToC<double _Complex, double>(y))};
-    return CToCpp<double, double _Complex>(r);
-  }
-#else
-  return std::pow(x, y);
-#endif
-}
-
-template <typename HostT>
-static std::complex<HostT> StdPowF2A(
-    const HostT &x, const std::complex<HostT> &y) {
-#ifdef _AIX
-  constexpr HostT zero{0.0};
-  std::complex<HostT> z(x, zero);
-  if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{cpowf(
-        CppToC<float _Complex, float>(z), CppToC<float _Complex, float>(y))};
-    return CToCpp<float, float _Complex>(r);
-  } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex r{cpow(CppToC<double _Complex, double>(z),
-        CppToC<double _Complex, double>(y))};
-    return CToCpp<double, double _Complex>(r);
-  }
-#else
-  return std::pow(x, y);
-#endif
-}
-
-template <typename HostT>
-static std::complex<HostT> StdPowF2B(
-    const std::complex<HostT> &x, const HostT &y) {
-#ifdef _AIX
-  constexpr HostT zero{0.0};
-  std::complex<HostT> z(y, zero);
-  if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex r{cpowf(
-        CppToC<float _Complex, float>(x), CppToC<float _Complex, float>(z))};
-    return CToCpp<float, float _Complex>(r);
-  } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex r{cpow(CppToC<double _Complex, double>(x),
-        CppToC<double _Complex, double>(z))};
-    return CToCpp<double, double _Complex>(r);
+template <typename F, F func> struct CComplexFunc {};
+template <typename R, typename... A, FuncPointer<R, A...> func>
+struct CComplexFunc<FuncPointer<R, A...>, func> {
+  static typename ToStdComplex<R>::Type wrapper(
+      typename ToStdComplex<A>::AType... args) {
+    R res{func(*reinterpret_cast<const A *>(&args)...)};
+    return *reinterpret_cast<typename ToStdComplex<R>::Type *>(&res);
   }
-#else
-  return std::pow(x, y);
-#endif
-}
+};
+#define C_COMPLEX_FUNC(func) CComplexFunc<decltype(&func), &func>::wrapper
 
-template <typename HostT>
-struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
-  using F = FuncPointer<std::complex<HostT>, const std::complex<HostT> &>;
-  using F2 = FuncPointer<std::complex<HostT>, const std::complex<HostT> &,
-      const std::complex<HostT> &>;
-  using F2A = FuncPointer<std::complex<HostT>, const HostT &,
-      const std::complex<HostT> &>;
-  using F2B = FuncPointer<std::complex<HostT>, const std::complex<HostT> &,
-      const HostT &>;
+template <>
+struct HostRuntimeLibrary<std::complex<float>, LibraryVersion::Libm> {
+  COMPLEX_SIGNATURES(float)
   static constexpr HostRuntimeFunction table[]{
-      FolderFactory<F, F{X<Cacos>::f}>::Create("acos"),
-      FolderFactory<F, F{X<Cacosh>::f}>::Create("acosh"),
-      FolderFactory<F, F{X<Casin>::f}>::Create("asin"),
-      FolderFactory<F, F{X<Casinh>::f}>::Create("asinh"),
-      FolderFactory<F, F{X<Catan>::f}>::Create("atan"),
-      FolderFactory<F, F{X<Catanh>::f}>::Create("atanh"),
-      FolderFactory<F, F{X<Ccos>::f}>::Create("cos"),
-      FolderFactory<F, F{X<Ccosh>::f}>::Create("cosh"),
-      FolderFactory<F, F{X<Cexp>::f}>::Create("exp"),
-      FolderFactory<F, F{X<Clog>::f}>::Create("log"),
-      FolderFactory<F2, F2{StdPowF2}>::Create("pow"),
-      FolderFactory<F2A, F2A{StdPowF2A}>::Create("pow"),
-      FolderFactory<F2B, F2B{StdPowF2B}>::Create("pow"),
-      FolderFactory<F, F{X<Csin>::f}>::Create("sin"),
-      FolderFactory<F, F{X<Csinh>::f}>::Create("sinh"),
-      FolderFactory<F, F{X<Csqrt>::f}>::Create("sqrt"),
-      FolderFactory<F, F{X<Ctan>::f}>::Create("tan"),
-      FolderFactory<F, F{X<Ctanh>::f}>::Create("tanh"),
+    FolderFactory<F, C_COMPLEX_FUNC(cacosf)>::Create("acos"),
+    FolderFactory<F, C_COMPLEX_FUNC(cacoshf)>::Create("acosh"),
+    FolderFactory<F, C_COMPLEX_FUNC(casinf)>::Create("asin"),
+    FolderFactory<F, C_COMPLEX_FUNC(casinhf)>::Create("asinh"),
+    FolderFactory<F, C_COMPLEX_FUNC(catanf)>::Create("atan"),
+    FolderFactory<F, C_COMPLEX_FUNC(catanhf)>::Create("atanh"),
+    FolderFactory<F, C_COMPLEX_FUNC(ccosf)>::Create("cos"),
+    FolderFactory<F, C_COMPLEX_FUNC(ccoshf)>::Create("cosh"),
+    FolderFactory<F, C_COMPLEX_FUNC(cexpf)>::Create("exp"),
+    FolderFactory<F, C_COMPLEX_FUNC(clogf)>::Create("log"),
+    FolderFactory<F2, C_COMPLEX_FUNC(cpowf)>::Create("pow"),
+    FolderFactory<F, C_COMPLEX_FUNC(csinf)>::Create("sin"),
+    FolderFactory<F, C_COMPLEX_FUNC(csinhf)>::Create("sinh"),
+    FolderFactory<F, C_COMPLEX_FUNC(csqrtf)>::Create("sqrt"),
+    FolderFactory<F, C_COMPLEX_FUNC(ctanf)>::Create("tan"),
+    FolderFactory<F, C_COMPLEX_FUNC(ctanhf)>::Create("tanh"),
   };
   static constexpr HostRuntimeMap map{table};
   static_assert(map.Verify(), "map must be sorted");
 };
+template <>
+struct HostRuntimeLibrary<std::complex<double>, LibraryVersion::Libm> {
+  COMPLEX_SIGNATURES(double)
+  static constexpr HostRuntimeFunction table[]{
+    FolderFactory<F, C_COMPLEX_FUNC(cacos)>::Create("acos"),
+    FolderFactory<F, C_COMPLEX_FUNC(cacosh)>::Create("acosh"),
+    FolderFactory<F, C_COMPLEX_FUNC(casin)>::Create("asin"),
+    FolderFactory<F, C_COMPLEX_FUNC(casinh)>::Create("asinh"),
+    FolderFactory<F, C_COMPLEX_FUNC(catan)>::Create("atan"),
+    FolderFactory<F, C_COMPLEX_FUNC(catanh)>::Create("atanh"),
+    FolderFactory<F, C_COMPLEX_FUNC(ccos)>::Create("cos"),
+    FolderFactory<F, C_COMPLEX_FUNC(ccosh)>::Create("cosh"),
+    FolderFactory<F, C_COMPLEX_FUNC(cexp)>::Create("exp"),
+    FolderFactory<F, C_COMPLEX_FUNC(__clog)>::Create("log"),
+    FolderFactory<F2, C_COMPLEX_FUNC(cpow)>::Create("pow"),
+    FolderFactory<F, C_COMPLEX_FUNC(csin)>::Create("sin"),
+    FolderFactory<F, C_COMPLEX_FUNC(csinh)>::Create("sinh"),
+    FolderFactory<F, C_COMPLEX_FUNC(csqrt)>::Create("sqrt"),
+    FolderFactory<F, C_COMPLEX_FUNC(ctan)>::Create("tan"),
+    FolderFactory<F, C_COMPLEX_FUNC(ctanh)>::Create("tanh"),
+  };
+  static constexpr HostRuntimeMap map{table};
+  static_assert(map.Verify(), "map must be sorted");
+};
+#endif // _AIX
+
 // Note regarding cmath:
 //  - cmath does not have modulo and erfc_scaled equivalent
 //  - C++17 defined standard Bessel math functions std::cyl_bessel_j

>From 4e4e177d1f9a293c4a387188e80f141de091fa27 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Sun, 26 Jan 2025 00:09:10 -0500
Subject: [PATCH 5/5] fix format

---
 flang/lib/Evaluate/intrinsics-library.cpp | 64 +++++++++++------------
 1 file changed, 32 insertions(+), 32 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index c8e9f8e3f00bbd..d2c1be65dca448 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -386,22 +386,22 @@ template <>
 struct HostRuntimeLibrary<std::complex<float>, LibraryVersion::Libm> {
   COMPLEX_SIGNATURES(float)
   static constexpr HostRuntimeFunction table[]{
-    FolderFactory<F, C_COMPLEX_FUNC(cacosf)>::Create("acos"),
-    FolderFactory<F, C_COMPLEX_FUNC(cacoshf)>::Create("acosh"),
-    FolderFactory<F, C_COMPLEX_FUNC(casinf)>::Create("asin"),
-    FolderFactory<F, C_COMPLEX_FUNC(casinhf)>::Create("asinh"),
-    FolderFactory<F, C_COMPLEX_FUNC(catanf)>::Create("atan"),
-    FolderFactory<F, C_COMPLEX_FUNC(catanhf)>::Create("atanh"),
-    FolderFactory<F, C_COMPLEX_FUNC(ccosf)>::Create("cos"),
-    FolderFactory<F, C_COMPLEX_FUNC(ccoshf)>::Create("cosh"),
-    FolderFactory<F, C_COMPLEX_FUNC(cexpf)>::Create("exp"),
-    FolderFactory<F, C_COMPLEX_FUNC(clogf)>::Create("log"),
-    FolderFactory<F2, C_COMPLEX_FUNC(cpowf)>::Create("pow"),
-    FolderFactory<F, C_COMPLEX_FUNC(csinf)>::Create("sin"),
-    FolderFactory<F, C_COMPLEX_FUNC(csinhf)>::Create("sinh"),
-    FolderFactory<F, C_COMPLEX_FUNC(csqrtf)>::Create("sqrt"),
-    FolderFactory<F, C_COMPLEX_FUNC(ctanf)>::Create("tan"),
-    FolderFactory<F, C_COMPLEX_FUNC(ctanhf)>::Create("tanh"),
+      FolderFactory<F, C_COMPLEX_FUNC(cacosf)>::Create("acos"),
+      FolderFactory<F, C_COMPLEX_FUNC(cacoshf)>::Create("acosh"),
+      FolderFactory<F, C_COMPLEX_FUNC(casinf)>::Create("asin"),
+      FolderFactory<F, C_COMPLEX_FUNC(casinhf)>::Create("asinh"),
+      FolderFactory<F, C_COMPLEX_FUNC(catanf)>::Create("atan"),
+      FolderFactory<F, C_COMPLEX_FUNC(catanhf)>::Create("atanh"),
+      FolderFactory<F, C_COMPLEX_FUNC(ccosf)>::Create("cos"),
+      FolderFactory<F, C_COMPLEX_FUNC(ccoshf)>::Create("cosh"),
+      FolderFactory<F, C_COMPLEX_FUNC(cexpf)>::Create("exp"),
+      FolderFactory<F, C_COMPLEX_FUNC(clogf)>::Create("log"),
+      FolderFactory<F2, C_COMPLEX_FUNC(cpowf)>::Create("pow"),
+      FolderFactory<F, C_COMPLEX_FUNC(csinf)>::Create("sin"),
+      FolderFactory<F, C_COMPLEX_FUNC(csinhf)>::Create("sinh"),
+      FolderFactory<F, C_COMPLEX_FUNC(csqrtf)>::Create("sqrt"),
+      FolderFactory<F, C_COMPLEX_FUNC(ctanf)>::Create("tan"),
+      FolderFactory<F, C_COMPLEX_FUNC(ctanhf)>::Create("tanh"),
   };
   static constexpr HostRuntimeMap map{table};
   static_assert(map.Verify(), "map must be sorted");
@@ -410,22 +410,22 @@ template <>
 struct HostRuntimeLibrary<std::complex<double>, LibraryVersion::Libm> {
   COMPLEX_SIGNATURES(double)
   static constexpr HostRuntimeFunction table[]{
-    FolderFactory<F, C_COMPLEX_FUNC(cacos)>::Create("acos"),
-    FolderFactory<F, C_COMPLEX_FUNC(cacosh)>::Create("acosh"),
-    FolderFactory<F, C_COMPLEX_FUNC(casin)>::Create("asin"),
-    FolderFactory<F, C_COMPLEX_FUNC(casinh)>::Create("asinh"),
-    FolderFactory<F, C_COMPLEX_FUNC(catan)>::Create("atan"),
-    FolderFactory<F, C_COMPLEX_FUNC(catanh)>::Create("atanh"),
-    FolderFactory<F, C_COMPLEX_FUNC(ccos)>::Create("cos"),
-    FolderFactory<F, C_COMPLEX_FUNC(ccosh)>::Create("cosh"),
-    FolderFactory<F, C_COMPLEX_FUNC(cexp)>::Create("exp"),
-    FolderFactory<F, C_COMPLEX_FUNC(__clog)>::Create("log"),
-    FolderFactory<F2, C_COMPLEX_FUNC(cpow)>::Create("pow"),
-    FolderFactory<F, C_COMPLEX_FUNC(csin)>::Create("sin"),
-    FolderFactory<F, C_COMPLEX_FUNC(csinh)>::Create("sinh"),
-    FolderFactory<F, C_COMPLEX_FUNC(csqrt)>::Create("sqrt"),
-    FolderFactory<F, C_COMPLEX_FUNC(ctan)>::Create("tan"),
-    FolderFactory<F, C_COMPLEX_FUNC(ctanh)>::Create("tanh"),
+      FolderFactory<F, C_COMPLEX_FUNC(cacos)>::Create("acos"),
+      FolderFactory<F, C_COMPLEX_FUNC(cacosh)>::Create("acosh"),
+      FolderFactory<F, C_COMPLEX_FUNC(casin)>::Create("asin"),
+      FolderFactory<F, C_COMPLEX_FUNC(casinh)>::Create("asinh"),
+      FolderFactory<F, C_COMPLEX_FUNC(catan)>::Create("atan"),
+      FolderFactory<F, C_COMPLEX_FUNC(catanh)>::Create("atanh"),
+      FolderFactory<F, C_COMPLEX_FUNC(ccos)>::Create("cos"),
+      FolderFactory<F, C_COMPLEX_FUNC(ccosh)>::Create("cosh"),
+      FolderFactory<F, C_COMPLEX_FUNC(cexp)>::Create("exp"),
+      FolderFactory<F, C_COMPLEX_FUNC(__clog)>::Create("log"),
+      FolderFactory<F2, C_COMPLEX_FUNC(cpow)>::Create("pow"),
+      FolderFactory<F, C_COMPLEX_FUNC(csin)>::Create("sin"),
+      FolderFactory<F, C_COMPLEX_FUNC(csinh)>::Create("sinh"),
+      FolderFactory<F, C_COMPLEX_FUNC(csqrt)>::Create("sqrt"),
+      FolderFactory<F, C_COMPLEX_FUNC(ctan)>::Create("tan"),
+      FolderFactory<F, C_COMPLEX_FUNC(ctanh)>::Create("tanh"),
   };
   static constexpr HostRuntimeMap map{table};
   static_assert(map.Verify(), "map must be sorted");



More information about the flang-commits mailing list