[flang] Removed dynamic loading feature for intrinsic folding

After more reflexion, dynamic loading brings to much uncertainty
regarding which library is actually being use for folding.
It is removed to avoid pushing people to use it.
A static linking to libpgmath will be provided in a later commit.

Original-commit: flang-compiler/f18@2161627d28
Tree-same-pre-rewrite: false
This commit is contained in:
Jean Perier 2019-03-21 10:08:57 -07:00 committed by GitHub
parent 9ce02da63a
commit ca0261b253
4 changed files with 9 additions and 188 deletions

View File

@ -37,9 +37,3 @@ target_link_libraries(FortranEvaluate
FortranParser
m
)
IF(CMAKE_SYSTEM_NAME STREQUAL Linux)
target_link_libraries(FortranEvaluate
dl
)
endif()

View File

@ -168,12 +168,5 @@ HostIntrinsicProceduresLibrary::GetHostProcedureWrapper(
return std::nullopt;
}
template<typename TR, typename... ArgInfo>
TargetRuntimeIntrinsicProcedure::TargetRuntimeIntrinsicProcedure(
const Signature<TR, ArgInfo...> &signature, const std::string &symbolName,
bool isElemental)
: IntrinsicProcedureRuntimeDescription{signature, isElemental},
symbol{symbolName} {}
}
#endif // FORTRAN_EVALUATE_INTRINSICS_LIBRARY_TEMPLATES_H_

View File

@ -12,8 +12,8 @@
// 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.
@ -22,10 +22,6 @@
#include <cerrno>
#include <cfenv>
#include <sstream>
#if defined(__APPLE__) || defined(__unix__)
#define IS_POSIX_COMPLIANT
#include <dlfcn.h>
#endif
namespace Fortran::evaluate {
@ -55,48 +51,7 @@ bool HostIntrinsicProceduresLibrary::HasEquivalentProcedure(
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
@ -148,92 +103,9 @@ void AddLibmComplexHostProcedure(
}
}
// 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);

View File

@ -15,17 +15,13 @@
#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>
@ -62,38 +58,12 @@ struct IntrinsicProcedureRuntimeDescription {
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 {
@ -119,9 +89,7 @@ using HostProcedureWrapper = std::function<ConstantContainer<TR>(
// 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};
@ -130,18 +98,12 @@ struct HostIntrinsicProceduresLibrary {
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
};
}