forked from OSchip/llvm-project
80 lines
3.0 KiB
C++
80 lines
3.0 KiB
C++
#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 <tuple>
|
|
|
|
using namespace Fortran::evaluate;
|
|
|
|
// helper to call functions on all types from tuple
|
|
template <typename... T> struct RunOnTypes {};
|
|
template <typename Test, typename... T>
|
|
struct RunOnTypes<Test, std::tuple<T...>> {
|
|
static void Run() { (..., Test::template Run<T>()); }
|
|
};
|
|
|
|
// test for fold.h GetScalarConstantValue function
|
|
struct TestGetScalarConstantValue {
|
|
template <typename T> static void Run() {
|
|
Expr<T> exprFullyTyped{Constant<T>{Scalar<T>{}}};
|
|
Expr<SomeKind<T::category>> exprSomeKind{exprFullyTyped};
|
|
Expr<SomeType> exprSomeType{exprSomeKind};
|
|
TEST(GetScalarConstantValue<T>(exprFullyTyped).has_value());
|
|
TEST(GetScalarConstantValue<T>(exprSomeKind).has_value());
|
|
TEST(GetScalarConstantValue<T>(exprSomeType).has_value());
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
Scalar<T> CallHostRt(
|
|
HostRuntimeWrapper func, FoldingContext &context, Scalar<T> x) {
|
|
return GetScalarConstantValue<T>(
|
|
func(context, {AsGenericExpr(Constant<T>{x})}))
|
|
.value();
|
|
}
|
|
|
|
void TestHostRuntimeSubnormalFlushing() {
|
|
using R4 = Type<TypeCategory::Real, 4>;
|
|
if constexpr (std::is_same_v<host::HostType<R4>, 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<R4> x1{Scalar<R4>::Word{0x00400000}};
|
|
Scalar<R4> y1Flushing{CallHostRt<R4>(*callable, flushingContext, x1)};
|
|
Scalar<R4> y1NoFlushing{CallHostRt<R4>(*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<R4>(y1Flushing) + 88.) > 2);
|
|
TEST(!y1NoFlushing.IsInfinite() &&
|
|
std::abs(host::CastFortranToHost<R4>(y1NoFlushing) + 88.) < 2);
|
|
} else {
|
|
TEST(false);
|
|
}
|
|
} else {
|
|
TEST(false); // Cannot run this test on the host
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
RunOnTypes<TestGetScalarConstantValue, AllIntrinsicTypes>::Run();
|
|
TestHostRuntimeSubnormalFlushing();
|
|
return testing::Complete();
|
|
}
|