#include "testing.h" #include "../../lib/Evaluate/host.h" #include "flang/Evaluate/call.h" #include "flang/Evaluate/expression.h" #include "flang/Evaluate/fold.h" #include "flang/Evaluate/intrinsics-library.h" #include "flang/Evaluate/intrinsics.h" #include "flang/Evaluate/tools.h" #include using namespace Fortran::evaluate; // helper to call functions on all types from tuple template struct RunOnTypes {}; template struct RunOnTypes> { static void Run() { (..., Test::template Run()); } }; // test for fold.h GetScalarConstantValue function struct TestGetScalarConstantValue { template static void Run() { Expr exprFullyTyped{Constant{Scalar{}}}; Expr> exprSomeKind{exprFullyTyped}; Expr exprSomeType{exprSomeKind}; TEST(GetScalarConstantValue(exprFullyTyped).has_value()); TEST(GetScalarConstantValue(exprSomeKind).has_value()); TEST(GetScalarConstantValue(exprSomeType).has_value()); } }; template Scalar CallHostRt( HostRuntimeWrapper func, FoldingContext &context, Scalar x) { return GetScalarConstantValue( func(context, {AsGenericExpr(Constant{x})})) .value(); } void TestHostRuntimeSubnormalFlushing() { using R4 = Type; if constexpr (std::is_same_v, float>) { Fortran::parser::CharBlock src; Fortran::parser::ContextualMessages messages{src, nullptr}; Fortran::common::IntrinsicTypeDefaultKinds defaults; auto intrinsics{Fortran::evaluate::IntrinsicProcTable::Configure(defaults)}; FoldingContext flushingContext{ messages, defaults, intrinsics, defaultRounding, true}; FoldingContext noFlushingContext{ messages, defaults, intrinsics, defaultRounding, false}; DynamicType r4{R4{}.GetType()}; // Test subnormal argument flushing if (auto callable{GetHostRuntimeWrapper("log", r4, {r4})}) { // Biggest IEEE 32bits subnormal power of two const Scalar x1{Scalar::Word{0x00400000}}; Scalar y1Flushing{CallHostRt(*callable, flushingContext, x1)}; Scalar y1NoFlushing{CallHostRt(*callable, noFlushingContext, x1)}; // We would expect y1Flushing to be NaN, but some libc logf implementation // "workaround" subnormal flushing by returning a constant negative // results for all subnormal values (-1.03972076416015625e2_4). In case of // flushing, the result should still be different than -88 +/- 2%. TEST(y1Flushing.IsInfinite() || std::abs(host::CastFortranToHost(y1Flushing) + 88.) > 2); TEST(!y1NoFlushing.IsInfinite() && std::abs(host::CastFortranToHost(y1NoFlushing) + 88.) < 2); } else { TEST(false); } } else { TEST(false); // Cannot run this test on the host } } int main() { RunOnTypes::Run(); TestHostRuntimeSubnormalFlushing(); return testing::Complete(); }