// See the License for the specific language governing permissions and
// limitations under the License.
-// This file defines the runtime libraries for the target as well as a default
-// set of host rte functions that can be used for folding.
+// This file defines host runtimes functions that can be used for folding
+// intrinsic functions.
// The default HostIntrinsicProceduresLibrary is built with <cmath> and
// <complex> functions that are guaranteed to exist from the C++ standard.
#include <cerrno>
#include <cfenv>
#include <sstream>
-#if defined(__APPLE__) || defined(__unix__)
-#define IS_POSIX_COMPLIANT
-#include <dlfcn.h>
-#endif
namespace Fortran::evaluate {
return false;
}
-void HostIntrinsicProceduresLibrary::LoadTargetIntrinsicProceduresLibrary(
- const TargetIntrinsicProceduresLibrary &lib) {
- if (dynamicallyLoadedLibraries.find(lib.name) !=
- dynamicallyLoadedLibraries.end()) {
- return; // already loaded
- }
-#ifdef IS_POSIX_COMPLIANT
- void *handle = dlopen((lib.name + std::string{".so"}).c_str(), RTLD_LAZY);
- if (!handle) {
- return;
- }
- dynamicallyLoadedLibraries.insert(std::make_pair(lib.name, handle));
- for (const auto &sym : lib.procedures) {
- void *func{dlsym(handle, sym.second.symbol.c_str())};
- auto error{dlerror()};
- if (error) {
- } else {
- // Note: below is the only reinterpret_cast from an object pointer to
- // function pointer As per C++11 and later rules on reinterpret_cast, it
- // is implementation defined whether this is supported. POSIX mandates
- // that such cast from function pointers to void* are defined. Hence this
- // reinterpret_cast is and MUST REMAIN inside ifdef related to POSIX.
- AddProcedure(HostRuntimeIntrinsicProcedure{
- sym.second, reinterpret_cast<FuncPointer<void *>>(func)});
- }
- }
-#else
- // TODO: systems that do not support dlopen (e.g windows)
-#endif
-}
-
-HostIntrinsicProceduresLibrary::~HostIntrinsicProceduresLibrary() {
- for (auto iter{dynamicallyLoadedLibraries.begin()};
- iter != dynamicallyLoadedLibraries.end(); ++iter) {
-#ifdef IS_POSIX_COMPLIANT
- (void)dlclose(iter->second);
-#endif
- }
-}
-
-// Map numerical intrinsic to <cmath>/<complex> functions (for host folding
-// only)
+// Map numerical intrinsic to <cmath>/<complex> functions
// TODO mapping to <cmath> function to be tested.<cmath> func takes
// real arg for n
}
}
-// define mapping between numerical intrinsics and libpgmath symbols
-
-enum class MathOption { Fast, Precise, Relaxed };
-
-char constexpr inline EncodePgmMathOption(MathOption m) {
- switch (m) {
- case MathOption::Fast: return 'f';
- case MathOption::Precise: return 'p';
- case MathOption::Relaxed: return 'r';
- }
- return '\0'; // unreachable. Silencing bogus g++ warning
-}
-
-template<typename T> struct EncodePgmTypeHelper {};
-
-template<> struct EncodePgmTypeHelper<Type<TypeCategory::Real, 4>> {
- static constexpr char value{'s'};
-};
-template<> struct EncodePgmTypeHelper<Type<TypeCategory::Real, 8>> {
- static constexpr char value{'d'};
-};
-template<> struct EncodePgmTypeHelper<Type<TypeCategory::Complex, 4>> {
- static constexpr char value{'c'};
-};
-template<> struct EncodePgmTypeHelper<Type<TypeCategory::Complex, 8>> {
- static constexpr char value{'z'};
-};
-
-template<typename T>
-static constexpr char EncodePgmType{EncodePgmTypeHelper<T>::value};
-
-template<typename T>
-static std::string MakeLibpgmathName(const std::string &name, MathOption m) {
- std::ostringstream stream;
- stream << "__" << EncodePgmMathOption(m) << EncodePgmType<T> << "_" << name
- << "_1";
- // TODO Take mask and vector length into account
- return stream.str();
-}
-
-template<typename T>
-static void AddLibpgmathTargetSymbols(
- TargetIntrinsicProceduresLibrary &lib, MathOption opt) {
- using F = Signature<T, ArgumentInfo<T, PassBy::Val>>;
- const std::string oneArgFuncs[]{"acos", "asin", "atan", "cos", "cosh", "exp",
- "log", "log10", "sin", "sinh", "tan", "tanh"};
- for (const std::string &name : oneArgFuncs) {
- lib.AddProcedure(TargetRuntimeIntrinsicProcedure{
- F{name}, MakeLibpgmathName<T>(name, opt), true});
- }
-
- if constexpr (T::category == TypeCategory::Real) {
- using F2 = Signature<T, ArgumentInfo<T, PassBy::Val>,
- ArgumentInfo<T, PassBy::Val>>;
- lib.AddProcedure(TargetRuntimeIntrinsicProcedure{
- F2{"atan2"}, MakeLibpgmathName<T>("acos", opt), true});
- } else {
- const std::string oneArgCmplxFuncs[]{
- "div", "sqrt"}; // for scalar, only complex available
- for (const std::string &name : oneArgCmplxFuncs) {
- lib.AddProcedure(TargetRuntimeIntrinsicProcedure{
- F{name}, MakeLibpgmathName<T>(name, opt), true});
- }
- }
-}
-
-TargetIntrinsicProceduresLibrary BuildLibpgmTargetIntrinsicProceduresLibrary(
- MathOption opt) {
- TargetIntrinsicProceduresLibrary lib{"libpgmath"};
- AddLibpgmathTargetSymbols<Type<TypeCategory::Real, 4>>(lib, opt);
- AddLibpgmathTargetSymbols<Type<TypeCategory::Real, 8>>(lib, opt);
- AddLibpgmathTargetSymbols<Type<TypeCategory::Complex, 4>>(lib, opt);
- AddLibpgmathTargetSymbols<Type<TypeCategory::Complex, 8>>(lib, opt);
- return lib;
-}
-
// Defines which host runtime functions will be used for folding
void HostIntrinsicProceduresLibrary::DefaultInit() {
- // TODO: when linkage information is available, this needs to be modified to
- // load runtime accordingly. For now, try loading libpgmath (libpgmath.so
- // needs to be in a directory from LD_LIBRARY_PATH) and then add libm symbols
- // when no equivalent symbols were already loaded
- TargetIntrinsicProceduresLibrary libpgmath{
- BuildLibpgmTargetIntrinsicProceduresLibrary(MathOption::Precise)};
- LoadTargetIntrinsicProceduresLibrary(libpgmath);
AddLibmRealHostProcedure<float>(*this);
AddLibmRealHostProcedure<double>(*this);
#ifndef FORTRAN_EVALUATE_INTRINSICS_LIBRARY_H_
#define FORTRAN_EVALUATE_INTRINSICS_LIBRARY_H_
-// Defines structures to be used in F18 when dealing with the intrinsic
-// procedures runtime. It abstracts both:
-// - the target intrinsic procedure runtime to be used for code generation
-// - the host intrinsic runtime to be used for constant folding purposes.
-// To avoid unnecessary header circular dependencies, the actual implementation
-// of the templatized member function are defined in
+// Defines structures to be used in F18 for folding intrinsic function with host
+// runtime libraries. To avoid unnecessary header circular dependencies, the
+// actual implementation of the templatized member function are defined in
// intrinsics-library-templates.h The header at hand is meant to be included by
// files that need to define intrinsic runtime data structure but that do not
// use them directly. To actually use the runtime data structures,
-// intrinsics-library-templates.h must be included Note that
-// intrinsics-library-templates.h includes the header at hand.
+// intrinsics-library-templates.h must be included.
#include <functional>
#include <map>
const std::vector<PassBy> argumentsPassedBy;
const bool isElemental;
const FuncPointer<void *> callable;
- // callable only usable by HostRuntimeIntrinsicProcedure but need to be
- // created in case TargetRuntimeIntrinsicProcedure is dynamically loaded
- // because creating it dynamically would be too complex
-
// Construct from description using host independent types (RuntimeTypes)
template<typename TR, typename... ArgInfo>
IntrinsicProcedureRuntimeDescription(
const Signature<TR, ArgInfo...> &signature, bool isElemental = false);
};
-// TargetRuntimeIntrinsicProcedure holds target runtime information
-// for an intrinsics procedure.
-struct TargetRuntimeIntrinsicProcedure : IntrinsicProcedureRuntimeDescription {
- // Construct from description using host independent types (RuntimeTypes)
- // Note: passing ref/val also needs to be passed by template to build
- // the callable
- template<typename TR, typename... ArgInfo>
- TargetRuntimeIntrinsicProcedure(const Signature<TR, ArgInfo...> &signature,
- const std::string &symbolName, bool isElemental = false);
- const std::string symbol;
-};
-
-struct TargetIntrinsicProceduresLibrary {
- TargetIntrinsicProceduresLibrary(const std::string &name) : name{name} {}
- void AddProcedure(TargetRuntimeIntrinsicProcedure &&sym) {
- const std::string name{sym.name};
- procedures.insert(std::make_pair(name, std::move(sym)));
- }
- const std::string name;
- std::multimap<std::string, const TargetRuntimeIntrinsicProcedure> procedures;
-};
-
// HostRuntimeIntrinsicProcedure allows host runtime function to be called for
// constant folding.
struct HostRuntimeIntrinsicProcedure : IntrinsicProcedureRuntimeDescription {
// HostRuntimeIntrinsicProcedure elements. It is meant for constant folding.
// When queried for an intrinsic procedure, it can return a callable object that
// implements this intrinsic if a host runtime function pointer for this
-// intrinsic was added to its data structure. It can also dynamically load
-// function pointer from a TargetIntrinsicProceduresLibrary if the related
-// library is available on the host.
+// intrinsic was added to its data structure.
struct HostIntrinsicProceduresLibrary {
void AddProcedure(HostRuntimeIntrinsicProcedure &&sym) {
const std::string name{sym.name};
bool HasEquivalentProcedure(
const IntrinsicProcedureRuntimeDescription &sym) const;
HostIntrinsicProceduresLibrary() { DefaultInit(); }
- ~HostIntrinsicProceduresLibrary();
- void DefaultInit(); // Try loading libpgmath functions and then load
- // functions from <cmath> and <complex>
- void LoadTargetIntrinsicProceduresLibrary(
- const TargetIntrinsicProceduresLibrary &lib);
+ void DefaultInit();
template<template<typename> typename ConstantContainer, typename TR,
typename... TA>
std::optional<HostProcedureWrapper<ConstantContainer, TR, TA...>>
GetHostProcedureWrapper(const std::string &name);
std::multimap<std::string, const HostRuntimeIntrinsicProcedure> procedures;
- std::map<std::string, void *>
- dynamicallyLoadedLibraries; // keep the handles for dlclose
};
}