1ee5fa1f2SLuke Ireland #include "testing.h"
2ee5fa1f2SLuke Ireland #include "../../lib/Evaluate/host.h"
3ee5fa1f2SLuke Ireland #include "flang/Evaluate/call.h"
4ee5fa1f2SLuke Ireland #include "flang/Evaluate/expression.h"
5ee5fa1f2SLuke Ireland #include "flang/Evaluate/fold.h"
694d9a4fdSJean Perier #include "flang/Evaluate/intrinsics-library.h"
7ee5fa1f2SLuke Ireland #include "flang/Evaluate/intrinsics.h"
823c2bedfSPeter Klausler #include "flang/Evaluate/target.h"
9ee5fa1f2SLuke Ireland #include "flang/Evaluate/tools.h"
10ee5fa1f2SLuke Ireland #include <tuple>
11ee5fa1f2SLuke Ireland
12ee5fa1f2SLuke Ireland using namespace Fortran::evaluate;
13ee5fa1f2SLuke Ireland
14ee5fa1f2SLuke Ireland // helper to call functions on all types from tuple
15ee5fa1f2SLuke Ireland template <typename... T> struct RunOnTypes {};
16ee5fa1f2SLuke Ireland template <typename Test, typename... T>
17ee5fa1f2SLuke Ireland struct RunOnTypes<Test, std::tuple<T...>> {
RunRunOnTypes18ee5fa1f2SLuke Ireland static void Run() { (..., Test::template Run<T>()); }
19ee5fa1f2SLuke Ireland };
20ee5fa1f2SLuke Ireland
21ee5fa1f2SLuke Ireland // test for fold.h GetScalarConstantValue function
22ee5fa1f2SLuke Ireland struct TestGetScalarConstantValue {
RunTestGetScalarConstantValue23ee5fa1f2SLuke Ireland template <typename T> static void Run() {
24ee5fa1f2SLuke Ireland Expr<T> exprFullyTyped{Constant<T>{Scalar<T>{}}};
25ee5fa1f2SLuke Ireland Expr<SomeKind<T::category>> exprSomeKind{exprFullyTyped};
26ee5fa1f2SLuke Ireland Expr<SomeType> exprSomeType{exprSomeKind};
27ee5fa1f2SLuke Ireland TEST(GetScalarConstantValue<T>(exprFullyTyped).has_value());
28ee5fa1f2SLuke Ireland TEST(GetScalarConstantValue<T>(exprSomeKind).has_value());
29ee5fa1f2SLuke Ireland TEST(GetScalarConstantValue<T>(exprSomeType).has_value());
30ee5fa1f2SLuke Ireland }
31ee5fa1f2SLuke Ireland };
32ee5fa1f2SLuke Ireland
33ee5fa1f2SLuke Ireland template <typename T>
CallHostRt(HostRuntimeWrapper func,FoldingContext & context,Scalar<T> x)3494d9a4fdSJean Perier Scalar<T> CallHostRt(
3594d9a4fdSJean Perier HostRuntimeWrapper func, FoldingContext &context, Scalar<T> x) {
3694d9a4fdSJean Perier return GetScalarConstantValue<T>(
3794d9a4fdSJean Perier func(context, {AsGenericExpr(Constant<T>{x})}))
3894d9a4fdSJean Perier .value();
39ee5fa1f2SLuke Ireland }
40ee5fa1f2SLuke Ireland
TestHostRuntimeSubnormalFlushing()41ee5fa1f2SLuke Ireland void TestHostRuntimeSubnormalFlushing() {
42ee5fa1f2SLuke Ireland using R4 = Type<TypeCategory::Real, 4>;
43ee5fa1f2SLuke Ireland if constexpr (std::is_same_v<host::HostType<R4>, float>) {
44ee5fa1f2SLuke Ireland Fortran::parser::CharBlock src;
45ee5fa1f2SLuke Ireland Fortran::parser::ContextualMessages messages{src, nullptr};
46ee5fa1f2SLuke Ireland Fortran::common::IntrinsicTypeDefaultKinds defaults;
47ee5fa1f2SLuke Ireland auto intrinsics{Fortran::evaluate::IntrinsicProcTable::Configure(defaults)};
4823c2bedfSPeter Klausler TargetCharacteristics flushingTargetCharacteristics;
4923c2bedfSPeter Klausler flushingTargetCharacteristics.set_areSubnormalsFlushedToZero(true);
5023c2bedfSPeter Klausler TargetCharacteristics noFlushingTargetCharacteristics;
5123c2bedfSPeter Klausler noFlushingTargetCharacteristics.set_areSubnormalsFlushedToZero(false);
521c91d9bdSPeter Klausler Fortran::common::LanguageFeatureControl languageFeatures;
53*181eab27SjeanPerier std::set<std::string> tempNames;
541c91d9bdSPeter Klausler FoldingContext flushingContext{messages, defaults, intrinsics,
55*181eab27SjeanPerier flushingTargetCharacteristics, languageFeatures, tempNames};
561c91d9bdSPeter Klausler FoldingContext noFlushingContext{messages, defaults, intrinsics,
57*181eab27SjeanPerier noFlushingTargetCharacteristics, languageFeatures, tempNames};
58ee5fa1f2SLuke Ireland
5994d9a4fdSJean Perier DynamicType r4{R4{}.GetType()};
60ee5fa1f2SLuke Ireland // Test subnormal argument flushing
6194d9a4fdSJean Perier if (auto callable{GetHostRuntimeWrapper("log", r4, {r4})}) {
62ee5fa1f2SLuke Ireland // Biggest IEEE 32bits subnormal power of two
6394d9a4fdSJean Perier const Scalar<R4> x1{Scalar<R4>::Word{0x00400000}};
6494d9a4fdSJean Perier Scalar<R4> y1Flushing{CallHostRt<R4>(*callable, flushingContext, x1)};
6594d9a4fdSJean Perier Scalar<R4> y1NoFlushing{CallHostRt<R4>(*callable, noFlushingContext, x1)};
6694d9a4fdSJean Perier // We would expect y1Flushing to be NaN, but some libc logf implementation
6794d9a4fdSJean Perier // "workaround" subnormal flushing by returning a constant negative
6894d9a4fdSJean Perier // results for all subnormal values (-1.03972076416015625e2_4). In case of
6994d9a4fdSJean Perier // flushing, the result should still be different than -88 +/- 2%.
7094d9a4fdSJean Perier TEST(y1Flushing.IsInfinite() ||
7194d9a4fdSJean Perier std::abs(host::CastFortranToHost<R4>(y1Flushing) + 88.) > 2);
7294d9a4fdSJean Perier TEST(!y1NoFlushing.IsInfinite() &&
7394d9a4fdSJean Perier std::abs(host::CastFortranToHost<R4>(y1NoFlushing) + 88.) < 2);
74ee5fa1f2SLuke Ireland } else {
75ee5fa1f2SLuke Ireland TEST(false);
76ee5fa1f2SLuke Ireland }
77ee5fa1f2SLuke Ireland } else {
78ee5fa1f2SLuke Ireland TEST(false); // Cannot run this test on the host
79ee5fa1f2SLuke Ireland }
80ee5fa1f2SLuke Ireland }
81ee5fa1f2SLuke Ireland
main()82ee5fa1f2SLuke Ireland int main() {
83ee5fa1f2SLuke Ireland RunOnTypes<TestGetScalarConstantValue, AllIntrinsicTypes>::Run();
84ee5fa1f2SLuke Ireland TestHostRuntimeSubnormalFlushing();
85ee5fa1f2SLuke Ireland return testing::Complete();
86ee5fa1f2SLuke Ireland }
87