| 1 | #include "../../lib/Evaluate/host.h" |
| 2 | #include "flang/Evaluate/call.h" |
| 3 | #include "flang/Evaluate/expression.h" |
| 4 | #include "flang/Evaluate/fold.h" |
| 5 | #include "flang/Evaluate/intrinsics-library.h" |
| 6 | #include "flang/Evaluate/intrinsics.h" |
| 7 | #include "flang/Evaluate/target.h" |
| 8 | #include "flang/Evaluate/tools.h" |
| 9 | #include "flang/Testing/testing.h" |
| 10 | #include <tuple> |
| 11 | |
| 12 | using namespace Fortran::evaluate; |
| 13 | |
| 14 | // helper to call functions on all types from tuple |
| 15 | template <typename... T> struct RunOnTypes {}; |
| 16 | template <typename Test, typename... T> |
| 17 | struct RunOnTypes<Test, std::tuple<T...>> { |
| 18 | static void Run() { (..., Test::template Run<T>()); } |
| 19 | }; |
| 20 | |
| 21 | // test for fold.h GetScalarConstantValue function |
| 22 | struct TestGetScalarConstantValue { |
| 23 | template <typename T> static void Run() { |
| 24 | Expr<T> exprFullyTyped{Constant<T>{Scalar<T>{}}}; |
| 25 | Expr<SomeKind<T::category>> exprSomeKind{exprFullyTyped}; |
| 26 | Expr<SomeType> exprSomeType{exprSomeKind}; |
| 27 | TEST(GetScalarConstantValue<T>(exprFullyTyped).has_value()); |
| 28 | TEST(GetScalarConstantValue<T>(exprSomeKind).has_value()); |
| 29 | TEST(GetScalarConstantValue<T>(exprSomeType).has_value()); |
| 30 | } |
| 31 | }; |
| 32 | |
| 33 | template <typename T> |
| 34 | Scalar<T> CallHostRt( |
| 35 | HostRuntimeWrapper func, FoldingContext &context, Scalar<T> x) { |
| 36 | return GetScalarConstantValue<T>( |
| 37 | func(context, {AsGenericExpr(Constant<T>{x})})) |
| 38 | .value(); |
| 39 | } |
| 40 | |
| 41 | void TestHostRuntimeSubnormalFlushing() { |
| 42 | using R4 = Type<TypeCategory::Real, 4>; |
| 43 | if constexpr (std::is_same_v<host::HostType<R4>, float>) { |
| 44 | Fortran::parser::CharBlock src; |
| 45 | Fortran::parser::ContextualMessages messages{src, nullptr}; |
| 46 | Fortran::common::IntrinsicTypeDefaultKinds defaults; |
| 47 | auto intrinsics{Fortran::evaluate::IntrinsicProcTable::Configure(defaults)}; |
| 48 | TargetCharacteristics flushingTargetCharacteristics; |
| 49 | flushingTargetCharacteristics.set_areSubnormalsFlushedToZero(true); |
| 50 | TargetCharacteristics noFlushingTargetCharacteristics; |
| 51 | noFlushingTargetCharacteristics.set_areSubnormalsFlushedToZero(false); |
| 52 | Fortran::common::LanguageFeatureControl languageFeatures; |
| 53 | std::set<std::string> tempNames; |
| 54 | FoldingContext flushingContext{messages, defaults, intrinsics, |
| 55 | flushingTargetCharacteristics, languageFeatures, tempNames}; |
| 56 | FoldingContext noFlushingContext{messages, defaults, intrinsics, |
| 57 | noFlushingTargetCharacteristics, languageFeatures, tempNames}; |
| 58 | |
| 59 | DynamicType r4{R4{}.GetType()}; |
| 60 | // Test subnormal argument flushing |
| 61 | if (auto callable{GetHostRuntimeWrapper("log" , r4, {r4})}) { |
| 62 | // Biggest IEEE 32bits subnormal power of two |
| 63 | const Scalar<R4> x1{Scalar<R4>::Word{0x00400000}}; |
| 64 | Scalar<R4> y1Flushing{CallHostRt<R4>(*callable, flushingContext, x1)}; |
| 65 | Scalar<R4> y1NoFlushing{CallHostRt<R4>(*callable, noFlushingContext, x1)}; |
| 66 | // We would expect y1Flushing to be NaN, but some libc logf implementation |
| 67 | // "workaround" subnormal flushing by returning a constant negative |
| 68 | // results for all subnormal values (-1.03972076416015625e2_4). In case of |
| 69 | // flushing, the result should still be different than -88 +/- 2%. |
| 70 | TEST(y1Flushing.IsInfinite() || |
| 71 | std::abs(host::CastFortranToHost<R4>(y1Flushing) + 88.) > 2); |
| 72 | TEST(!y1NoFlushing.IsInfinite() && |
| 73 | std::abs(host::CastFortranToHost<R4>(y1NoFlushing) + 88.) < 2); |
| 74 | } else { |
| 75 | TEST(false); |
| 76 | } |
| 77 | } else { |
| 78 | TEST(false); // Cannot run this test on the host |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | int main() { |
| 83 | RunOnTypes<TestGetScalarConstantValue, AllIntrinsicTypes>::Run(); |
| 84 | TestHostRuntimeSubnormalFlushing(); |
| 85 | return testing::Complete(); |
| 86 | } |
| 87 | |