2019-01-25 01:49:00 +08:00
|
|
|
#include "testing.h"
|
2020-02-25 23:11:52 +08:00
|
|
|
#include "../../lib/Evaluate/host.h"
|
|
|
|
#include "../../lib/Evaluate/intrinsics-library-templates.h"
|
|
|
|
#include "flang/Evaluate/call.h"
|
|
|
|
#include "flang/Evaluate/expression.h"
|
|
|
|
#include "flang/Evaluate/fold.h"
|
|
|
|
#include "flang/Evaluate/intrinsics.h"
|
|
|
|
#include "flang/Evaluate/tools.h"
|
2019-01-25 01:49:00 +08:00
|
|
|
#include <tuple>
|
|
|
|
|
|
|
|
using namespace Fortran::evaluate;
|
|
|
|
|
2019-01-25 19:24:31 +08:00
|
|
|
// helper to call functions on all types from tuple
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename... T> struct RunOnTypes {};
|
|
|
|
template <typename Test, typename... T>
|
2019-01-25 19:24:31 +08:00
|
|
|
struct RunOnTypes<Test, std::tuple<T...>> {
|
|
|
|
static void Run() { (..., Test::template Run<T>()); }
|
|
|
|
};
|
2019-01-25 01:49:00 +08:00
|
|
|
|
2019-02-02 00:30:23 +08:00
|
|
|
// test for fold.h GetScalarConstantValue function
|
2019-01-25 01:49:00 +08:00
|
|
|
struct TestGetScalarConstantValue {
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename T> static void Run() {
|
2019-01-25 01:49:00 +08:00
|
|
|
Expr<T> exprFullyTyped{Constant<T>{Scalar<T>{}}};
|
|
|
|
Expr<SomeKind<T::category>> exprSomeKind{exprFullyTyped};
|
|
|
|
Expr<SomeType> exprSomeType{exprSomeKind};
|
2019-02-02 05:37:49 +08:00
|
|
|
TEST(GetScalarConstantValue<T>(exprFullyTyped).has_value());
|
|
|
|
TEST(GetScalarConstantValue<T>(exprSomeKind).has_value());
|
|
|
|
TEST(GetScalarConstantValue<T>(exprSomeType).has_value());
|
2019-01-25 01:49:00 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
template <typename T>
|
2019-04-04 22:40:03 +08:00
|
|
|
static FunctionRef<T> CreateIntrinsicElementalCall(
|
|
|
|
const std::string &name, const Expr<T> &arg) {
|
|
|
|
Fortran::semantics::Attrs attrs;
|
|
|
|
attrs.set(Fortran::semantics::Attr::ELEMENTAL);
|
|
|
|
ActualArguments args{ActualArgument{AsGenericExpr(arg)}};
|
|
|
|
ProcedureDesignator intrinsic{
|
|
|
|
SpecificIntrinsic{name, T::GetType(), 0, attrs}};
|
|
|
|
return FunctionRef<T>{std::move(intrinsic), std::move(args)};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test flushSubnormalsToZero when folding with host runtime.
|
2020-01-28 10:18:45 +08:00
|
|
|
// Subnormal value flushing on host is handle in host.cpp
|
2019-04-04 22:40:03 +08:00
|
|
|
// HostFloatingPointEnvironment::SetUpHostFloatingPointEnvironment
|
|
|
|
|
2019-04-09 19:27:27 +08:00
|
|
|
// Dummy host runtime functions where subnormal flushing matters
|
2020-03-29 12:00:16 +08:00
|
|
|
float SubnormalFlusher1(float f) { // given f is subnormal
|
|
|
|
return 2.3 * f; // returns 0 if subnormal arguments are flushed to zero
|
2019-04-09 19:27:27 +08:00
|
|
|
}
|
|
|
|
|
2020-03-29 12:00:16 +08:00
|
|
|
float SubnormalFlusher2(float f) { // given f/2 is subnormal
|
|
|
|
return f / 2.3; // returns 0 if subnormal
|
2019-04-09 19:27:27 +08:00
|
|
|
}
|
|
|
|
|
2019-04-11 22:51:27 +08:00
|
|
|
void TestHostRuntimeSubnormalFlushing() {
|
2019-04-04 22:40:03 +08:00
|
|
|
using R4 = Type<TypeCategory::Real, 4>;
|
2019-04-09 19:27:27 +08:00
|
|
|
if constexpr (std::is_same_v<host::HostType<R4>, float>) {
|
2019-04-04 22:40:03 +08:00
|
|
|
Fortran::parser::CharBlock src;
|
|
|
|
Fortran::parser::ContextualMessages messages{src, nullptr};
|
2019-07-18 06:58:28 +08:00
|
|
|
Fortran::common::IntrinsicTypeDefaultKinds defaults;
|
2019-10-09 06:21:09 +08:00
|
|
|
auto intrinsics{Fortran::evaluate::IntrinsicProcTable::Configure(defaults)};
|
|
|
|
FoldingContext flushingContext{
|
|
|
|
messages, defaults, intrinsics, defaultRounding, true};
|
2019-07-18 06:58:28 +08:00
|
|
|
FoldingContext noFlushingContext{
|
2019-10-09 06:21:09 +08:00
|
|
|
messages, defaults, intrinsics, defaultRounding, false};
|
2019-04-04 22:40:03 +08:00
|
|
|
|
2019-04-09 19:27:27 +08:00
|
|
|
HostIntrinsicProceduresLibrary lib;
|
|
|
|
lib.AddProcedure(HostRuntimeIntrinsicProcedure{
|
|
|
|
"flusher_test1", SubnormalFlusher1, true});
|
|
|
|
lib.AddProcedure(HostRuntimeIntrinsicProcedure{
|
|
|
|
"flusher_test2", SubnormalFlusher2, true});
|
2019-04-04 22:40:03 +08:00
|
|
|
|
2019-04-09 19:27:27 +08:00
|
|
|
// Test subnormal argument flushing
|
|
|
|
if (auto callable{
|
|
|
|
lib.GetHostProcedureWrapper<Scalar, R4, R4>("flusher_test1")}) {
|
|
|
|
// Biggest IEEE 32bits subnormal power of two
|
|
|
|
host::HostType<R4> input1{5.87747175411144e-39};
|
|
|
|
const Scalar<R4> x1{host::CastHostToFortran<R4>(input1)};
|
|
|
|
Scalar<R4> y1Flushing{callable.value()(flushingContext, x1)};
|
|
|
|
Scalar<R4> y1NoFlushing{callable.value()(noFlushingContext, x1)};
|
|
|
|
TEST(y1Flushing.IsZero());
|
|
|
|
TEST(!y1NoFlushing.IsZero());
|
|
|
|
} else {
|
|
|
|
TEST(false);
|
|
|
|
}
|
|
|
|
// Test subnormal result flushing
|
|
|
|
if (auto callable{
|
|
|
|
lib.GetHostProcedureWrapper<Scalar, R4, R4>("flusher_test2")}) {
|
|
|
|
// Smallest (positive) non-subnormal IEEE 32 bit float value
|
|
|
|
host::HostType<R4> input2{1.1754944e-38};
|
|
|
|
const Scalar<R4> x2{host::CastHostToFortran<R4>(input2)};
|
|
|
|
Scalar<R4> y2Flushing{callable.value()(flushingContext, x2)};
|
|
|
|
Scalar<R4> y2NoFlushing{callable.value()(noFlushingContext, x2)};
|
|
|
|
TEST(y2Flushing.IsZero());
|
|
|
|
TEST(!y2NoFlushing.IsZero());
|
2019-04-04 22:40:03 +08:00
|
|
|
} else {
|
|
|
|
TEST(false);
|
|
|
|
}
|
|
|
|
} else {
|
2020-03-29 12:00:16 +08:00
|
|
|
TEST(false); // Cannot run this test on the host
|
2019-04-04 22:40:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-25 01:49:00 +08:00
|
|
|
int main() {
|
2019-02-02 00:30:23 +08:00
|
|
|
RunOnTypes<TestGetScalarConstantValue, AllIntrinsicTypes>::Run();
|
2019-04-11 22:51:27 +08:00
|
|
|
TestHostRuntimeSubnormalFlushing();
|
2019-01-25 01:49:00 +08:00
|
|
|
return testing::Complete();
|
|
|
|
}
|