diff --git a/flang/lib/Evaluate/intrinsics-library.cpp b/flang/lib/Evaluate/intrinsics-library.cpp index c1b270f518c0e..d2c1be65dca44 100644 --- a/flang/lib/Evaluate/intrinsics-library.cpp +++ b/flang/lib/Evaluate/intrinsics-library.cpp @@ -260,6 +260,16 @@ struct HostRuntimeLibrary { static_assert(map.Verify(), "map must be sorted"); }; +#define COMPLEX_SIGNATURES(HOST_T) \ + using F = FuncPointer, const std::complex &>; \ + using F2 = FuncPointer, const std::complex &, \ + const std::complex &>; \ + using F2A = FuncPointer, const HOST_T &, \ + const std::complex &>; \ + using F2B = FuncPointer, const std::complex &, \ + const HOST_T &>; + +#ifndef _AIX // Helpers to map complex std::pow whose resolution in F2{std::pow} is // ambiguous as of clang++ 20. template @@ -267,98 +277,24 @@ static std::complex StdPowF2( const std::complex &x, const std::complex &y) { return std::pow(x, y); } + template static std::complex StdPowF2A( const HostT &x, const std::complex &y) { return std::pow(x, y); } + template static std::complex StdPowF2B( const std::complex &x, const HostT &y) { return std::pow(x, y); } -#ifdef _AIX -#ifdef __clang_major__ -#pragma clang diagnostic ignored "-Wc99-extensions" -#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 static TR &reIm(TA &x, CRI n) { - return reinterpret_cast(x)[n]; -} -template static TR CppToC(const std::complex &x) { - TR r; - reIm(r, CRI::Real) = x.real(); - reIm(r, CRI::Imag) = x.imag(); - return r; -} -template static std::complex CToCpp(const TA &x) { - TA &z{const_cast(x)}; - return std::complex(reIm(z, CRI::Real), reIm(z, CRI::Imag)); -} -#endif - -template -static std::complex CSqrt(const std::complex &x) { - std::complex 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) { - float _Complex r{csqrtf(CppToC(x))}; - res = CToCpp(r); - } else if constexpr (std::is_same_v) { - double _Complex r{csqrt(CppToC(x))}; - res = CToCpp(r); - } else { - DIE("bad complex component type"); - } -#else - res = std::sqrt(x); -#endif - return res; -} - -template -static std::complex CAcos(const std::complex &x) { - std::complex 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) { - float _Complex r{cacosf(CppToC(x))}; - res = CToCpp(r); - } else if constexpr (std::is_same_v) { - double _Complex r{cacos(CppToC(x))}; - res = CToCpp(r); - } else { - DIE("bad complex component type"); - } -#else - res = std::acos(x); -#endif - return res; -} - template struct HostRuntimeLibrary, LibraryVersion::Libm> { - using F = FuncPointer, const std::complex &>; - using F2 = FuncPointer, const std::complex &, - const std::complex &>; - using F2A = FuncPointer, const HostT &, - const std::complex &>; - using F2B = FuncPointer, const std::complex &, - const HostT &>; + COMPLEX_SIGNATURES(HostT) static constexpr HostRuntimeFunction table[]{ - FolderFactory::Create("acos"), + FolderFactory::Create("acos"), FolderFactory::Create("acosh"), FolderFactory::Create("asin"), FolderFactory::Create("asinh"), @@ -373,13 +309,129 @@ struct HostRuntimeLibrary, LibraryVersion::Libm> { FolderFactory::Create("pow"), FolderFactory::Create("sin"), FolderFactory::Create("sinh"), - FolderFactory::Create("sqrt"), + FolderFactory::Create("sqrt"), FolderFactory::Create("tan"), FolderFactory::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 + +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 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); +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); +} + +template struct ToStdComplex { + using Type = T; + using AType = Type; +}; +template <> struct ToStdComplex { + using Type = std::complex; + using AType = const Type &; +}; +template <> struct ToStdComplex { + using Type = std::complex; + using AType = const Type &; +}; + +template struct CComplexFunc {}; +template func> +struct CComplexFunc, func> { + static typename ToStdComplex::Type wrapper( + typename ToStdComplex::AType... args) { + R res{func(*reinterpret_cast(&args)...)}; + return *reinterpret_cast::Type *>(&res); + } +}; +#define C_COMPLEX_FUNC(func) CComplexFunc::wrapper + +template <> +struct HostRuntimeLibrary, LibraryVersion::Libm> { + COMPLEX_SIGNATURES(float) + static constexpr HostRuntimeFunction table[]{ + FolderFactory::Create("acos"), + FolderFactory::Create("acosh"), + FolderFactory::Create("asin"), + FolderFactory::Create("asinh"), + FolderFactory::Create("atan"), + FolderFactory::Create("atanh"), + FolderFactory::Create("cos"), + FolderFactory::Create("cosh"), + FolderFactory::Create("exp"), + FolderFactory::Create("log"), + FolderFactory::Create("pow"), + FolderFactory::Create("sin"), + FolderFactory::Create("sinh"), + FolderFactory::Create("sqrt"), + FolderFactory::Create("tan"), + FolderFactory::Create("tanh"), + }; + static constexpr HostRuntimeMap map{table}; + static_assert(map.Verify(), "map must be sorted"); +}; +template <> +struct HostRuntimeLibrary, LibraryVersion::Libm> { + COMPLEX_SIGNATURES(double) + static constexpr HostRuntimeFunction table[]{ + FolderFactory::Create("acos"), + FolderFactory::Create("acosh"), + FolderFactory::Create("asin"), + FolderFactory::Create("asinh"), + FolderFactory::Create("atan"), + FolderFactory::Create("atanh"), + FolderFactory::Create("cos"), + FolderFactory::Create("cosh"), + FolderFactory::Create("exp"), + FolderFactory::Create("log"), + FolderFactory::Create("pow"), + FolderFactory::Create("sin"), + FolderFactory::Create("sinh"), + FolderFactory::Create("sqrt"), + FolderFactory::Create("tan"), + FolderFactory::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