From: Jean Perier Date: Wed, 20 Feb 2019 16:55:00 +0000 (-0800) Subject: [flang] Use new indirection layer to host runtime in folding X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9b1d9289902ebcbf5e3f6fd1dcde9c8b17310464;p=platform%2Fupstream%2Fllvm.git [flang] Use new indirection layer to host runtime in folding Original-commit: flang-compiler/f18@e8bb9c52afce3a4e6175bd4b1a3d4641f77491b9 Tree-same-pre-rewrite: false --- diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index 5dfa3ad..7bf1d42 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -18,6 +18,7 @@ #include "expression.h" #include "host.h" #include "int-power.h" +#include "rte.h" #include "tools.h" #include "traversal.h" #include "type.h" @@ -161,75 +162,50 @@ ComplexPart FoldOperation(FoldingContext &context, ComplexPart &&complexPart) { FoldOperation(context, std::move(complex)), complexPart.part()}; } -// helpers to fold intrinsic function references namespace intrinsicHelper { -// helper to produce hash of intrinsic names based the first 3 letters. All -// intrinsic names are longer than 3 letters -static constexpr inline std::int32_t CommonHash(const char *s, std::size_t n) { - if (n < 3) { - return 0; - } - return (((static_cast(s[0]) << 8) + s[1]) << 8) + s[2]; -} - -static constexpr std::int32_t operator"" _hash(const char *s, std::size_t n) { - return CommonHash(s, n); -} - -static std::int32_t DynamicHash(const std::string &s) { - return CommonHash(s.data(), s.size()); -} - -// Define function pointer and callable types used in a common utility that +// helpers to fold intrinsic function references +// Define callable types used in a common utility that // takes care of array and cast/conversion aspects for elemental intrinsics -// Note: math complex functions from are passing arg as const ref -template using FuncPointer = TR (*)(TA...); - -template -using HostFuncPointer = FuncPointer, - std::conditional_t &, Host::HostType>...>; template using ScalarFunc = std::function(const Scalar &...)>; - -// Helper that build std::function operating on Scalar types from host runtime -// function. There is version that only works if the scalar has a matching host -// type and one that allow conversions of scalar types toward "bigger" host -// types. By "bigger", it is meant that all the scalar types can be converted to -// and from this host type without any precision loss. The purpose of this is -// mainly to allow folding of 16 bits float intrinsic function with the host -// runtime for 32bit floats when it is acceptable (e.g acos). -template -static constexpr inline ScalarFunc HostFuncWrap( - HostFuncPointer func) { - return [=](const Scalar &... x) -> Scalar { - // TODO fp-exception - return Host::CastHostToFortran(func(Host::CastFortranToHost(x)...)); - }; -} - -// A utility that applies a scalar function over arrays or scalar for elemental -// intrinsics. -template -static inline Expr FoldElementalIntrinsicHelper(FunctionRef &&funcRef, - ScalarFunc scalarFunc, std::index_sequence) { +template +using ScalarFuncWithContext = + std::function(FoldingContext &, const Scalar &...)>; + +template typename WrapperType, typename TR, + typename... TA, std::size_t... I> +static inline Expr FoldElementalIntrinsicHelper(FoldingContext &context, + FunctionRef &&funcRef, WrapperType func, + std::index_sequence) { static_assert( (... && IsSpecificIntrinsicType)); // TODO derived types for MERGE? std::tuple>...> scalars{ GetScalarConstantValue(*funcRef.arguments()[I]->value)...}; if ((... && std::get(scalars).has_value())) { - return Expr{Constant{scalarFunc(*std::get(scalars)...)}}; + if constexpr (std::is_same_v, + ScalarFuncWithContext>) { + return Expr{Constant{func(context, *std::get(scalars)...)}}; + } else if constexpr (std::is_same_v, + ScalarFunc>) { + return Expr{Constant{func(*std::get(scalars)...)}}; + } } // TODO: handle arrays when Constant can represent them return Expr{std::move(funcRef)}; } template -static Expr FoldElementalIntrinsic( - FunctionRef &&funcRef, ScalarFunc scalarFunc) { - return FoldElementalIntrinsicHelper( - std::move(funcRef), scalarFunc, std::index_sequence_for{}); +static Expr FoldElementalIntrinsic(FoldingContext &context, + FunctionRef &&funcRef, ScalarFunc func) { + return FoldElementalIntrinsicHelper( + context, std::move(funcRef), func, std::index_sequence_for{}); +} +template +static Expr FoldElementalIntrinsic(FoldingContext &context, + FunctionRef &&funcRef, ScalarFuncWithContext func) { + return FoldElementalIntrinsicHelper( + context, std::move(funcRef), func, std::index_sequence_for{}); } } @@ -245,67 +221,52 @@ Expr> FoldOperation(FoldingContext &context, } } if (auto *intrinsic{std::get_if(&funcRef.proc().u)}) { - std::string name{intrinsic->name}; - switch (DynamicHash(name)) { - case "kin"_hash: - if (name == "kind") { - if constexpr (common::HasMember) { - return Expr{funcRef.arguments()[0]->value()->GetType()->kind}; - } else { - common::die("kind() result not integral"); - } + const std::string name{intrinsic->name}; + if (name == "kind") { + if constexpr (common::HasMember) { + return Expr{funcRef.arguments()[0]->value()->GetType()->kind}; + } else { + common::die("kind() result not integral"); } - break; - case "len"_hash: - if (name == "len") { - if constexpr (std::is_same_v) { - if (auto *charExpr{UnwrapExpr>( - *funcRef.arguments()[0]->value())}) { - return std::visit([](auto &kx) { return kx.LEN(); }, charExpr->u); - } - } else { - common::die("len() result not SubscriptInteger"); + } else if (name == "len") { + if constexpr (std::is_same_v) { + if (auto *charExpr{UnwrapExpr>( + *funcRef.arguments()[0]->value())}) { + return std::visit([](auto &kx) { return kx.LEN(); }, charExpr->u); } + } else { + common::die("len() result not SubscriptInteger"); } - break; - case "ian"_hash: - if (name == "iand") { - if (auto *x{std::get_if( - &funcRef.arguments()[0]->value->u)}) { - *funcRef.arguments()[0]->value = - Fold(context, ConvertToType(std::move(*x))); - } - if (auto *x{std::get_if( - &funcRef.arguments()[1]->value->u)}) { - *funcRef.arguments()[1]->value = - Fold(context, ConvertToType(std::move(*x))); - } - return FoldElementalIntrinsic( - std::move(funcRef), ScalarFunc(&Scalar::IAND)); + } else if (name == "iand") { + if (auto *x{std::get_if( + &funcRef.arguments()[0]->value->u)}) { + *funcRef.arguments()[0]->value = + Fold(context, ConvertToType(std::move(*x))); } - break; - case "int"_hash: - if (name == "int") { - return std::visit( - [&](auto &&x) -> Expr { - using From = std::decay_t; - if constexpr (std::is_same_v || - std::is_same_v> || - std::is_same_v> || - std::is_same_v>) { - return Fold(context, ConvertToType(std::move(x))); - } else { - common::die("int() argument type not valid"); - return Expr{std::move(funcRef)}; // unreachable - } - }, - std::move(funcRef.arguments()[0]->value->u)); + if (auto *x{std::get_if( + &funcRef.arguments()[1]->value->u)}) { + *funcRef.arguments()[1]->value = + Fold(context, ConvertToType(std::move(*x))); } - break; - default: - // TODO: many more intrinsic functions - break; + return FoldElementalIntrinsic( + context, std::move(funcRef), ScalarFunc(&Scalar::IAND)); + } else if (name == "int") { + return std::visit( + [&](auto &&x) -> Expr { + using From = std::decay_t; + if constexpr (std::is_same_v || + std::is_same_v> || + std::is_same_v> || + std::is_same_v>) { + return Fold(context, ConvertToType(std::move(x))); + } else { + common::die("int() argument type not valid"); + return Expr{std::move(funcRef)}; // unreachable + } + }, + std::move(funcRef.arguments()[0]->value->u)); } + // TODO: many more intrinsic functions } return Expr{std::move(funcRef)}; } @@ -321,90 +282,71 @@ Expr> FoldOperation(FoldingContext &context, } } if (auto *intrinsic{std::get_if(&funcRef.proc().u)}) { - std::string name{intrinsic->name}; - switch (DynamicHash(name)) { - case "aco"_hash: - if (name == "acos") { - if constexpr (Host::HostTypeExists()) { - return FoldElementalIntrinsic(std::move(funcRef), - HostFuncWrap(HostFuncPointer{std::acos})); - } else { - context.messages().Say( - "acos(real(kind=%d)) cannot be folded on host"_en_US, KIND); + const std::string name{intrinsic->name}; + if (name == "acos" || name == "acosh") { + if (auto callable{ + context.hostRte().GetHostProcedureWrapper(name)}) { + return FoldElementalIntrinsic( + context, std::move(funcRef), *callable); + } else { + context.messages().Say( + "%s(real(kind=%d)) cannot be folded on host"_en_US, name.c_str(), + KIND); + } + } else if (name == "bessel_jn" || name == "bessel_yn") { + if (funcRef.arguments().size() == 2) { // elemental + using Int8 = Type; + if (auto *n{std::get_if>( + &funcRef.arguments()[0]->value->u)}) { + *funcRef.arguments()[0]->value = + Fold(context, ConvertToType(std::move(*n))); } - } else if (name == "acosh") { - if constexpr (Host::HostTypeExists()) { - return FoldElementalIntrinsic(std::move(funcRef), - HostFuncWrap(HostFuncPointer{std::acosh})); + if (auto callable{ + context.hostRte().GetHostProcedureWrapper( + name)}) { + return FoldElementalIntrinsic( + context, std::move(funcRef), *callable); } else { context.messages().Say( - "acosh(real(kind=%d)) cannot be folded on host"_en_US, KIND); - } - } - case "bes"_hash: - if (name == "bessel_jn" || name == "bessel_yn") { - if (funcRef.arguments().size() == 2) { // elemental - if constexpr (Host::HostTypeExists()) { - // TODO mapping to function to be tested. func takes - // real arg for n - if (auto *n{std::get_if>( - &funcRef.arguments()[0]->value->u)}) { - *funcRef.arguments()[0]->value = - Fold(context, ConvertToType(std::move(*n))); - } - auto hostFunc{name == "bessel_jn" - ? HostFuncPointer{std::cyl_bessel_j} - : HostFuncPointer{std::cyl_neumann}}; - return FoldElementalIntrinsic( - std::move(funcRef), HostFuncWrap(hostFunc)); - } + "%s(integer(kind=8), real(kind=%d)) cannot be folded on host"_en_US, + name.c_str(), KIND); } } - break; - case "dpr"_hash: - if (name == "dprod") { - if (auto *x{std::get_if>( - &funcRef.arguments()[0]->value->u)}) { - if (auto *y{std::get_if>( - &funcRef.arguments()[1]->value->u)}) { - return Fold(context, - Expr{Multiply{ConvertToType(std::move(*x)), - ConvertToType(std::move(*y))}}); - } + } else if (name == "dprod") { + if (auto *x{ + std::get_if>(&funcRef.arguments()[0]->value->u)}) { + if (auto *y{std::get_if>( + &funcRef.arguments()[1]->value->u)}) { + return Fold(context, + Expr{Multiply{ConvertToType(std::move(*x)), + ConvertToType(std::move(*y))}}); } - common::die("Wrong argument type in dprod()"); - break; } - break; - case "rea"_hash: - if (name == "real") { - return std::visit( - [&](auto &&x) -> Expr { - using From = std::decay_t; - if constexpr (std::is_same_v) { - typename T::Scalar::Word::ValueWithOverflow result{ - T::Scalar::Word::ConvertUnsigned(x)}; - if (result.overflow) { // C1601 - context.messages().Say( - "Non null truncated bits of boz literal constant in REAL intrinsic"_en_US); - } - return Expr{Constant{Scalar(std::move(result.value))}}; - } else if constexpr (std::is_same_v> || - std::is_same_v> || - std::is_same_v>) { - return Fold(context, ConvertToType(std::move(x))); - } else { - common::die("real() argument type not valid"); - return Expr{std::move(funcRef)}; // unreachable + common::die("Wrong argument type in dprod()"); + } else if (name == "real") { + return std::visit( + [&](auto &&x) -> Expr { + using From = std::decay_t; + if constexpr (std::is_same_v) { + typename T::Scalar::Word::ValueWithOverflow result{ + T::Scalar::Word::ConvertUnsigned(x)}; + if (result.overflow) { // C1601 + context.messages().Say( + "Non null truncated bits of boz literal constant in REAL intrinsic"_en_US); } - }, - std::move(funcRef.arguments()[0]->value->u)); - } - break; - default: - // TODO: many more intrinsic functions - break; + return Expr{Constant{Scalar(std::move(result.value))}}; + } else if constexpr (std::is_same_v> || + std::is_same_v> || + std::is_same_v>) { + return Fold(context, ConvertToType(std::move(x))); + } else { + common::die("real() argument type not valid"); + return Expr{std::move(funcRef)}; // unreachable + } + }, + std::move(funcRef.arguments()[0]->value->u)); } + // TODO: many more intrinsic functions } return Expr{std::move(funcRef)}; } @@ -420,64 +362,52 @@ Expr> FoldOperation(FoldingContext &context, } } if (auto *intrinsic{std::get_if(&funcRef.proc().u)}) { - std::string name{intrinsic->name}; - switch (DynamicHash(name)) { - case "aco"_hash: - if (name == "acos") { - if constexpr (Host::HostTypeExists()) { - return FoldElementalIntrinsic(std::move(funcRef), - HostFuncWrap(HostFuncPointer{std::acos})); - } else { - context.messages().Say( - "acos(complex(kind=%d)) cannot be folded on host"_en_US, KIND); - } - } else if (name == "acosh") { - if constexpr (Host::HostTypeExists()) { - return FoldElementalIntrinsic(std::move(funcRef), - HostFuncWrap(HostFuncPointer{std::acosh})); - } else { - context.messages().Say( - "acosh(complex(kind=%d)) cannot be folded on host"_en_US, KIND); - } + const std::string name{intrinsic->name}; + if (name == "acos" || name == "acosh" || name == "asin" || name == "atan" || + name == "atanh") { + if (auto callable{ + context.hostRte().GetHostProcedureWrapper(name)}) { + return FoldElementalIntrinsic( + context, std::move(funcRef), *callable); + } else { + context.messages().Say( + "%s(complex(kind=%d)) cannot be folded on host"_en_US, name.c_str(), + KIND); } - case "cmp"_hash: - if (name == "cmplx") { - if (funcRef.arguments().size() == 2) { - if (auto *x{std::get_if>( - &funcRef.arguments()[0]->value->u)}) { - return Fold(context, ConvertToType(std::move(*x))); - } else { - common::die("x must be complex in cmplx(x[, kind])"); - } + } + if (name == "cmplx") { + if (funcRef.arguments().size() == 2) { + if (auto *x{std::get_if>( + &funcRef.arguments()[0]->value->u)}) { + return Fold(context, ConvertToType(std::move(*x))); } else { - CHECK(funcRef.arguments().size() == 3); - using Part = typename T::Part; - Expr im{funcRef.arguments()[1].has_value() - ? std::move(*funcRef.arguments()[1]->value) - : AsGenericExpr(Constant{Scalar{}})}; - Expr re{std::move(*funcRef.arguments()[0]->value)}; - int reRank{re.Rank()}; - int imRank{im.Rank()}; - semantics::Attrs attrs; - attrs.set(semantics::Attr::ELEMENTAL); - auto reReal{ - FunctionRef{ProcedureDesignator{SpecificIntrinsic{ - "real", Part::GetType(), reRank, attrs}}, - ActualArguments{ActualArgument{std::move(re)}}}}; - auto imReal{ - FunctionRef{ProcedureDesignator{SpecificIntrinsic{ - "real", Part::GetType(), imRank, attrs}}, - ActualArguments{ActualArgument{std::move(im)}}}}; - return Fold(context, - Expr{ComplexConstructor{Expr{std::move(reReal)}, - Expr{std::move(imReal)}}}); + common::die("x must be complex in cmplx(x[, kind])"); } + } else { + CHECK(funcRef.arguments().size() == 3); + using Part = typename T::Part; + Expr im{funcRef.arguments()[1].has_value() + ? std::move(*funcRef.arguments()[1]->value) + : AsGenericExpr(Constant{Scalar{}})}; + Expr re{std::move(*funcRef.arguments()[0]->value)}; + int reRank{re.Rank()}; + int imRank{im.Rank()}; + semantics::Attrs attrs; + attrs.set(semantics::Attr::ELEMENTAL); + auto reReal{ + FunctionRef{ProcedureDesignator{SpecificIntrinsic{ + "real", Part::GetType(), reRank, attrs}}, + ActualArguments{ActualArgument{std::move(re)}}}}; + auto imReal{ + FunctionRef{ProcedureDesignator{SpecificIntrinsic{ + "real", Part::GetType(), imRank, attrs}}, + ActualArguments{ActualArgument{std::move(im)}}}}; + return Fold(context, + Expr{ComplexConstructor{ + Expr{std::move(reReal)}, Expr{std::move(imReal)}}}); } - break; - default: - // TODO: many more intrinsic functions - break; } + // TODO: many more intrinsic functions } return Expr{std::move(funcRef)}; } @@ -494,41 +424,35 @@ Expr> FoldOperation(FoldingContext &context, } if (auto *intrinsic{std::get_if(&funcRef.proc().u)}) { std::string name{intrinsic->name}; - switch (DynamicHash(name)) { - case "bge"_hash: - if (name == "bge") { - using LargestInt = Type; - static_assert(std::is_same_v, BOZLiteralConstant>); - if (auto *x{std::get_if>( - &funcRef.arguments()[0]->value->u)}) { - *funcRef.arguments()[0]->value = - Fold(context, ConvertToType(std::move(*x))); - } else if (auto *x{std::get_if( - &funcRef.arguments()[0]->value->u)}) { - *funcRef.arguments()[0]->value = - AsGenericExpr(Constant{std::move(*x)}); - } - if (auto *x{std::get_if>( - &funcRef.arguments()[1]->value->u)}) { - *funcRef.arguments()[1]->value = - Fold(context, ConvertToType(std::move(*x))); - } else if (auto *x{std::get_if( - &funcRef.arguments()[1]->value->u)}) { - *funcRef.arguments()[1]->value = - AsGenericExpr(Constant{std::move(*x)}); - } - return FoldElementalIntrinsic( - std::move(funcRef), - ScalarFunc( - [](const Scalar &i, const Scalar &j) { - return Scalar{i.BGE(j)}; - })); + if (name == "bge") { + using LargestInt = Type; + static_assert(std::is_same_v, BOZLiteralConstant>); + if (auto *x{std::get_if>( + &funcRef.arguments()[0]->value->u)}) { + *funcRef.arguments()[0]->value = + Fold(context, ConvertToType(std::move(*x))); + } else if (auto *x{std::get_if( + &funcRef.arguments()[0]->value->u)}) { + *funcRef.arguments()[0]->value = + AsGenericExpr(Constant{std::move(*x)}); + } + if (auto *x{std::get_if>( + &funcRef.arguments()[1]->value->u)}) { + *funcRef.arguments()[1]->value = + Fold(context, ConvertToType(std::move(*x))); + } else if (auto *x{std::get_if( + &funcRef.arguments()[1]->value->u)}) { + *funcRef.arguments()[1]->value = + AsGenericExpr(Constant{std::move(*x)}); } - break; - default: - // TODO: many more intrinsic functions - break; + return FoldElementalIntrinsic(context, + std::move(funcRef), + ScalarFunc( + [](const Scalar &i, const Scalar &j) { + return Scalar{i.BGE(j)}; + })); } + // TODO: many more intrinsic functions } return Expr{std::move(funcRef)}; }