2 #include "../../lib/Evaluate/host.h"
3 #include "flang/Evaluate/call.h"
4 #include "flang/Evaluate/expression.h"
5 #include "flang/Evaluate/fold.h"
6 #include "flang/Evaluate/intrinsics-library.h"
7 #include "flang/Evaluate/intrinsics.h"
8 #include "flang/Evaluate/target.h"
9 #include "flang/Evaluate/tools.h"
12 using namespace Fortran::evaluate
;
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
>()); }
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());
35 HostRuntimeWrapper func
, FoldingContext
&context
, Scalar
<T
> x
) {
36 return GetScalarConstantValue
<T
>(
37 func(context
, {AsGenericExpr(Constant
<T
>{x
})}))
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
};
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);
78 TEST(false); // Cannot run this test on the host
83 RunOnTypes
<TestGetScalarConstantValue
, AllIntrinsicTypes
>::Run();
84 TestHostRuntimeSubnormalFlushing();
85 return testing::Complete();