[flang-commits] [flang] [flang] Use libm routine for compile-time folding on AIX (PR #114106)

Kelvin Li via flang-commits flang-commits at lists.llvm.org
Fri Nov 8 14:34:17 PST 2024


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

>From 1742f2aa7bc57123c4a7df53dc2976b0cd589bb8 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Tue, 29 Oct 2024 13:36:24 -0400
Subject: [PATCH 1/8] [flang] Use libm routine for compile-time folding on AIX

---
 flang/lib/Evaluate/CMakeLists.txt         |  1 +
 flang/lib/Evaluate/intrinsics-library.cpp | 24 +++++++++++++++++++++++
 flang/lib/Evaluate/wrappers.c             | 17 ++++++++++++++++
 3 files changed, 42 insertions(+)
 create mode 100644 flang/lib/Evaluate/wrappers.c

diff --git a/flang/lib/Evaluate/CMakeLists.txt b/flang/lib/Evaluate/CMakeLists.txt
index b38f450d746ea7..8ffbfc8848da74 100644
--- a/flang/lib/Evaluate/CMakeLists.txt
+++ b/flang/lib/Evaluate/CMakeLists.txt
@@ -58,6 +58,7 @@ add_flang_library(FortranEvaluate
   tools.cpp
   type.cpp
   variable.cpp
+  wrappers.c
 
   LINK_LIBS
   FortranCommon
diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index bb439a6bb3a746..8b16d187513690 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -277,6 +277,26 @@ static std::complex<HostT> StdPowF2B(
   return std::pow(x, y);
 }
 
+#ifdef _AIX
+extern "C" {
+void csqrtf_wrapper(const float[], float[]);
+void csqrt_wrapper(const double[], double[]);
+} // extern "C"
+
+template <typename HostT>
+static std::complex<HostT> CSQRT(const std::complex<HostT> &x) {
+  HostT y[2]{x.real(), x.imag()};
+  HostT r[2];
+  if constexpr (std::is_same_v<HostT, float>) {
+    csqrtf_wrapper(y, r);
+  } else if constexpr (std::is_same_v<HostT, double>) {
+    csqrt_wrapper(y, r);
+  }
+  std::complex<HostT> res(r[0], r[1]);
+  return res;
+}
+#endif
+
 template <typename HostT>
 struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
   using F = FuncPointer<std::complex<HostT>, const std::complex<HostT> &>;
@@ -302,7 +322,11 @@ struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
       FolderFactory<F2B, F2B{StdPowF2B}>::Create("pow"),
       FolderFactory<F, F{std::sin}>::Create("sin"),
       FolderFactory<F, F{std::sinh}>::Create("sinh"),
+#ifdef _AIX
+      FolderFactory<F, F{CSQRT}>::Create("sqrt"),
+#else
       FolderFactory<F, F{std::sqrt}>::Create("sqrt"),
+#endif
       FolderFactory<F, F{std::tan}>::Create("tan"),
       FolderFactory<F, F{std::tanh}>::Create("tanh"),
   };
diff --git a/flang/lib/Evaluate/wrappers.c b/flang/lib/Evaluate/wrappers.c
new file mode 100644
index 00000000000000..b0823cac45ae4b
--- /dev/null
+++ b/flang/lib/Evaluate/wrappers.c
@@ -0,0 +1,17 @@
+#include <complex.h>
+
+void csqrtf_wrapper(const float x[2], float res[2])
+{
+  float complex c = x[0] + I * x[1];
+  float complex r = csqrtf(c);
+  res[0] = crealf(r);
+  res[1] = cimagf(r);
+}
+
+void csqrt_wrapper(const double x[2], double res[2])
+{
+  double complex c = x[0] + I * x[1];
+  double complex r = csqrt(c);
+  res[0] = creal(r);
+  res[1] = cimag(r);
+}

>From d5219a9792ca177f8b4bca79a9ab718c6076ec64 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Tue, 29 Oct 2024 14:23:26 -0400
Subject: [PATCH 2/8] Add copyright note and fix format

---
 flang/lib/Evaluate/wrappers.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Evaluate/wrappers.c b/flang/lib/Evaluate/wrappers.c
index b0823cac45ae4b..360d638366b466 100644
--- a/flang/lib/Evaluate/wrappers.c
+++ b/flang/lib/Evaluate/wrappers.c
@@ -1,15 +1,21 @@
+//===-- lib/Evaluate/wrappers.c -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
 #include <complex.h>
 
-void csqrtf_wrapper(const float x[2], float res[2])
-{
+void csqrtf_wrapper(const float x[2], float res[2]) {
   float complex c = x[0] + I * x[1];
   float complex r = csqrtf(c);
   res[0] = crealf(r);
   res[1] = cimagf(r);
 }
 
-void csqrt_wrapper(const double x[2], double res[2])
-{
+void csqrt_wrapper(const double x[2], double res[2]) {
   double complex c = x[0] + I * x[1];
   double complex r = csqrt(c);
   res[0] = creal(r);

>From 22151341815e1e5aa9067558f14bc206c72d5f19 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Wed, 6 Nov 2024 17:07:58 -0500
Subject: [PATCH 3/8] Fix windows build failure

---
 flang/lib/Evaluate/intrinsics-library.cpp | 18 ++++++++++--------
 flang/lib/Evaluate/wrappers.c             |  2 ++
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 8b16d187513690..66f5c582853828 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -282,9 +282,12 @@ extern "C" {
 void csqrtf_wrapper(const float[], float[]);
 void csqrt_wrapper(const double[], double[]);
 } // extern "C"
+#endif
 
 template <typename HostT>
-static std::complex<HostT> CSQRT(const std::complex<HostT> &x) {
+static std::complex<HostT> CSqrt(const std::complex<HostT> &x) {
+  std::complex<HostT> res;
+#if _AIX
   HostT y[2]{x.real(), x.imag()};
   HostT r[2];
   if constexpr (std::is_same_v<HostT, float>) {
@@ -292,10 +295,13 @@ static std::complex<HostT> CSQRT(const std::complex<HostT> &x) {
   } else if constexpr (std::is_same_v<HostT, double>) {
     csqrt_wrapper(y, r);
   }
-  std::complex<HostT> res(r[0], r[1]);
+  res.real(r[0]);
+  res.imag(r[1]);
+#else
+  res = std::sqrt(x);
+#endif
   return res;
 }
-#endif
 
 template <typename HostT>
 struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
@@ -322,11 +328,7 @@ struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
       FolderFactory<F2B, F2B{StdPowF2B}>::Create("pow"),
       FolderFactory<F, F{std::sin}>::Create("sin"),
       FolderFactory<F, F{std::sinh}>::Create("sinh"),
-#ifdef _AIX
-      FolderFactory<F, F{CSQRT}>::Create("sqrt"),
-#else
-      FolderFactory<F, F{std::sqrt}>::Create("sqrt"),
-#endif
+      FolderFactory<F, F{CSqrt}>::Create("sqrt"),
       FolderFactory<F, F{std::tan}>::Create("tan"),
       FolderFactory<F, F{std::tanh}>::Create("tanh"),
   };
diff --git a/flang/lib/Evaluate/wrappers.c b/flang/lib/Evaluate/wrappers.c
index 360d638366b466..19a681cf7db8a8 100644
--- a/flang/lib/Evaluate/wrappers.c
+++ b/flang/lib/Evaluate/wrappers.c
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#ifdef _AIX
 #include <complex.h>
 
 void csqrtf_wrapper(const float x[2], float res[2]) {
@@ -21,3 +22,4 @@ void csqrt_wrapper(const double x[2], double res[2]) {
   res[0] = creal(r);
   res[1] = cimag(r);
 }
+#endif

>From 77682f74ff5d87d4c60ffff945411714b081bac8 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 7 Nov 2024 18:42:48 -0500
Subject: [PATCH 4/8] Address review comments - remove the wrapper files -
 simplify code

---
 flang/lib/Evaluate/CMakeLists.txt         |  1 -
 flang/lib/Evaluate/intrinsics-library.cpp | 32 ++++++++++++++++-------
 flang/lib/Evaluate/wrappers.c             | 25 ------------------
 3 files changed, 22 insertions(+), 36 deletions(-)
 delete mode 100644 flang/lib/Evaluate/wrappers.c

diff --git a/flang/lib/Evaluate/CMakeLists.txt b/flang/lib/Evaluate/CMakeLists.txt
index 8ffbfc8848da74..b38f450d746ea7 100644
--- a/flang/lib/Evaluate/CMakeLists.txt
+++ b/flang/lib/Evaluate/CMakeLists.txt
@@ -58,7 +58,6 @@ add_flang_library(FortranEvaluate
   tools.cpp
   type.cpp
   variable.cpp
-  wrappers.c
 
   LINK_LIBS
   FortranCommon
diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 66f5c582853828..214dd2cf1dad40 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -278,25 +278,37 @@ static std::complex<HostT> StdPowF2B(
 }
 
 #ifdef _AIX
+#ifdef __clang_major__
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#endif
+
 extern "C" {
-void csqrtf_wrapper(const float[], float[]);
-void csqrt_wrapper(const double[], double[]);
-} // extern "C"
+float _Complex csqrtf(float _Complex);
+double _Complex csqrt(double _Complex);
+}
 #endif
 
 template <typename HostT>
 static std::complex<HostT> CSqrt(const std::complex<HostT> &x) {
   std::complex<HostT> res;
-#if _AIX
-  HostT y[2]{x.real(), x.imag()};
-  HostT r[2];
+#ifdef _AIX
   if constexpr (std::is_same_v<HostT, float>) {
-    csqrtf_wrapper(y, r);
+    float _Complex c;
+    reinterpret_cast<HostT(&)[2]>(c)[0] = x.real();
+    reinterpret_cast<HostT(&)[2]>(c)[1] = x.imag();
+    float _Complex r{csqrtf(c)};
+    res.real(reinterpret_cast<HostT(&)[2]>(r)[0]);
+    res.imag(reinterpret_cast<HostT(&)[2]>(r)[1]);
   } else if constexpr (std::is_same_v<HostT, double>) {
-    csqrt_wrapper(y, r);
+    double _Complex c;
+    reinterpret_cast<HostT(&)[2]>(c)[0] = x.real();
+    reinterpret_cast<HostT(&)[2]>(c)[1] = x.imag();
+    double _Complex r{csqrt(c)};
+    res.real(reinterpret_cast<HostT(&)[2]>(r)[0]);
+    res.imag(reinterpret_cast<HostT(&)[2]>(r)[1]);
+  } else {
+    assert("bad complex component type");
   }
-  res.real(r[0]);
-  res.imag(r[1]);
 #else
   res = std::sqrt(x);
 #endif
diff --git a/flang/lib/Evaluate/wrappers.c b/flang/lib/Evaluate/wrappers.c
deleted file mode 100644
index 19a681cf7db8a8..00000000000000
--- a/flang/lib/Evaluate/wrappers.c
+++ /dev/null
@@ -1,25 +0,0 @@
-//===-- lib/Evaluate/wrappers.c -------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifdef _AIX
-#include <complex.h>
-
-void csqrtf_wrapper(const float x[2], float res[2]) {
-  float complex c = x[0] + I * x[1];
-  float complex r = csqrtf(c);
-  res[0] = crealf(r);
-  res[1] = cimagf(r);
-}
-
-void csqrt_wrapper(const double x[2], double res[2]) {
-  double complex c = x[0] + I * x[1];
-  double complex r = csqrt(c);
-  res[0] = creal(r);
-  res[1] = cimag(r);
-}
-#endif

>From 83e3cf6ad7f52d016499206e7b5fe8872b4e95b1 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 7 Nov 2024 19:03:52 -0500
Subject: [PATCH 5/8] Use DIE

---
 flang/lib/Evaluate/intrinsics-library.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 214dd2cf1dad40..878cfca932b9eb 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -15,6 +15,7 @@
 #include "fold-implementation.h"
 #include "host.h"
 #include "flang/Common/erfc-scaled.h"
+#include "flang/Common/idioms.h"
 #include "flang/Common/static-multimap-view.h"
 #include "flang/Evaluate/expression.h"
 #include <cfloat>
@@ -307,7 +308,7 @@ static std::complex<HostT> CSqrt(const std::complex<HostT> &x) {
     res.real(reinterpret_cast<HostT(&)[2]>(r)[0]);
     res.imag(reinterpret_cast<HostT(&)[2]>(r)[1]);
   } else {
-    assert("bad complex component type");
+    DIE("bad complex component type");
   }
 #else
   res = std::sqrt(x);

>From 1b5253df9dc68bf83fb77574947aa032348bd432 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Thu, 7 Nov 2024 19:10:25 -0500
Subject: [PATCH 6/8] Add comments

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

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 878cfca932b9eb..8fe5e272ea2e82 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -293,6 +293,8 @@ 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.
   if constexpr (std::is_same_v<HostT, float>) {
     float _Complex c;
     reinterpret_cast<HostT(&)[2]>(c)[0] = x.real();

>From 612b6c12897a9d3178c047c1234170812d94f699 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Fri, 8 Nov 2024 17:27:46 -0500
Subject: [PATCH 7/8] Add cacos

---
 flang/lib/Evaluate/intrinsics-library.cpp | 57 +++++++++++++++++------
 1 file changed, 44 insertions(+), 13 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 8fe5e272ea2e82..35c643ffa801bc 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -284,9 +284,27 @@ static std::complex<HostT> StdPowF2B(
 #endif
 
 extern "C" {
+float _Complex cacosf(float _Complex);
+double _Complex cacos(double _Complex);
 float _Complex csqrtf(float _Complex);
 double _Complex csqrt(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));
+}
 #endif
 
 template <typename HostT>
@@ -296,19 +314,11 @@ static std::complex<HostT> CSqrt(const std::complex<HostT> &x) {
   // On AIX, the implementation of csqrt[f] and std::sqrt is different,
   // use csqrt[f] in folding.
   if constexpr (std::is_same_v<HostT, float>) {
-    float _Complex c;
-    reinterpret_cast<HostT(&)[2]>(c)[0] = x.real();
-    reinterpret_cast<HostT(&)[2]>(c)[1] = x.imag();
-    float _Complex r{csqrtf(c)};
-    res.real(reinterpret_cast<HostT(&)[2]>(r)[0]);
-    res.imag(reinterpret_cast<HostT(&)[2]>(r)[1]);
+    float _Complex r{csqrtf(CppToC<float _Complex, float>(x))};
+    res = CToCpp<float, float _Complex>(r);
   } else if constexpr (std::is_same_v<HostT, double>) {
-    double _Complex c;
-    reinterpret_cast<HostT(&)[2]>(c)[0] = x.real();
-    reinterpret_cast<HostT(&)[2]>(c)[1] = x.imag();
-    double _Complex r{csqrt(c)};
-    res.real(reinterpret_cast<HostT(&)[2]>(r)[0]);
-    res.imag(reinterpret_cast<HostT(&)[2]>(r)[1]);
+    double _Complex r{csqrt(CppToC<double _Complex, double>(x))};
+    res = CToCpp<double, double _Complex>(r);
   } else {
     DIE("bad complex component type");
   }
@@ -318,6 +328,27 @@ static std::complex<HostT> CSqrt(const std::complex<HostT> &x) {
   return res;
 }
 
+template <typename HostT>
+static std::complex<HostT> CAcos(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");
+  }
+#else
+  res = std::acos(x);
+#endif
+  return res;
+}
+
 template <typename HostT>
 struct HostRuntimeLibrary<std::complex<HostT>, LibraryVersion::Libm> {
   using F = FuncPointer<std::complex<HostT>, const std::complex<HostT> &>;
@@ -328,7 +359,7 @@ 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{std::acos}>::Create("acos"),
+      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"),

>From 0f07d9fa6f74f6b5801c84b5588d1d3a78b59e32 Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Fri, 8 Nov 2024 17:33:50 -0500
Subject: [PATCH 8/8] Fix format

---
 flang/lib/Evaluate/intrinsics-library.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp
index 35c643ffa801bc..45c6d1876b5500 100644
--- a/flang/lib/Evaluate/intrinsics-library.cpp
+++ b/flang/lib/Evaluate/intrinsics-library.cpp
@@ -302,8 +302,7 @@ template <typename TR, typename T> static TR CppToC(const std::complex<T> &x) {
 }
 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));
+  return std::complex<T>(reIm<T, TA>(z, CRI::Real), reIm<T, TA>(z, CRI::Imag));
 }
 #endif
 



More information about the flang-commits mailing list