xref: /llvm-project/flang/unittests/Evaluate/folding.cpp (revision 181eab27d244b9a9eb32d6716f9c38f7f3723356)
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