[flang] renaming to focus scope on intrinsic runtime

Original-commit: flang-compiler/f18@7cfd33b178
Tree-same-pre-rewrite: false
This commit is contained in:
Jean Perier 2019-03-01 09:20:12 -08:00 committed by GitHub
parent fa3a179fec
commit 8d032dc96b
7 changed files with 221 additions and 193 deletions

View File

@ -29,7 +29,7 @@ add_library(FortranEvaluate
tools.cc
type.cc
variable.cc
rte.cc
intrinsics-library.cc
)
target_link_libraries(FortranEvaluate

View File

@ -15,6 +15,7 @@
#ifndef FORTRAN_EVALUATE_COMMON_H_
#define FORTRAN_EVALUATE_COMMON_H_
#include "intrinsics-library.h"
#include "../common/Fortran.h"
#include "../common/enum-set.h"
#include "../common/idioms.h"
@ -22,7 +23,6 @@
#include "../common/restorer.h"
#include "../parser/char-block.h"
#include "../parser/message.h"
#include "rte-interface.h"
#include <cinttypes>
#include <map>
@ -219,7 +219,9 @@ public:
bool flushSubnormalsToZero() const { return flushSubnormalsToZero_; }
bool bigEndian() const { return bigEndian_; }
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::optional<std::int64_t> GetImpliedDo(parser::CharBlock) const;
@ -241,7 +243,7 @@ private:
bool bigEndian_{false};
const semantics::DerivedTypeSpec *pdtInstance_{nullptr};
std::map<parser::CharBlock, std::int64_t> impliedDos_;
rte::HostRte hostRte_;
HostIntrinsicProceduresLibrary hostIntrinsicsLibrary_;
};
void RealFlagWarnings(FoldingContext &, const RealFlags &, const char *op);

View File

@ -18,7 +18,7 @@
#include "expression.h"
#include "host.h"
#include "int-power.h"
#include "rte.h"
#include "intrinsics-library-templates.h"
#include "tools.h"
#include "traversal.h"
#include "type.h"
@ -331,8 +331,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
const std::string name{intrinsic->name};
if (name == "acos" || name == "acosh" ||
(name == "atan" && funcRef.arguments().size() == 1)) {
if (auto callable{
context.hostRte().GetHostProcedureWrapper<Scalar, T, T>(name)}) {
if (auto callable{context.hostIntrinsicsLibrary()
.GetHostProcedureWrapper<Scalar, T, T>(name)}) {
return FoldElementalIntrinsic<T, T>(
context, std::move(funcRef), *callable);
} else {
@ -342,9 +342,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
}
}
if (name == "atan") {
if (auto callable{
context.hostRte().GetHostProcedureWrapper<Scalar, T, T, T>(
name)}) {
if (auto callable{context.hostIntrinsicsLibrary()
.GetHostProcedureWrapper<Scalar, T, T, T>(name)}) {
return FoldElementalIntrinsic<T, T, T>(
context, std::move(funcRef), *callable);
} else {
@ -361,8 +360,8 @@ Expr<Type<TypeCategory::Real, KIND>> FoldOperation(FoldingContext &context,
Fold(context, ConvertToType<Int8>(std::move(*n)));
}
if (auto callable{
context.hostRte().GetHostProcedureWrapper<Scalar, T, Int8, T>(
name)}) {
context.hostIntrinsicsLibrary()
.GetHostProcedureWrapper<Scalar, T, Int8, T>(name)}) {
return FoldElementalIntrinsic<T, Int8, T>(
context, std::move(funcRef), *callable);
} else {
@ -423,8 +422,8 @@ Expr<Type<TypeCategory::Complex, KIND>> FoldOperation(FoldingContext &context,
const std::string name{intrinsic->name};
if (name == "acos" || name == "acosh" || name == "asin" || name == "atan" ||
name == "atanh") {
if (auto callable{
context.hostRte().GetHostProcedureWrapper<Scalar, T, T>(name)}) {
if (auto callable{context.hostIntrinsicsLibrary()
.GetHostProcedureWrapper<Scalar, T, T>(name)}) {
return FoldElementalIntrinsic<T, T>(
context, std::move(funcRef), *callable);
} else {

View File

@ -12,18 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FORTRAN_EVALUATE_RTE_H_
#define FORTRAN_EVALUATE_RTE_H_
#ifndef FORTRAN_EVALUATE_INTRINSICS_LIBRARY_TEMPLATES_H_
#define FORTRAN_EVALUATE_INTRINSICS_LIBRARY_TEMPLATES_H_
// This header defines the actual implementation of the templatized member
// function of the structures defined in rte-interface.h. It should only be
// included if these member functions are used, else rte-interface.h is
// function of the structures defined in intrinsics-library.h. It should only be
// included if these member functions are used, else intrinsics-library.h is
// sufficient. This is to avoid circular dependencies. The below implementation
// cannot be defined in .cc file because it would be too cumbersome to decide
// which version should be instantiated in a generic way.
#include "host.h"
#include "rte-interface.h"
#include "intrinsics-library.h"
#include "type.h"
#include "../common/template.h"
@ -31,11 +31,11 @@
#include <tuple>
#include <type_traits>
namespace Fortran::evaluate::rte {
namespace Fortran::evaluate {
// Define meaningful types for the runtime
// 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>
@ -44,12 +44,14 @@ struct IndexInTupleHelper<T, std::tuple<TT...>> {
};
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");
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>
using HostArgType = std::conditional_t<Pass == PassBy::Ref,
@ -84,7 +86,7 @@ template<typename TR, typename... ArgInfo> struct CallableHostWrapper {
hostFPE.CheckAndRestoreFloatingPointEnvironment(context);
return host::CastHostToFortran<TR>(res);
} 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");
return Scalar<TR>{}; // unreachable
}
@ -93,7 +95,7 @@ template<typename TR, typename... ArgInfo> struct CallableHostWrapper {
};
template<typename TR, typename... ArgInfo>
RteProcedureSymbol::RteProcedureSymbol(
IntrinsicProcedureRuntimeDescription::IntrinsicProcedureRuntimeDescription(
const Signature<TR, ArgInfo...> &signature, bool isElemental)
: name{signature.name}, returnType{typeCodeOf<TR>},
argumentsType{typeCodeOf<typename ArgInfo::Type>...},
@ -119,16 +121,18 @@ using SignatureFromHostFuncPointer =
Signature<host::FortranType<HostTR>, ArgInfoFromHostType<HostTA>...>;
template<typename HostTR, typename... HostTA>
HostRteProcedureSymbol::HostRteProcedureSymbol(const std::string &name,
FuncPointer<HostTR, HostTA...> func, bool isElemental)
: RteProcedureSymbol(
HostRuntimeIntrinsicProcedure::HostRuntimeIntrinsicProcedure(
const std::string &name, FuncPointer<HostTR, HostTA...> func,
bool isElemental)
: IntrinsicProcedureRuntimeDescription(
SignatureFromHostFuncPointer<HostTR, HostTA...>{name}, isElemental),
handle{reinterpret_cast<FuncPointer<void *>>(func)} {}
template<template<typename> typename ConstantContainer, typename TR,
typename... 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...>()) {
auto rteProcRange{procedures.equal_range(name)};
const TypeCode resTypeCode{typeCodeOf<TR>};
@ -165,10 +169,11 @@ HostRte::GetHostProcedureWrapper(const std::string &name) {
}
template<typename TR, typename... ArgInfo>
TargetRteProcedureSymbol::TargetRteProcedureSymbol(
TargetRuntimeIntrinsicProcedure::TargetRuntimeIntrinsicProcedure(
const Signature<TR, ArgInfo...> &signature, const std::string &symbolName,
bool isElemental)
: RteProcedureSymbol{signature, isElemental}, symbol{symbolName} {}
: IntrinsicProcedureRuntimeDescription{signature, isElemental},
symbol{symbolName} {}
}
#endif // FORTRAN_EVALUATE_RTE_H_
#endif // FORTRAN_EVALUATE_INTRINSICS_LIBRARY_TEMPLATES_H_

View File

@ -14,10 +14,10 @@
// 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.
// The default HostRte is built with <cmath> and <complex> functions
// that are guaranteed to exist from the C++ standard.
// The default HostIntrinsicProceduresLibrary is built with <cmath> and
// <complex> functions that are guaranteed to exist from the C++ standard.
#include "rte.h"
#include "intrinsics-library-templates.h"
#include "../common/idioms.h"
#include <cerrno>
#include <cfenv>
@ -27,11 +27,12 @@
#include <dlfcn.h>
#endif
namespace Fortran::evaluate::rte {
namespace Fortran::evaluate {
using namespace Fortran::parser::literals;
// 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 size_t nargs{sym.argumentsType.size()};
for (auto iter{rteProcRange.first}; iter != rteProcRange.second; ++iter) {
@ -54,7 +55,8 @@ bool HostRte::HasEquivalentProcedure(const RteProcedureSymbol &sym) const {
return false;
}
void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
void HostIntrinsicProceduresLibrary::LoadTargetIntrinsicProceduresLibrary(
const TargetIntrinsicProceduresLibrary &lib) {
if (dynamicallyLoadedLibraries.find(lib.name) !=
dynamicallyLoadedLibraries.end()) {
return; // already loaded
@ -75,7 +77,7 @@ void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
// 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(HostRteProcedureSymbol{
AddProcedure(HostRuntimeIntrinsicProcedure{
sym.second, reinterpret_cast<FuncPointer<void *>>(func)});
}
}
@ -84,7 +86,7 @@ void HostRte::LoadTargetRteLibrary(const TargetRteLibrary &lib) {
#endif
}
HostRte::~HostRte() {
HostIntrinsicProceduresLibrary::~HostIntrinsicProceduresLibrary() {
for (auto iter{dynamicallyLoadedLibraries.begin()};
iter != dynamicallyLoadedLibraries.end(); ++iter) {
#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);
}
template<typename HostT> void AddLibmRealHostProcedure(HostRte &hostRte) {
template<typename HostT>
void AddLibmRealHostProcedure(
HostIntrinsicProceduresLibrary &hostIntrinsicLibrary) {
using F = FuncPointer<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},
{"asinh", F{std::asinh}, true}, {"atan", F{std::atan}, 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}};
for (auto sym : libmSymbols) {
if (!hostRte.HasEquivalentProcedure(sym)) {
hostRte.AddProcedure(std::move(sym));
if (!hostIntrinsicLibrary.HasEquivalentProcedure(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> &>;
HostRteProcedureSymbol libmSymbols[]{{"acos", F{std::acos}, true},
HostRuntimeIntrinsicProcedure libmSymbols[]{{"acos", F{std::acos}, true},
{"acosh", F{std::acosh}, true}, {"asin", F{std::asin}, true},
{"asinh", F{std::asinh}, true}, {"atan", F{std::atan}, 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}};
for (auto sym : libmSymbols) {
if (!hostRte.HasEquivalentProcedure(sym)) {
hostRte.AddProcedure(std::move(sym));
if (!hostIntrinsicLibrary.HasEquivalentProcedure(sym)) {
hostIntrinsicLibrary.AddProcedure(std::move(sym));
}
}
}
@ -183,32 +189,34 @@ static std::string MakeLibpgmathName(const std::string &name, MathOption m) {
}
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>>;
const std::string oneArgFuncs[]{"acos", "asin", "atan", "cos", "cosh", "exp",
"log", "log10", "sin", "sinh", "tan", "tanh"};
for (const std::string &name : oneArgFuncs) {
lib.AddProcedure(TargetRteProcedureSymbol{
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(TargetRteProcedureSymbol{
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(TargetRteProcedureSymbol{
lib.AddProcedure(TargetRuntimeIntrinsicProcedure{
F{name}, MakeLibpgmathName<T>(name, opt), true});
}
}
}
TargetRteLibrary BuildLibpgmTargetRteLibrary(MathOption opt) {
TargetRteLibrary lib{"libpgmath"};
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);
@ -218,13 +226,14 @@ TargetRteLibrary BuildLibpgmTargetRteLibrary(MathOption opt) {
// 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
// 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
TargetRteLibrary libpgmath{BuildLibpgmTargetRteLibrary(MathOption::Precise)};
LoadTargetRteLibrary(libpgmath);
TargetIntrinsicProceduresLibrary libpgmath{
BuildLibpgmTargetIntrinsicProceduresLibrary(MathOption::Precise)};
LoadTargetIntrinsicProceduresLibrary(libpgmath);
AddLibmRealHostProcedure<float>(*this);
AddLibmRealHostProcedure<double>(*this);

View File

@ -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_

View File

@ -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_