forked from OSchip/llvm-project
[flang] renaming to focus scope on intrinsic runtime
Original-commit: flang-compiler/f18@7cfd33b178 Tree-same-pre-rewrite: false
This commit is contained in:
parent
fa3a179fec
commit
8d032dc96b
|
@ -29,7 +29,7 @@ add_library(FortranEvaluate
|
||||||
tools.cc
|
tools.cc
|
||||||
type.cc
|
type.cc
|
||||||
variable.cc
|
variable.cc
|
||||||
rte.cc
|
intrinsics-library.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(FortranEvaluate
|
target_link_libraries(FortranEvaluate
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#ifndef FORTRAN_EVALUATE_COMMON_H_
|
#ifndef FORTRAN_EVALUATE_COMMON_H_
|
||||||
#define FORTRAN_EVALUATE_COMMON_H_
|
#define FORTRAN_EVALUATE_COMMON_H_
|
||||||
|
|
||||||
|
#include "intrinsics-library.h"
|
||||||
#include "../common/Fortran.h"
|
#include "../common/Fortran.h"
|
||||||
#include "../common/enum-set.h"
|
#include "../common/enum-set.h"
|
||||||
#include "../common/idioms.h"
|
#include "../common/idioms.h"
|
||||||
|
@ -22,7 +23,6 @@
|
||||||
#include "../common/restorer.h"
|
#include "../common/restorer.h"
|
||||||
#include "../parser/char-block.h"
|
#include "../parser/char-block.h"
|
||||||
#include "../parser/message.h"
|
#include "../parser/message.h"
|
||||||
#include "rte-interface.h"
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
@ -219,7 +219,9 @@ public:
|
||||||
bool flushSubnormalsToZero() const { return flushSubnormalsToZero_; }
|
bool flushSubnormalsToZero() const { return flushSubnormalsToZero_; }
|
||||||
bool bigEndian() const { return bigEndian_; }
|
bool bigEndian() const { return bigEndian_; }
|
||||||
const semantics::DerivedTypeSpec *pdtInstance() const { return pdtInstance_; }
|
const semantics::DerivedTypeSpec *pdtInstance() const { return pdtInstance_; }
|
||||||
rte::HostRte &hostRte() { return hostRte_; }
|
HostIntrinsicProceduresLibrary &hostIntrinsicsLibrary() {
|
||||||
|
return hostIntrinsicsLibrary_;
|
||||||
|
}
|
||||||
|
|
||||||
std::int64_t &StartImpliedDo(parser::CharBlock, std::int64_t = 1);
|
std::int64_t &StartImpliedDo(parser::CharBlock, std::int64_t = 1);
|
||||||
std::optional<std::int64_t> GetImpliedDo(parser::CharBlock) const;
|
std::optional<std::int64_t> GetImpliedDo(parser::CharBlock) const;
|
||||||
|
@ -241,7 +243,7 @@ private:
|
||||||
bool bigEndian_{false};
|
bool bigEndian_{false};
|
||||||
const semantics::DerivedTypeSpec *pdtInstance_{nullptr};
|
const semantics::DerivedTypeSpec *pdtInstance_{nullptr};
|
||||||
std::map<parser::CharBlock, std::int64_t> impliedDos_;
|
std::map<parser::CharBlock, std::int64_t> impliedDos_;
|
||||||
rte::HostRte hostRte_;
|
HostIntrinsicProceduresLibrary hostIntrinsicsLibrary_;
|
||||||
};
|
};
|
||||||
|
|
||||||
void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op);
|
void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include "expression.h"
|
#include "expression.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "int-power.h"
|
#include "int-power.h"
|
||||||
#include "rte.h"
|
#include "intrinsics-library-templates.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "traversal.h"
|
#include "traversal.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
|
@ -331,8 +331,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
|
||||||
const std::string name{intrinsic->name};
|
const std::string name{intrinsic->name};
|
||||||
if (name == "acos" || name == "acosh" ||
|
if (name == "acos" || name == "acosh" ||
|
||||||
(name == "atan" && funcRef.arguments().size() == 1)) {
|
(name == "atan" && funcRef.arguments().size() == 1)) {
|
||||||
if (auto callable{
|
if (auto callable{context.hostIntrinsicsLibrary()
|
||||||
context.hostRte().GetHostProcedureWrapper<Scalar, T, T>(name)}) {
|
.GetHostProcedureWrapper<Scalar, T, T>(name)}) {
|
||||||
return FoldElementalIntrinsic<T, T>(
|
return FoldElementalIntrinsic<T, T>(
|
||||||
context, std::move(funcRef), *callable);
|
context, std::move(funcRef), *callable);
|
||||||
} else {
|
} else {
|
||||||
|
@ -342,9 +342,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (name == "atan") {
|
if (name == "atan") {
|
||||||
if (auto callable{
|
if (auto callable{context.hostIntrinsicsLibrary()
|
||||||
context.hostRte().GetHostProcedureWrapper<Scalar, T, T, T>(
|
.GetHostProcedureWrapper<Scalar, T, T, T>(name)}) {
|
||||||
name)}) {
|
|
||||||
return FoldElementalIntrinsic<T, T, T>(
|
return FoldElementalIntrinsic<T, T, T>(
|
||||||
context, std::move(funcRef), *callable);
|
context, std::move(funcRef), *callable);
|
||||||
} else {
|
} else {
|
||||||
|
@ -361,8 +360,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
|
||||||
Fold(context, ConvertToType<Int8>(std::move(*n)));
|
Fold(context, ConvertToType<Int8>(std::move(*n)));
|
||||||
}
|
}
|
||||||
if (auto callable{
|
if (auto callable{
|
||||||
context.hostRte().GetHostProcedureWrapper<Scalar, T, Int8, T>(
|
context.hostIntrinsicsLibrary()
|
||||||
name)}) {
|
.GetHostProcedureWrapper<Scalar, T, Int8, T>(name)}) {
|
||||||
return FoldElementalIntrinsic<T, Int8, T>(
|
return FoldElementalIntrinsic<T, Int8, T>(
|
||||||
context, std::move(funcRef), *callable);
|
context, std::move(funcRef), *callable);
|
||||||
} else {
|
} else {
|
||||||
|
@ -423,8 +422,8 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldOperation(FoldingContext &context,
|
||||||
const std::string name{intrinsic->name};
|
const std::string name{intrinsic->name};
|
||||||
if (name == "acos" || name == "acosh" || name == "asin" || name == "atan" ||
|
if (name == "acos" || name == "acosh" || name == "asin" || name == "atan" ||
|
||||||
name == "atanh") {
|
name == "atanh") {
|
||||||
if (auto callable{
|
if (auto callable{context.hostIntrinsicsLibrary()
|
||||||
context.hostRte().GetHostProcedureWrapper<Scalar, T, T>(name)}) {
|
.GetHostProcedureWrapper<Scalar, T, T>(name)}) {
|
||||||
return FoldElementalIntrinsic<T, T>(
|
return FoldElementalIntrinsic<T, T>(
|
||||||
context, std::move(funcRef), *callable);
|
context, std::move(funcRef), *callable);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -12,18 +12,18 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#ifndef FORTRAN_EVALUATE_RTE_H_
|
#ifndef FORTRAN_EVALUATE_INTRINSICS_LIBRARY_TEMPLATES_H_
|
||||||
#define FORTRAN_EVALUATE_RTE_H_
|
#define FORTRAN_EVALUATE_INTRINSICS_LIBRARY_TEMPLATES_H_
|
||||||
|
|
||||||
// This header defines the actual implementation of the templatized member
|
// This header defines the actual implementation of the templatized member
|
||||||
// function of the structures defined in rte-interface.h. It should only be
|
// function of the structures defined in intrinsics-library.h. It should only be
|
||||||
// included if these member functions are used, else rte-interface.h is
|
// included if these member functions are used, else intrinsics-library.h is
|
||||||
// sufficient. This is to avoid circular dependencies. The below implementation
|
// sufficient. This is to avoid circular dependencies. The below implementation
|
||||||
// cannot be defined in .cc file because it would be too cumbersome to decide
|
// cannot be defined in .cc file because it would be too cumbersome to decide
|
||||||
// which version should be instantiated in a generic way.
|
// which version should be instantiated in a generic way.
|
||||||
|
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "rte-interface.h"
|
#include "intrinsics-library.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
#include "../common/template.h"
|
#include "../common/template.h"
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Fortran::evaluate::rte {
|
namespace Fortran::evaluate {
|
||||||
|
|
||||||
// Define meaningful types for the runtime
|
// Define meaningful types for the runtime
|
||||||
// TODO: add the support for void and descriptor
|
// TODO: add the support for void and descriptor
|
||||||
using RteTypes = evaluate::AllIntrinsicTypes;
|
using RuntimeTypes = evaluate::AllIntrinsicTypes;
|
||||||
|
|
||||||
template<typename T, typename... TT> struct IndexInTupleHelper {};
|
template<typename T, typename... TT> struct IndexInTupleHelper {};
|
||||||
template<typename T, typename... TT>
|
template<typename T, typename... TT>
|
||||||
|
@ -44,12 +44,14 @@ struct IndexInTupleHelper<T, std::tuple<TT...>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
std::tuple_size_v<RteTypes> < std::numeric_limits<TypeCode>::max(),
|
std::tuple_size_v<RuntimeTypes> < std::numeric_limits<TypeCode>::max(),
|
||||||
"TypeCode is too small");
|
"TypeCode is too small");
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline constexpr TypeCode typeCodeOf{IndexInTupleHelper<T, RteTypes>::value};
|
inline constexpr TypeCode typeCodeOf{
|
||||||
|
IndexInTupleHelper<T, RuntimeTypes>::value};
|
||||||
|
|
||||||
template<TypeCode n> using TypeOf = typename std::tuple_element_t<n, RteTypes>;
|
template<TypeCode n>
|
||||||
|
using RuntimeTypeOf = typename std::tuple_element_t<n, RuntimeTypes>;
|
||||||
|
|
||||||
template<typename TA, PassBy Pass>
|
template<typename TA, PassBy Pass>
|
||||||
using HostArgType = std::conditional_t<Pass == PassBy::Ref,
|
using HostArgType = std::conditional_t<Pass == PassBy::Ref,
|
||||||
|
@ -84,7 +86,7 @@ template<typename TR, typename... ArgInfo> struct CallableHostWrapper {
|
||||||
hostFPE.CheckAndRestoreFloatingPointEnvironment(context);
|
hostFPE.CheckAndRestoreFloatingPointEnvironment(context);
|
||||||
return host::CastHostToFortran<TR>(res);
|
return host::CastHostToFortran<TR>(res);
|
||||||
} else {
|
} else {
|
||||||
common::die("Internal error: Host does not supports rte functions types. "
|
common::die("Internal error: Host does not supports this function types."
|
||||||
"This should not have been called for folding");
|
"This should not have been called for folding");
|
||||||
return Scalar<TR>{}; // unreachable
|
return Scalar<TR>{}; // unreachable
|
||||||
}
|
}
|
||||||
|
@ -93,7 +95,7 @@ template<typename TR, typename... ArgInfo> struct CallableHostWrapper {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TR, typename... ArgInfo>
|
template<typename TR, typename... ArgInfo>
|
||||||
RteProcedureSymbol::RteProcedureSymbol(
|
IntrinsicProcedureRuntimeDescription::IntrinsicProcedureRuntimeDescription(
|
||||||
const Signature<TR, ArgInfo...> &signature, bool isElemental)
|
const Signature<TR, ArgInfo...> &signature, bool isElemental)
|
||||||
: name{signature.name}, returnType{typeCodeOf<TR>},
|
: name{signature.name}, returnType{typeCodeOf<TR>},
|
||||||
argumentsType{typeCodeOf<typename ArgInfo::Type>...},
|
argumentsType{typeCodeOf<typename ArgInfo::Type>...},
|
||||||
|
@ -119,16 +121,18 @@ using SignatureFromHostFuncPointer =
|
||||||
Signature<host::FortranType<HostTR>, ArgInfoFromHostType<HostTA>...>;
|
Signature<host::FortranType<HostTR>, ArgInfoFromHostType<HostTA>...>;
|
||||||
|
|
||||||
template<typename HostTR, typename... HostTA>
|
template<typename HostTR, typename... HostTA>
|
||||||
HostRteProcedureSymbol::HostRteProcedureSymbol(const std::string &name,
|
HostRuntimeIntrinsicProcedure::HostRuntimeIntrinsicProcedure(
|
||||||
FuncPointer<HostTR, HostTA...> func, bool isElemental)
|
const std::string &name, FuncPointer<HostTR, HostTA...> func,
|
||||||
: RteProcedureSymbol(
|
bool isElemental)
|
||||||
|
: IntrinsicProcedureRuntimeDescription(
|
||||||
SignatureFromHostFuncPointer<HostTR, HostTA...>{name}, isElemental),
|
SignatureFromHostFuncPointer<HostTR, HostTA...>{name}, isElemental),
|
||||||
handle{reinterpret_cast<FuncPointer<void *>>(func)} {}
|
handle{reinterpret_cast<FuncPointer<void *>>(func)} {}
|
||||||
|
|
||||||
template<template<typename> typename ConstantContainer, typename TR,
|
template<template<typename> typename ConstantContainer, typename TR,
|
||||||
typename... TA>
|
typename... TA>
|
||||||
std::optional<HostProcedureWrapper<ConstantContainer, TR, TA...>>
|
std::optional<HostProcedureWrapper<ConstantContainer, TR, TA...>>
|
||||||
HostRte::GetHostProcedureWrapper(const std::string &name) {
|
HostIntrinsicProceduresLibrary::GetHostProcedureWrapper(
|
||||||
|
const std::string &name) {
|
||||||
if constexpr (host::HostTypeExists<TR, TA...>()) {
|
if constexpr (host::HostTypeExists<TR, TA...>()) {
|
||||||
auto rteProcRange{procedures.equal_range(name)};
|
auto rteProcRange{procedures.equal_range(name)};
|
||||||
const TypeCode resTypeCode{typeCodeOf<TR>};
|
const TypeCode resTypeCode{typeCodeOf<TR>};
|
||||||
|
@ -165,10 +169,11 @@ HostRte::GetHostProcedureWrapper(const std::string &name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TR, typename... ArgInfo>
|
template<typename TR, typename... ArgInfo>
|
||||||
TargetRteProcedureSymbol::TargetRteProcedureSymbol(
|
TargetRuntimeIntrinsicProcedure::TargetRuntimeIntrinsicProcedure(
|
||||||
const Signature<TR, ArgInfo...> &signature, const std::string &symbolName,
|
const Signature<TR, ArgInfo...> &signature, const std::string &symbolName,
|
||||||
bool isElemental)
|
bool isElemental)
|
||||||
: RteProcedureSymbol{signature, isElemental}, symbol{symbolName} {}
|
: IntrinsicProcedureRuntimeDescription{signature, isElemental},
|
||||||
|
symbol{symbolName} {}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif // FORTRAN_EVALUATE_RTE_H_
|
#endif // FORTRAN_EVALUATE_INTRINSICS_LIBRARY_TEMPLATES_H_
|
|
@ -14,10 +14,10 @@
|
||||||
|
|
||||||
// This file defines the runtime libraries for the target as well as a default
|
// 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.
|
// set of host rte functions that can be used for folding.
|
||||||
// The default HostRte is built with <cmath> and <complex> functions
|
// The default HostIntrinsicProceduresLibrary is built with <cmath> and
|
||||||
// that are guaranteed to exist from the C++ standard.
|
// <complex> functions that are guaranteed to exist from the C++ standard.
|
||||||
|
|
||||||
#include "rte.h"
|
#include "intrinsics-library-templates.h"
|
||||||
#include "../common/idioms.h"
|
#include "../common/idioms.h"
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cfenv>
|
#include <cfenv>
|
||||||
|
@ -27,11 +27,12 @@
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Fortran::evaluate::rte {
|
namespace Fortran::evaluate {
|
||||||
|
|
||||||
using namespace Fortran::parser::literals;
|
using namespace Fortran::parser::literals;
|
||||||
// Note: argument passing is ignored in equivalence
|
// Note: argument passing is ignored in equivalence
|
||||||
bool HostRte::HasEquivalentProcedure(const RteProcedureSymbol &sym) const {
|
bool HostIntrinsicProceduresLibrary::HasEquivalentProcedure(
|
||||||
|
const IntrinsicProcedureRuntimeDescription &sym) const {
|
||||||
const auto rteProcRange{procedures.equal_range(sym.name)};
|
const auto rteProcRange{procedures.equal_range(sym.name)};
|
||||||
const size_t nargs{sym.argumentsType.size()};
|
const size_t nargs{sym.argumentsType.size()};
|
||||||
for (auto iter{rteProcRange.first}; iter != rteProcRange.second; ++iter) {
|
for (auto iter{rteProcRange.first}; iter != rteProcRange.second; ++iter) {
|
||||||
|
@ -54,7 +55,8 @@ bool HostRte::HasEquivalentProcedure(const RteProcedureSymbol &sym) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
|
void HostIntrinsicProceduresLibrary::LoadTargetIntrinsicProceduresLibrary(
|
||||||
|
const TargetIntrinsicProceduresLibrary &lib) {
|
||||||
if (dynamicallyLoadedLibraries.find(lib.name) !=
|
if (dynamicallyLoadedLibraries.find(lib.name) !=
|
||||||
dynamicallyLoadedLibraries.end()) {
|
dynamicallyLoadedLibraries.end()) {
|
||||||
return; // already loaded
|
return; // already loaded
|
||||||
|
@ -75,7 +77,7 @@ void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
|
||||||
// is implementation defined whether this is supported. POSIX mandates
|
// is implementation defined whether this is supported. POSIX mandates
|
||||||
// that such cast from function pointers to void* are defined. Hence this
|
// that such cast from function pointers to void* are defined. Hence this
|
||||||
// reinterpret_cast is and MUST REMAIN inside ifdef related to POSIX.
|
// reinterpret_cast is and MUST REMAIN inside ifdef related to POSIX.
|
||||||
AddProcedure(HostRteProcedureSymbol{
|
AddProcedure(HostRuntimeIntrinsicProcedure{
|
||||||
sym.second, reinterpret_cast<FuncPointer<void *>>(func)});
|
sym.second, reinterpret_cast<FuncPointer<void *>>(func)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +86,7 @@ void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
HostRte::~HostRte() {
|
HostIntrinsicProceduresLibrary::~HostIntrinsicProceduresLibrary() {
|
||||||
for (auto iter{dynamicallyLoadedLibraries.begin()};
|
for (auto iter{dynamicallyLoadedLibraries.begin()};
|
||||||
iter != dynamicallyLoadedLibraries.end(); ++iter) {
|
iter != dynamicallyLoadedLibraries.end(); ++iter) {
|
||||||
#ifdef IS_POSIX_COMPLIANT
|
#ifdef IS_POSIX_COMPLIANT
|
||||||
|
@ -105,10 +107,12 @@ template<typename HostT> static HostT Bessel_yn(std::int64_t n, HostT x) {
|
||||||
return std::cyl_neumann(static_cast<HostT>(n), x);
|
return std::cyl_neumann(static_cast<HostT>(n), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename HostT> void AddLibmRealHostProcedure(HostRte &hostRte) {
|
template<typename HostT>
|
||||||
|
void AddLibmRealHostProcedure(
|
||||||
|
HostIntrinsicProceduresLibrary &hostIntrinsicLibrary) {
|
||||||
using F = FuncPointer<HostT, HostT>;
|
using F = FuncPointer<HostT, HostT>;
|
||||||
using F2 = FuncPointer<HostT, HostT, HostT>;
|
using F2 = FuncPointer<HostT, HostT, HostT>;
|
||||||
HostRteProcedureSymbol libmSymbols[]{{"acos", F{std::acos}, true},
|
HostRuntimeIntrinsicProcedure libmSymbols[]{{"acos", F{std::acos}, true},
|
||||||
{"acosh", F{std::acosh}, true}, {"asin", F{std::asin}, true},
|
{"acosh", F{std::acosh}, true}, {"asin", F{std::asin}, true},
|
||||||
{"asinh", F{std::asinh}, true}, {"atan", F{std::atan}, true},
|
{"asinh", F{std::asinh}, true}, {"atan", F{std::atan}, true},
|
||||||
{"atan", F2{std::atan2}, true}, {"atanh", F{std::atanh}, true},
|
{"atan", F2{std::atan2}, true}, {"atanh", F{std::atanh}, true},
|
||||||
|
@ -119,15 +123,17 @@ template<typename HostT> void AddLibmRealHostProcedure(HostRte &hostRte) {
|
||||||
{"tan", F{std::tan}, true}, {"tanh", F{std::tanh}, true}};
|
{"tan", F{std::tan}, true}, {"tanh", F{std::tanh}, true}};
|
||||||
|
|
||||||
for (auto sym : libmSymbols) {
|
for (auto sym : libmSymbols) {
|
||||||
if (!hostRte.HasEquivalentProcedure(sym)) {
|
if (!hostIntrinsicLibrary.HasEquivalentProcedure(sym)) {
|
||||||
hostRte.AddProcedure(std::move(sym));
|
hostIntrinsicLibrary.AddProcedure(std::move(sym));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename HostT> void AddLibmComplexHostProcedure(HostRte &hostRte) {
|
template<typename HostT>
|
||||||
|
void AddLibmComplexHostProcedure(
|
||||||
|
HostIntrinsicProceduresLibrary &hostIntrinsicLibrary) {
|
||||||
using F = FuncPointer<std::complex<HostT>, const std::complex<HostT> &>;
|
using F = FuncPointer<std::complex<HostT>, const std::complex<HostT> &>;
|
||||||
HostRteProcedureSymbol libmSymbols[]{{"acos", F{std::acos}, true},
|
HostRuntimeIntrinsicProcedure libmSymbols[]{{"acos", F{std::acos}, true},
|
||||||
{"acosh", F{std::acosh}, true}, {"asin", F{std::asin}, true},
|
{"acosh", F{std::acosh}, true}, {"asin", F{std::asin}, true},
|
||||||
{"asinh", F{std::asinh}, true}, {"atan", F{std::atan}, true},
|
{"asinh", F{std::asinh}, true}, {"atan", F{std::atan}, true},
|
||||||
{"atanh", F{std::atanh}, true}, {"cos", F{std::cos}, true},
|
{"atanh", F{std::atanh}, true}, {"cos", F{std::cos}, true},
|
||||||
|
@ -136,8 +142,8 @@ template<typename HostT> void AddLibmComplexHostProcedure(HostRte &hostRte) {
|
||||||
{"tan", F{std::tan}, true}, {"tanh", F{std::tanh}, true}};
|
{"tan", F{std::tan}, true}, {"tanh", F{std::tanh}, true}};
|
||||||
|
|
||||||
for (auto sym : libmSymbols) {
|
for (auto sym : libmSymbols) {
|
||||||
if (!hostRte.HasEquivalentProcedure(sym)) {
|
if (!hostIntrinsicLibrary.HasEquivalentProcedure(sym)) {
|
||||||
hostRte.AddProcedure(std::move(sym));
|
hostIntrinsicLibrary.AddProcedure(std::move(sym));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,32 +189,34 @@ static std::string MakeLibpgmathName(const std::string &name, MathOption m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void AddLibpgmathTargetSymbols(TargetRteLibrary &lib, MathOption opt) {
|
static void AddLibpgmathTargetSymbols(
|
||||||
|
TargetIntrinsicProceduresLibrary &lib, MathOption opt) {
|
||||||
using F = Signature<T, ArgumentInfo<T, PassBy::Val>>;
|
using F = Signature<T, ArgumentInfo<T, PassBy::Val>>;
|
||||||
const std::string oneArgFuncs[]{"acos", "asin", "atan", "cos", "cosh", "exp",
|
const std::string oneArgFuncs[]{"acos", "asin", "atan", "cos", "cosh", "exp",
|
||||||
"log", "log10", "sin", "sinh", "tan", "tanh"};
|
"log", "log10", "sin", "sinh", "tan", "tanh"};
|
||||||
for (const std::string &name : oneArgFuncs) {
|
for (const std::string &name : oneArgFuncs) {
|
||||||
lib.AddProcedure(TargetRteProcedureSymbol{
|
lib.AddProcedure(TargetRuntimeIntrinsicProcedure{
|
||||||
F{name}, MakeLibpgmathName<T>(name, opt), true});
|
F{name}, MakeLibpgmathName<T>(name, opt), true});
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (T::category == TypeCategory::Real) {
|
if constexpr (T::category == TypeCategory::Real) {
|
||||||
using F2 = Signature<T, ArgumentInfo<T, PassBy::Val>,
|
using F2 = Signature<T, ArgumentInfo<T, PassBy::Val>,
|
||||||
ArgumentInfo<T, PassBy::Val>>;
|
ArgumentInfo<T, PassBy::Val>>;
|
||||||
lib.AddProcedure(TargetRteProcedureSymbol{
|
lib.AddProcedure(TargetRuntimeIntrinsicProcedure{
|
||||||
F2{"atan2"}, MakeLibpgmathName<T>("acos", opt), true});
|
F2{"atan2"}, MakeLibpgmathName<T>("acos", opt), true});
|
||||||
} else {
|
} else {
|
||||||
const std::string oneArgCmplxFuncs[]{
|
const std::string oneArgCmplxFuncs[]{
|
||||||
"div", "sqrt"}; // for scalar, only complex available
|
"div", "sqrt"}; // for scalar, only complex available
|
||||||
for (const std::string &name : oneArgCmplxFuncs) {
|
for (const std::string &name : oneArgCmplxFuncs) {
|
||||||
lib.AddProcedure(TargetRteProcedureSymbol{
|
lib.AddProcedure(TargetRuntimeIntrinsicProcedure{
|
||||||
F{name}, MakeLibpgmathName<T>(name, opt), true});
|
F{name}, MakeLibpgmathName<T>(name, opt), true});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetRteLibrary BuildLibpgmTargetRteLibrary(MathOption opt) {
|
TargetIntrinsicProceduresLibrary BuildLibpgmTargetIntrinsicProceduresLibrary(
|
||||||
TargetRteLibrary lib{"libpgmath"};
|
MathOption opt) {
|
||||||
|
TargetIntrinsicProceduresLibrary lib{"libpgmath"};
|
||||||
AddLibpgmathTargetSymbols<Type<TypeCategory::Real, 4>>(lib, opt);
|
AddLibpgmathTargetSymbols<Type<TypeCategory::Real, 4>>(lib, opt);
|
||||||
AddLibpgmathTargetSymbols<Type<TypeCategory::Real, 8>>(lib, opt);
|
AddLibpgmathTargetSymbols<Type<TypeCategory::Real, 8>>(lib, opt);
|
||||||
AddLibpgmathTargetSymbols<Type<TypeCategory::Complex, 4>>(lib, opt);
|
AddLibpgmathTargetSymbols<Type<TypeCategory::Complex, 4>>(lib, opt);
|
||||||
|
@ -218,13 +226,14 @@ TargetRteLibrary BuildLibpgmTargetRteLibrary(MathOption opt) {
|
||||||
|
|
||||||
// Defines which host runtime functions will be used for folding
|
// Defines which host runtime functions will be used for folding
|
||||||
|
|
||||||
void HostRte::DefaultInit() {
|
void HostIntrinsicProceduresLibrary::DefaultInit() {
|
||||||
// TODO: when linkage information is available, this needs to be modified to
|
// TODO: when linkage information is available, this needs to be modified to
|
||||||
// load runtime accordingly. For now, try loading libpgmath (libpgmath.so
|
// 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
|
// needs to be in a directory from LD_LIBRARY_PATH) and then add libm symbols
|
||||||
// when no equivalent symbols were already loaded
|
// when no equivalent symbols were already loaded
|
||||||
TargetRteLibrary libpgmath{BuildLibpgmTargetRteLibrary(MathOption::Precise)};
|
TargetIntrinsicProceduresLibrary libpgmath{
|
||||||
LoadTargetRteLibrary(libpgmath);
|
BuildLibpgmTargetIntrinsicProceduresLibrary(MathOption::Precise)};
|
||||||
|
LoadTargetIntrinsicProceduresLibrary(libpgmath);
|
||||||
|
|
||||||
AddLibmRealHostProcedure<float>(*this);
|
AddLibmRealHostProcedure<float>(*this);
|
||||||
AddLibmRealHostProcedure<double>(*this);
|
AddLibmRealHostProcedure<double>(*this);
|
|
@ -0,0 +1,148 @@
|
||||||
|
// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#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
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Fortran::evaluate {
|
||||||
|
class FoldingContext;
|
||||||
|
|
||||||
|
using TypeCode = unsigned char;
|
||||||
|
|
||||||
|
template<typename TR, typename... TA> using FuncPointer = TR (*)(TA...);
|
||||||
|
|
||||||
|
enum class PassBy { Ref, Val };
|
||||||
|
template<typename TA, PassBy Pass = PassBy::Ref> struct ArgumentInfo {
|
||||||
|
using Type = TA;
|
||||||
|
static constexpr PassBy pass{Pass};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TR, typename... ArgInfo> struct Signature {
|
||||||
|
// Note valid template argument are of form
|
||||||
|
//<TR, ArgumentInfo<TA, PassBy>...> where TA and TR belong to RuntimeTypes.
|
||||||
|
// RuntimeTypes is a type union defined in intrinsics-library-templates.h to
|
||||||
|
// avoid circular dependencies. Argument of type void cannot be passed by
|
||||||
|
// value. So far TR cannot be a pointer.
|
||||||
|
const std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntrinsicProcedureRuntimeDescription {
|
||||||
|
const std::string name;
|
||||||
|
const TypeCode returnType;
|
||||||
|
const std::vector<TypeCode> argumentsType;
|
||||||
|
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 {
|
||||||
|
// Construct from runtime pointer with host types (float, double....)
|
||||||
|
template<typename HostTR, typename... HostTA>
|
||||||
|
HostRuntimeIntrinsicProcedure(const std::string &name,
|
||||||
|
FuncPointer<HostTR, HostTA...> func, bool isElemental = false);
|
||||||
|
HostRuntimeIntrinsicProcedure(
|
||||||
|
const IntrinsicProcedureRuntimeDescription &rteProc,
|
||||||
|
FuncPointer<void *> handle)
|
||||||
|
: IntrinsicProcedureRuntimeDescription{rteProc}, handle{handle} {}
|
||||||
|
const FuncPointer<void *> handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defines a wrapper type that indirects calls to host runtime functions.
|
||||||
|
// Valid ConstantContainer are Scalar (only for elementals) and Constant.
|
||||||
|
template<template<typename> typename ConstantContainer, typename TR,
|
||||||
|
typename... TA>
|
||||||
|
using HostProcedureWrapper = std::function<ConstantContainer<TR>(
|
||||||
|
FoldingContext &, ConstantContainer<TA>...)>;
|
||||||
|
|
||||||
|
// HostIntrinsicProceduresLibrary is a data structure that holds
|
||||||
|
// 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.
|
||||||
|
struct HostIntrinsicProceduresLibrary {
|
||||||
|
void AddProcedure(HostRuntimeIntrinsicProcedure &&sym) {
|
||||||
|
const std::string name{sym.name};
|
||||||
|
procedures.insert(std::make_pair(name, std::move(sym)));
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // FORTRAN_EVALUATE_INTRINSICS_LIBRARY_H_
|
|
@ -1,135 +0,0 @@
|
||||||
// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#ifndef FORTRAN_EVALUATE_RTE_INTERFACE_H_
|
|
||||||
#define FORTRAN_EVALUATE_RTE_INTERFACE_H_
|
|
||||||
|
|
||||||
// Defines the structure that must be used in F18 when dealing with the
|
|
||||||
// runtime, either with the target runtime or with the host runtime for
|
|
||||||
// folding purposes
|
|
||||||
// To avoid unnecessary header circular dependencies, the actual implementation
|
|
||||||
// of the templatized member function are defined in rte.h
|
|
||||||
// The header at hand must be included in order to add the rte interface data
|
|
||||||
// structure as a member of some structure.
|
|
||||||
// To actually use the rte interface, rte.h must be included. Note that rte.h
|
|
||||||
// includes the header at hand.
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <map>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace Fortran::evaluate {
|
|
||||||
class FoldingContext;
|
|
||||||
namespace rte {
|
|
||||||
|
|
||||||
using TypeCode = unsigned char;
|
|
||||||
|
|
||||||
template<typename TR, typename... TA> using FuncPointer = TR (*)(TA...);
|
|
||||||
|
|
||||||
enum class PassBy { Ref, Val };
|
|
||||||
template<typename TA, PassBy Pass = PassBy::Ref> struct ArgumentInfo {
|
|
||||||
using Type = TA;
|
|
||||||
static constexpr PassBy pass{Pass};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename TR, typename... ArgInfo> struct Signature {
|
|
||||||
// Note valid template argument are of form
|
|
||||||
//<TR, ArgumentInfo<TA, PassBy>...> where TA and TR belong to RteTypes.
|
|
||||||
// RteTypes is a type union defined in rte.h to avoid circular dependencies.
|
|
||||||
// Argument of type void cannot be passed by value
|
|
||||||
// So far TR cannot be a pointer.
|
|
||||||
const std::string name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RteProcedureSymbol {
|
|
||||||
const std::string name;
|
|
||||||
const TypeCode returnType;
|
|
||||||
const std::vector<TypeCode> argumentsType;
|
|
||||||
const std::vector<PassBy> argumentsPassedBy;
|
|
||||||
const bool isElemental;
|
|
||||||
const FuncPointer<void *> callable;
|
|
||||||
// callable only usable by HostRteProcedureSymbol but need to be created in
|
|
||||||
// case TargetRteProcedureSymbol is dynamically loaded because creating it
|
|
||||||
// dynamically would be too complex
|
|
||||||
|
|
||||||
// Construct from description using host independent types (RteTypes)
|
|
||||||
template<typename TR, typename... ArgInfo>
|
|
||||||
RteProcedureSymbol(
|
|
||||||
const Signature<TR, ArgInfo...> &signature, bool isElemental = false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// For target rte library info
|
|
||||||
struct TargetRteProcedureSymbol : RteProcedureSymbol {
|
|
||||||
// Construct from description using host independent types (RteTypes)
|
|
||||||
// Note: passing ref/val also needs to be passed by template to build
|
|
||||||
// the callable
|
|
||||||
template<typename TR, typename... ArgInfo>
|
|
||||||
TargetRteProcedureSymbol(const Signature<TR, ArgInfo...> &signature,
|
|
||||||
const std::string &symbolName, bool isElemental = false);
|
|
||||||
const std::string symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TargetRteLibrary {
|
|
||||||
TargetRteLibrary(const std::string &name) : name{name} {}
|
|
||||||
void AddProcedure(TargetRteProcedureSymbol &&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 TargetRteProcedureSymbol> procedures;
|
|
||||||
};
|
|
||||||
|
|
||||||
// To use host runtime for folding
|
|
||||||
struct HostRteProcedureSymbol : RteProcedureSymbol {
|
|
||||||
// Construct from runtime pointer with host types (float, double....)
|
|
||||||
template<typename HostTR, typename... HostTA>
|
|
||||||
HostRteProcedureSymbol(const std::string &name,
|
|
||||||
FuncPointer<HostTR, HostTA...> func, bool isElemental = false);
|
|
||||||
HostRteProcedureSymbol(
|
|
||||||
const RteProcedureSymbol &rteProc, FuncPointer<void *> handle)
|
|
||||||
: RteProcedureSymbol{rteProc}, handle{handle} {}
|
|
||||||
const FuncPointer<void *> handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
// valid ConstantContainer are Scalar (only for elementals) and Constant
|
|
||||||
template<template<typename> typename ConstantContainer, typename TR,
|
|
||||||
typename... TA>
|
|
||||||
using HostProcedureWrapper = std::function<ConstantContainer<TR>(
|
|
||||||
FoldingContext &, ConstantContainer<TA>...)>;
|
|
||||||
|
|
||||||
struct HostRte {
|
|
||||||
void AddProcedure(HostRteProcedureSymbol &&sym) {
|
|
||||||
const std::string name{sym.name};
|
|
||||||
procedures.insert(std::make_pair(name, std::move(sym)));
|
|
||||||
}
|
|
||||||
bool HasEquivalentProcedure(const RteProcedureSymbol &sym) const;
|
|
||||||
HostRte() { DefaultInit(); }
|
|
||||||
~HostRte();
|
|
||||||
void DefaultInit(); // load functions from <cmath> and <complex>
|
|
||||||
void LoadTargetRteLibrary(const TargetRteLibrary &lib); // TODO
|
|
||||||
template<template<typename> typename ConstantContainer, typename TR,
|
|
||||||
typename... TA>
|
|
||||||
std::optional<HostProcedureWrapper<ConstantContainer, TR, TA...>>
|
|
||||||
GetHostProcedureWrapper(const std::string &name);
|
|
||||||
// some data structure of HostRteProcedureSymbol
|
|
||||||
std::multimap<std::string, const HostRteProcedureSymbol> procedures;
|
|
||||||
std::map<std::string, void *>
|
|
||||||
dynamicallyLoadedLibraries; // keep the handles for dlclose
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // FORTRAN_EVALUATE_RTE_INTERFACE_H_
|
|
Loading…
Reference in New Issue