[flang] Use a common enum class in evaluate and runtime for type category.

Original-commit: flang-compiler/f18@5012e652af
Reviewed-on: https://github.com/flang-compiler/f18/pull/162
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-08-01 09:45:59 -07:00
parent 2dce7b9554
commit 51b3ceaafe
13 changed files with 295 additions and 261 deletions

View File

@ -0,0 +1,29 @@
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FORTRAN_COMMON_FORTRAN_H_
#define FORTRAN_COMMON_FORTRAN_H_
// Fortran language concepts that are used in many phases are defined
// once here to avoid redundancy and needless translation.
#include "idioms.h"
namespace Fortran::common {
// Fortran has five kinds of intrinsic data, and the derived types.
ENUM_CLASS(TypeCategory, Integer, Real, Complex, Character, Logical, Derived)
} // namespace Fortran::common
#endif // FORTRAN_COMMON_FORTRAN_H_

View File

@ -25,20 +25,21 @@ namespace Fortran::evaluate {
// An expression of some specific result type.
template<typename A> class Expr;
template<int KIND> using IntegerExpr = Expr<Type<Category::Integer, KIND>>;
template<int KIND> using IntegerExpr = Expr<Type<TypeCategory::Integer, KIND>>;
using DefaultIntegerExpr = IntegerExpr<DefaultInteger::kind>;
template<int KIND> using RealExpr = Expr<Type<Category::Real, KIND>>;
template<int KIND> using ComplexExpr = Expr<Type<Category::Complex, KIND>>;
template<int KIND> using CharacterExpr = Expr<Type<Category::Character, KIND>>;
template<int KIND> using LogicalExpr = Expr<Type<Category::Logical, KIND>>;
template<int KIND> using RealExpr = Expr<Type<TypeCategory::Real, KIND>>;
template<int KIND> using ComplexExpr = Expr<Type<TypeCategory::Complex, KIND>>;
template<int KIND>
using CharacterExpr = Expr<Type<TypeCategory::Character, KIND>>;
template<int KIND> using LogicalExpr = Expr<Type<TypeCategory::Logical, KIND>>;
// An expression whose result is within one particular type category and
// of any supported kind.
using AnyKindIntegerExpr = Expr<AnyKindType<Category::Integer>>;
using AnyKindRealExpr = Expr<AnyKindType<Category::Real>>;
using AnyKindComplexExpr = Expr<AnyKindType<Category::Complex>>;
using AnyKindCharacterExpr = Expr<AnyKindType<Category::Character>>;
using AnyKindLogicalExpr = Expr<AnyKindType<Category::Logical>>;
using AnyKindIntegerExpr = Expr<AnyKindType<TypeCategory::Integer>>;
using AnyKindRealExpr = Expr<AnyKindType<TypeCategory::Real>>;
using AnyKindComplexExpr = Expr<AnyKindType<TypeCategory::Complex>>;
using AnyKindCharacterExpr = Expr<AnyKindType<TypeCategory::Character>>;
using AnyKindLogicalExpr = Expr<AnyKindType<TypeCategory::Logical>>;
// A completely generic expression.
struct GenericExpr;

View File

@ -44,12 +44,12 @@ std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) {
return o;
}
template<Category CAT>
template<TypeCategory CAT>
std::ostream &Expr<AnyKindType<CAT>>::Dump(std::ostream &o) const {
return DumpExpr(o, u);
}
template<Category CAT>
template<TypeCategory CAT>
std::ostream &CategoryComparison<CAT>::Dump(std::ostream &o) const {
return DumpExpr(o, u);
}
@ -231,7 +231,7 @@ auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
template<int KIND>
auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
const ScalarConstant<Category::Integer> &c) -> std::optional<Scalar> {
const ScalarConstant<TypeCategory::Integer> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::ConvertSigned(x)};
@ -246,7 +246,7 @@ auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
template<int KIND>
auto IntegerExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
const ScalarConstant<Category::Real> &c) -> std::optional<Scalar> {
const ScalarConstant<TypeCategory::Real> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{x.template ToInteger<Scalar>()};
@ -402,7 +402,7 @@ static void RealFlagWarnings(
template<int KIND>
auto RealExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
const ScalarConstant<Category::Integer> &c) -> std::optional<Scalar> {
const ScalarConstant<TypeCategory::Integer> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::FromInteger(x)};
@ -414,7 +414,7 @@ auto RealExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
template<int KIND>
auto RealExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
const ScalarConstant<Category::Real> &c) -> std::optional<Scalar> {
const ScalarConstant<TypeCategory::Real> &c) -> std::optional<Scalar> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::Convert(x)};
@ -470,7 +470,7 @@ auto RealExpr<KIND>::Power::FoldScalar(FoldingContext &context, const Scalar &a,
template<int KIND>
auto RealExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
const Scalar &a, const ScalarConstant<Category::Integer> &b)
const Scalar &a, const ScalarConstant<TypeCategory::Integer> &b)
-> std::optional<Scalar> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar> {
@ -580,7 +580,7 @@ auto ComplexExpr<KIND>::Power::FoldScalar(FoldingContext &context,
template<int KIND>
auto ComplexExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
const Scalar &a, const ScalarConstant<Category::Integer> &b)
const Scalar &a, const ScalarConstant<TypeCategory::Integer> &b)
-> std::optional<Scalar> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar> {
@ -672,7 +672,7 @@ template<typename A>
auto Comparison<A>::FoldScalar(FoldingContext &c,
const OperandScalarConstant &a, const OperandScalarConstant &b)
-> std::optional<Scalar> {
if constexpr (A::category == Category::Integer) {
if constexpr (A::category == TypeCategory::Integer) {
switch (a.CompareSigned(b)) {
case Ordering::Less:
return {opr == RelationalOperator::LE || opr == RelationalOperator::LE ||
@ -685,7 +685,7 @@ auto Comparison<A>::FoldScalar(FoldingContext &c,
opr == RelationalOperator::GT};
}
}
if constexpr (A::category == Category::Real) {
if constexpr (A::category == TypeCategory::Real) {
switch (a.Compare(b)) {
case Relation::Less:
return {opr == RelationalOperator::LE || opr == RelationalOperator::LE ||
@ -699,12 +699,12 @@ auto Comparison<A>::FoldScalar(FoldingContext &c,
case Relation::Unordered: return std::nullopt;
}
}
if constexpr (A::category == Category::Complex) {
if constexpr (A::category == TypeCategory::Complex) {
bool eqOk{opr == RelationalOperator::LE || opr == RelationalOperator::EQ ||
opr == RelationalOperator::GE};
return {eqOk == a.Equals(b)};
}
if constexpr (A::category == Category::Character) {
if constexpr (A::category == TypeCategory::Character) {
switch (Compare(a, b)) {
case Ordering::Less:
return {opr == RelationalOperator::LE || opr == RelationalOperator::LE ||
@ -781,7 +781,7 @@ std::optional<GenericScalar> GenericExpr::ScalarValue() const {
u);
}
template<Category CAT>
template<TypeCategory CAT>
auto Expr<AnyKindType<CAT>>::ScalarValue() const -> std::optional<Scalar> {
return std::visit(
[](const auto &x) -> std::optional<Scalar> {
@ -793,7 +793,7 @@ auto Expr<AnyKindType<CAT>>::ScalarValue() const -> std::optional<Scalar> {
u);
}
template<Category CAT>
template<TypeCategory CAT>
auto Expr<AnyKindType<CAT>>::Fold(FoldingContext &context)
-> std::optional<Scalar> {
return std::visit(
@ -817,47 +817,47 @@ std::optional<GenericScalar> GenericExpr::Fold(FoldingContext &context) {
u);
}
template class Expr<AnyKindType<Category::Integer>>;
template class Expr<AnyKindType<Category::Real>>;
template class Expr<AnyKindType<Category::Complex>>;
template class Expr<AnyKindType<Category::Character>>;
template class Expr<AnyKindType<Category::Logical>>;
template class Expr<AnyKindType<TypeCategory::Integer>>;
template class Expr<AnyKindType<TypeCategory::Real>>;
template class Expr<AnyKindType<TypeCategory::Complex>>;
template class Expr<AnyKindType<TypeCategory::Character>>;
template class Expr<AnyKindType<TypeCategory::Logical>>;
template class Expr<Type<Category::Integer, 1>>;
template class Expr<Type<Category::Integer, 2>>;
template class Expr<Type<Category::Integer, 4>>;
template class Expr<Type<Category::Integer, 8>>;
template class Expr<Type<Category::Integer, 16>>;
template class Expr<Type<Category::Real, 2>>;
template class Expr<Type<Category::Real, 4>>;
template class Expr<Type<Category::Real, 8>>;
template class Expr<Type<Category::Real, 10>>;
template class Expr<Type<Category::Real, 16>>;
template class Expr<Type<Category::Complex, 2>>;
template class Expr<Type<Category::Complex, 4>>;
template class Expr<Type<Category::Complex, 8>>;
template class Expr<Type<Category::Complex, 10>>;
template class Expr<Type<Category::Complex, 16>>;
template class Expr<Type<Category::Character, 1>>;
template class Expr<Type<Category::Logical, 1>>;
template class Expr<Type<Category::Logical, 2>>;
template class Expr<Type<Category::Logical, 4>>;
template class Expr<Type<Category::Logical, 8>>;
template class Expr<Type<TypeCategory::Integer, 1>>;
template class Expr<Type<TypeCategory::Integer, 2>>;
template class Expr<Type<TypeCategory::Integer, 4>>;
template class Expr<Type<TypeCategory::Integer, 8>>;
template class Expr<Type<TypeCategory::Integer, 16>>;
template class Expr<Type<TypeCategory::Real, 2>>;
template class Expr<Type<TypeCategory::Real, 4>>;
template class Expr<Type<TypeCategory::Real, 8>>;
template class Expr<Type<TypeCategory::Real, 10>>;
template class Expr<Type<TypeCategory::Real, 16>>;
template class Expr<Type<TypeCategory::Complex, 2>>;
template class Expr<Type<TypeCategory::Complex, 4>>;
template class Expr<Type<TypeCategory::Complex, 8>>;
template class Expr<Type<TypeCategory::Complex, 10>>;
template class Expr<Type<TypeCategory::Complex, 16>>;
template class Expr<Type<TypeCategory::Character, 1>>;
template class Expr<Type<TypeCategory::Logical, 1>>;
template class Expr<Type<TypeCategory::Logical, 2>>;
template class Expr<Type<TypeCategory::Logical, 4>>;
template class Expr<Type<TypeCategory::Logical, 8>>;
template struct Comparison<Type<Category::Integer, 1>>;
template struct Comparison<Type<Category::Integer, 2>>;
template struct Comparison<Type<Category::Integer, 4>>;
template struct Comparison<Type<Category::Integer, 8>>;
template struct Comparison<Type<Category::Integer, 16>>;
template struct Comparison<Type<Category::Real, 2>>;
template struct Comparison<Type<Category::Real, 4>>;
template struct Comparison<Type<Category::Real, 8>>;
template struct Comparison<Type<Category::Real, 10>>;
template struct Comparison<Type<Category::Real, 16>>;
template struct Comparison<Type<Category::Complex, 2>>;
template struct Comparison<Type<Category::Complex, 4>>;
template struct Comparison<Type<Category::Complex, 8>>;
template struct Comparison<Type<Category::Complex, 10>>;
template struct Comparison<Type<Category::Complex, 16>>;
template struct Comparison<Type<Category::Character, 1>>;
template struct Comparison<Type<TypeCategory::Integer, 1>>;
template struct Comparison<Type<TypeCategory::Integer, 2>>;
template struct Comparison<Type<TypeCategory::Integer, 4>>;
template struct Comparison<Type<TypeCategory::Integer, 8>>;
template struct Comparison<Type<TypeCategory::Integer, 16>>;
template struct Comparison<Type<TypeCategory::Real, 2>>;
template struct Comparison<Type<TypeCategory::Real, 4>>;
template struct Comparison<Type<TypeCategory::Real, 8>>;
template struct Comparison<Type<TypeCategory::Real, 10>>;
template struct Comparison<Type<TypeCategory::Real, 16>>;
template struct Comparison<Type<TypeCategory::Complex, 2>>;
template struct Comparison<Type<TypeCategory::Complex, 4>>;
template struct Comparison<Type<TypeCategory::Complex, 8>>;
template struct Comparison<Type<TypeCategory::Complex, 10>>;
template struct Comparison<Type<TypeCategory::Complex, 16>>;
template struct Comparison<Type<TypeCategory::Character, 1>>;
} // namespace Fortran::evaluate

View File

@ -100,24 +100,25 @@ private:
// Per-category expressions
template<int KIND> class Expr<Type<Category::Integer, KIND>> {
template<int KIND> class Expr<Type<TypeCategory::Integer, KIND>> {
public:
using Result = Type<Category::Integer, KIND>;
using Result = Type<TypeCategory::Integer, KIND>;
using Scalar = typename Result::Value;
using FoldableTrait = std::true_type;
struct ConvertInteger
: public Unary<ConvertInteger, Result, AnyKindType<Category::Integer>> {
using Unary<ConvertInteger, Result, AnyKindType<Category::Integer>>::Unary;
: public Unary<ConvertInteger, Result, AnyKindType<TypeCategory::Integer>> {
using Unary<ConvertInteger, Result,
AnyKindType<TypeCategory::Integer>>::Unary;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const ScalarConstant<Category::Integer> &);
FoldingContext &, const ScalarConstant<TypeCategory::Integer> &);
};
struct ConvertReal
: public Unary<ConvertReal, Result, AnyKindType<Category::Real>> {
using Unary<ConvertReal, Result, AnyKindType<Category::Real>>::Unary;
: public Unary<ConvertReal, Result, AnyKindType<TypeCategory::Real>> {
using Unary<ConvertReal, Result, AnyKindType<TypeCategory::Real>>::Unary;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const ScalarConstant<Category::Real> &);
FoldingContext &, const ScalarConstant<TypeCategory::Real> &);
};
template<typename CRTP> using Un = Unary<CRTP, Result>;
@ -203,9 +204,9 @@ private:
u_;
};
template<int KIND> class Expr<Type<Category::Real, KIND>> {
template<int KIND> class Expr<Type<TypeCategory::Real, KIND>> {
public:
using Result = Type<Category::Real, KIND>;
using Result = Type<TypeCategory::Real, KIND>;
using Scalar = typename Result::Value;
using FoldableTrait = std::true_type;
@ -213,16 +214,17 @@ public:
// and part access operations (resp.). Conversions between kinds of
// Complex are done via decomposition to Real and reconstruction.
struct ConvertInteger
: public Unary<ConvertInteger, Result, AnyKindType<Category::Integer>> {
using Unary<ConvertInteger, Result, AnyKindType<Category::Integer>>::Unary;
: public Unary<ConvertInteger, Result, AnyKindType<TypeCategory::Integer>> {
using Unary<ConvertInteger, Result,
AnyKindType<TypeCategory::Integer>>::Unary;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const ScalarConstant<Category::Integer> &);
FoldingContext &, const ScalarConstant<TypeCategory::Integer> &);
};
struct ConvertReal
: public Unary<ConvertReal, Result, AnyKindType<Category::Real>> {
using Unary<ConvertReal, Result, AnyKindType<Category::Real>>::Unary;
: public Unary<ConvertReal, Result, AnyKindType<TypeCategory::Real>> {
using Unary<ConvertReal, Result, AnyKindType<TypeCategory::Real>>::Unary;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const ScalarConstant<Category::Real> &);
FoldingContext &, const ScalarConstant<TypeCategory::Real> &);
};
template<typename CRTP> using Un = Unary<CRTP, Result>;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
@ -261,12 +263,12 @@ public:
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
struct IntPower
: public Binary<IntPower, Result, Result, AnyKindType<Category::Integer>> {
struct IntPower : public Binary<IntPower, Result, Result,
AnyKindType<TypeCategory::Integer>> {
using Binary<IntPower, Result, Result,
AnyKindType<Category::Integer>>::Binary;
AnyKindType<TypeCategory::Integer>>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
const ScalarConstant<Category::Integer> &);
const ScalarConstant<TypeCategory::Integer> &);
};
struct Max : public Bin<Max> {
using Bin<Max>::Bin;
@ -278,7 +280,7 @@ public:
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
using Cplx = Type<Category::Complex, KIND>;
using Cplx = Type<TypeCategory::Complex, KIND>;
using CplxScalar = typename Cplx::Value;
template<typename CRTP> using CplxUn = Unary<CRTP, Result, Cplx>;
struct RealPart : public CplxUn<RealPart> {
@ -321,9 +323,9 @@ private:
u_;
};
template<int KIND> class Expr<Type<Category::Complex, KIND>> {
template<int KIND> class Expr<Type<TypeCategory::Complex, KIND>> {
public:
using Result = Type<Category::Complex, KIND>;
using Result = Type<TypeCategory::Complex, KIND>;
using Scalar = typename Result::Value;
using FoldableTrait = std::true_type;
template<typename CRTP> using Un = Unary<CRTP, Result>;
@ -363,14 +365,14 @@ public:
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
};
struct IntPower
: public Binary<IntPower, Result, Result, AnyKindType<Category::Integer>> {
struct IntPower : public Binary<IntPower, Result, Result,
AnyKindType<TypeCategory::Integer>> {
using Binary<IntPower, Result, Result,
AnyKindType<Category::Integer>>::Binary;
AnyKindType<TypeCategory::Integer>>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
const ScalarConstant<Category::Integer> &);
const ScalarConstant<TypeCategory::Integer> &);
};
using Part = Type<Category::Real, KIND>;
using Part = Type<TypeCategory::Real, KIND>;
using PartScalar = typename Part::Value;
struct CMPLX : public Binary<CMPLX, Result, Part> {
using Binary<CMPLX, Result, Part>::Binary;
@ -397,9 +399,9 @@ private:
u_;
};
template<int KIND> class Expr<Type<Category::Character, KIND>> {
template<int KIND> class Expr<Type<TypeCategory::Character, KIND>> {
public:
using Result = Type<Category::Character, KIND>;
using Result = Type<TypeCategory::Character, KIND>;
using Scalar = typename Result::Value;
using FoldableTrait = std::true_type;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
@ -447,8 +449,8 @@ ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
template<typename A>
struct Comparison
: public Binary<Comparison<A>, Type<Category::Logical, 1>, A> {
using Base = Binary<Comparison, Type<Category::Logical, 1>, A>;
: public Binary<Comparison<A>, Type<TypeCategory::Logical, 1>, A> {
using Base = Binary<Comparison, Type<TypeCategory::Logical, 1>, A>;
using typename Base::Scalar;
using OperandScalarConstant = typename Base::LeftScalar;
CLASS_BOILERPLATE(Comparison)
@ -461,27 +463,27 @@ struct Comparison
RelationalOperator opr;
};
extern template struct Comparison<Type<Category::Integer, 1>>;
extern template struct Comparison<Type<Category::Integer, 2>>;
extern template struct Comparison<Type<Category::Integer, 4>>;
extern template struct Comparison<Type<Category::Integer, 8>>;
extern template struct Comparison<Type<Category::Integer, 16>>;
extern template struct Comparison<Type<Category::Real, 2>>;
extern template struct Comparison<Type<Category::Real, 4>>;
extern template struct Comparison<Type<Category::Real, 8>>;
extern template struct Comparison<Type<Category::Real, 10>>;
extern template struct Comparison<Type<Category::Real, 16>>;
extern template struct Comparison<Type<Category::Complex, 2>>;
extern template struct Comparison<Type<Category::Complex, 4>>;
extern template struct Comparison<Type<Category::Complex, 8>>;
extern template struct Comparison<Type<Category::Complex, 10>>;
extern template struct Comparison<Type<Category::Complex, 16>>;
extern template struct Comparison<Type<Category::Character, 1>>;
extern template struct Comparison<Type<TypeCategory::Integer, 1>>;
extern template struct Comparison<Type<TypeCategory::Integer, 2>>;
extern template struct Comparison<Type<TypeCategory::Integer, 4>>;
extern template struct Comparison<Type<TypeCategory::Integer, 8>>;
extern template struct Comparison<Type<TypeCategory::Integer, 16>>;
extern template struct Comparison<Type<TypeCategory::Real, 2>>;
extern template struct Comparison<Type<TypeCategory::Real, 4>>;
extern template struct Comparison<Type<TypeCategory::Real, 8>>;
extern template struct Comparison<Type<TypeCategory::Real, 10>>;
extern template struct Comparison<Type<TypeCategory::Real, 16>>;
extern template struct Comparison<Type<TypeCategory::Complex, 2>>;
extern template struct Comparison<Type<TypeCategory::Complex, 4>>;
extern template struct Comparison<Type<TypeCategory::Complex, 8>>;
extern template struct Comparison<Type<TypeCategory::Complex, 10>>;
extern template struct Comparison<Type<TypeCategory::Complex, 16>>;
extern template struct Comparison<Type<TypeCategory::Character, 1>>;
// Dynamically polymorphic comparisons whose operands are expressions of
// the same supported kind of a particular type category.
template<Category CAT> struct CategoryComparison {
using Scalar = typename Type<Category::Logical, 1>::Value;
template<TypeCategory CAT> struct CategoryComparison {
using Scalar = typename Type<TypeCategory::Logical, 1>::Value;
CLASS_BOILERPLATE(CategoryComparison)
template<int KIND> using KindComparison = Comparison<Type<CAT, KIND>>;
template<int KIND> CategoryComparison(const KindComparison<KIND> &x) : u{x} {}
@ -491,9 +493,9 @@ template<Category CAT> struct CategoryComparison {
typename KindsVariant<CAT, KindComparison>::type u;
};
template<int KIND> class Expr<Type<Category::Logical, KIND>> {
template<int KIND> class Expr<Type<TypeCategory::Logical, KIND>> {
public:
using Result = Type<Category::Logical, KIND>;
using Result = Type<TypeCategory::Logical, KIND>;
using Scalar = typename Result::Value;
using FoldableTrait = std::true_type;
struct Not : Unary<Not, Result> {
@ -525,9 +527,9 @@ public:
CLASS_BOILERPLATE(Expr)
Expr(const Scalar &x) : u_{x} {}
Expr(bool x) : u_{Scalar{x}} {}
template<Category CAT, int K>
template<TypeCategory CAT, int K>
Expr(const Comparison<Type<CAT, K>> &x) : u_{CategoryComparison<CAT>{x}} {}
template<Category CAT, int K>
template<TypeCategory CAT, int K>
Expr(Comparison<Type<CAT, K>> &&x)
: u_{CategoryComparison<CAT>{std::move(x)}} {}
template<typename A> Expr(const A &x) : u_(x) {}
@ -543,36 +545,37 @@ public:
private:
std::variant<Scalar, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Not, And, Or, Eqv, Neqv,
CategoryComparison<Category::Integer>, CategoryComparison<Category::Real>,
CategoryComparison<Category::Complex>,
CategoryComparison<Category::Character>>
CategoryComparison<TypeCategory::Integer>,
CategoryComparison<TypeCategory::Real>,
CategoryComparison<TypeCategory::Complex>,
CategoryComparison<TypeCategory::Character>>
u_;
};
extern template class Expr<Type<Category::Integer, 1>>;
extern template class Expr<Type<Category::Integer, 2>>;
extern template class Expr<Type<Category::Integer, 4>>;
extern template class Expr<Type<Category::Integer, 8>>;
extern template class Expr<Type<Category::Integer, 16>>;
extern template class Expr<Type<Category::Real, 2>>;
extern template class Expr<Type<Category::Real, 4>>;
extern template class Expr<Type<Category::Real, 8>>;
extern template class Expr<Type<Category::Real, 10>>;
extern template class Expr<Type<Category::Real, 16>>;
extern template class Expr<Type<Category::Complex, 2>>;
extern template class Expr<Type<Category::Complex, 4>>;
extern template class Expr<Type<Category::Complex, 8>>;
extern template class Expr<Type<Category::Complex, 10>>;
extern template class Expr<Type<Category::Complex, 16>>;
extern template class Expr<Type<Category::Character, 1>>;
extern template class Expr<Type<Category::Logical, 1>>;
extern template class Expr<Type<Category::Logical, 2>>;
extern template class Expr<Type<Category::Logical, 4>>;
extern template class Expr<Type<Category::Logical, 8>>;
extern template class Expr<Type<TypeCategory::Integer, 1>>;
extern template class Expr<Type<TypeCategory::Integer, 2>>;
extern template class Expr<Type<TypeCategory::Integer, 4>>;
extern template class Expr<Type<TypeCategory::Integer, 8>>;
extern template class Expr<Type<TypeCategory::Integer, 16>>;
extern template class Expr<Type<TypeCategory::Real, 2>>;
extern template class Expr<Type<TypeCategory::Real, 4>>;
extern template class Expr<Type<TypeCategory::Real, 8>>;
extern template class Expr<Type<TypeCategory::Real, 10>>;
extern template class Expr<Type<TypeCategory::Real, 16>>;
extern template class Expr<Type<TypeCategory::Complex, 2>>;
extern template class Expr<Type<TypeCategory::Complex, 4>>;
extern template class Expr<Type<TypeCategory::Complex, 8>>;
extern template class Expr<Type<TypeCategory::Complex, 10>>;
extern template class Expr<Type<TypeCategory::Complex, 16>>;
extern template class Expr<Type<TypeCategory::Character, 1>>;
extern template class Expr<Type<TypeCategory::Logical, 1>>;
extern template class Expr<Type<TypeCategory::Logical, 2>>;
extern template class Expr<Type<TypeCategory::Logical, 4>>;
extern template class Expr<Type<TypeCategory::Logical, 8>>;
// Dynamically polymorphic expressions that can hold any supported kind
// of a specific intrinsic type category.
template<Category CAT> class Expr<AnyKindType<CAT>> {
template<TypeCategory CAT> class Expr<AnyKindType<CAT>> {
public:
using Result = AnyKindType<CAT>;
using Scalar = typename Result::Value;
@ -586,11 +589,11 @@ public:
typename KindsVariant<CAT, KindExpr>::type u;
};
extern template class Expr<AnyKindType<Category::Integer>>;
extern template class Expr<AnyKindType<Category::Real>>;
extern template class Expr<AnyKindType<Category::Complex>>;
extern template class Expr<AnyKindType<Category::Character>>;
extern template class Expr<AnyKindType<Category::Logical>>;
extern template class Expr<AnyKindType<TypeCategory::Integer>>;
extern template class Expr<AnyKindType<TypeCategory::Real>>;
extern template class Expr<AnyKindType<TypeCategory::Complex>>;
extern template class Expr<AnyKindType<TypeCategory::Character>>;
extern template class Expr<AnyKindType<TypeCategory::Logical>>;
// A completely generic expression, polymorphic across the intrinsic type
// categories and each of their kinds.
@ -598,9 +601,9 @@ struct GenericExpr {
using Scalar = GenericScalar;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(GenericExpr)
template<Category CAT, int KIND>
template<TypeCategory CAT, int KIND>
GenericExpr(const Expr<Type<CAT, KIND>> &x) : u{Expr<AnyKindType<CAT>>{x}} {}
template<Category CAT, int KIND>
template<TypeCategory CAT, int KIND>
GenericExpr(Expr<Type<CAT, KIND>> &&x)
: u{Expr<AnyKindType<CAT>>{std::move(x)}} {}
template<typename A> GenericExpr(const A &x) : u{x} {}

View File

@ -24,16 +24,17 @@
#include "integer.h"
#include "logical.h"
#include "real.h"
#include "../common/fortran.h"
#include "../common/idioms.h"
#include <string>
#include <variant>
namespace Fortran::evaluate {
ENUM_CLASS(Category, Integer, Real, Complex, Character, Logical, Derived)
using common::TypeCategory;
template<Category C, int KIND> struct TypeBase {
static constexpr Category category{C};
template<TypeCategory C, int KIND> struct TypeBase {
static constexpr TypeCategory category{C};
static constexpr int kind{KIND};
static constexpr bool hasLen{false};
static std::string Dump() {
@ -41,51 +42,55 @@ template<Category C, int KIND> struct TypeBase {
}
};
template<Category C, int KIND> struct Type;
template<TypeCategory C, int KIND> struct Type;
template<int KIND>
struct Type<Category::Integer, KIND>
: public TypeBase<Category::Integer, KIND> {
struct Type<TypeCategory::Integer, KIND>
: public TypeBase<TypeCategory::Integer, KIND> {
using Value = value::Integer<8 * KIND>;
};
template<> struct Type<Category::Real, 2> : public TypeBase<Category::Real, 2> {
using Value = value::Real<typename Type<Category::Integer, 2>::Value, 11>;
using Complex = Type<Category::Complex, 2>;
};
template<> struct Type<Category::Real, 4> : public TypeBase<Category::Real, 4> {
using Value = value::Real<typename Type<Category::Integer, 4>::Value, 24>;
using Complex = Type<Category::Complex, 2>;
};
template<> struct Type<Category::Real, 8> : public TypeBase<Category::Real, 8> {
using Value = value::Real<typename Type<Category::Integer, 8>::Value, 53>;
using Complex = Type<Category::Complex, 2>;
template<>
struct Type<TypeCategory::Real, 2> : public TypeBase<TypeCategory::Real, 2> {
using Value = value::Real<typename Type<TypeCategory::Integer, 2>::Value, 11>;
using Complex = Type<TypeCategory::Complex, 2>;
};
template<>
struct Type<Category::Real, 10> : public TypeBase<Category::Real, 10> {
struct Type<TypeCategory::Real, 4> : public TypeBase<TypeCategory::Real, 4> {
using Value = value::Real<typename Type<TypeCategory::Integer, 4>::Value, 24>;
using Complex = Type<TypeCategory::Complex, 2>;
};
template<>
struct Type<TypeCategory::Real, 8> : public TypeBase<TypeCategory::Real, 8> {
using Value = value::Real<typename Type<TypeCategory::Integer, 8>::Value, 53>;
using Complex = Type<TypeCategory::Complex, 2>;
};
template<>
struct Type<TypeCategory::Real, 10> : public TypeBase<TypeCategory::Real, 10> {
using Value = value::Real<value::Integer<80>, 64, false>;
using Complex = Type<Category::Complex, 2>;
using Complex = Type<TypeCategory::Complex, 2>;
};
template<>
struct Type<Category::Real, 16> : public TypeBase<Category::Real, 16> {
using Value = value::Real<typename Type<Category::Integer, 16>::Value, 112>;
using Complex = Type<Category::Complex, 2>;
struct Type<TypeCategory::Real, 16> : public TypeBase<TypeCategory::Real, 16> {
using Value =
value::Real<typename Type<TypeCategory::Integer, 16>::Value, 112>;
using Complex = Type<TypeCategory::Complex, 2>;
};
// The KIND type parameter on COMPLEX is the kind of each of its components.
template<int KIND>
struct Type<Category::Complex, KIND>
: public TypeBase<Category::Complex, KIND> {
using Part = Type<Category::Real, KIND>;
struct Type<TypeCategory::Complex, KIND>
: public TypeBase<TypeCategory::Complex, KIND> {
using Part = Type<TypeCategory::Real, KIND>;
using Value = value::Complex<typename Part::Value>;
};
template<int KIND> struct Type<Category::Character, KIND> {
static constexpr Category category{Category::Character};
template<int KIND> struct Type<TypeCategory::Character, KIND> {
static constexpr TypeCategory category{TypeCategory::Character};
static constexpr int kind{KIND};
static constexpr bool hasLen{true};
using Value = std::string;
@ -95,8 +100,8 @@ template<int KIND> struct Type<Category::Character, KIND> {
};
template<int KIND>
struct Type<Category::Logical, KIND>
: public TypeBase<Category::Logical, KIND> {
struct Type<TypeCategory::Logical, KIND>
: public TypeBase<TypeCategory::Logical, KIND> {
using Value = value::Logical<8 * KIND>;
};
@ -107,15 +112,15 @@ struct Type<Category::Logical, KIND>
// two numeric storage units.
// TODO: Support a compile-time option to default everything to KIND=8
using DefaultReal = Type<Category::Real, 4>;
using DefaultDoublePrecision = Type<Category::Real, 2 * DefaultReal::kind>;
using DefaultInteger = Type<Category::Integer, DefaultReal::kind>;
using DefaultReal = Type<TypeCategory::Real, 4>;
using DefaultDoublePrecision = Type<TypeCategory::Real, 2 * DefaultReal::kind>;
using DefaultInteger = Type<TypeCategory::Integer, DefaultReal::kind>;
using IntrinsicTypeParameterType = DefaultInteger;
using DefaultComplex = typename DefaultReal::Complex;
using DefaultLogical = Type<Category::Logical, DefaultInteger::kind>;
using DefaultCharacter = Type<Category::Character, 1>;
using DefaultLogical = Type<TypeCategory::Logical, DefaultInteger::kind>;
using DefaultCharacter = Type<TypeCategory::Character, 1>;
using SubscriptInteger = Type<Category::Integer, 8>;
using SubscriptInteger = Type<TypeCategory::Integer, 8>;
// These macros invoke other macros on each of the supported kinds of
// a given category.
@ -131,27 +136,28 @@ using SubscriptInteger = Type<Category::Integer, 8>;
// applications of some class template to all of the supported kinds of
// a category of intrinsic type.
#define TKIND(K) T<K>
template<Category CAT, template<int> class T> struct KindsVariant;
template<template<int> class T> struct KindsVariant<Category::Integer, T> {
template<TypeCategory CAT, template<int> class T> struct KindsVariant;
template<template<int> class T> struct KindsVariant<TypeCategory::Integer, T> {
using type = std::variant<FOR_EACH_INTEGER_KIND(TKIND, COMMA)>;
};
template<template<int> class T> struct KindsVariant<Category::Real, T> {
template<template<int> class T> struct KindsVariant<TypeCategory::Real, T> {
using type = std::variant<FOR_EACH_REAL_KIND(TKIND, COMMA)>;
};
template<template<int> class T> struct KindsVariant<Category::Complex, T> {
template<template<int> class T> struct KindsVariant<TypeCategory::Complex, T> {
using type = std::variant<FOR_EACH_COMPLEX_KIND(TKIND, COMMA)>;
};
template<template<int> class T> struct KindsVariant<Category::Character, T> {
template<template<int> class T>
struct KindsVariant<TypeCategory::Character, T> {
using type = std::variant<FOR_EACH_CHARACTER_KIND(TKIND, COMMA)>;
};
template<template<int> class T> struct KindsVariant<Category::Logical, T> {
template<template<int> class T> struct KindsVariant<TypeCategory::Logical, T> {
using type = std::variant<FOR_EACH_LOGICAL_KIND(TKIND, COMMA)>;
};
#undef TKIND
// Holds a scalar constant of any kind within a particular intrinsic type
// category.
template<Category CAT> struct ScalarConstant {
template<TypeCategory CAT> struct ScalarConstant {
CLASS_BOILERPLATE(ScalarConstant)
template<int KIND> using KindScalar = typename Type<CAT, KIND>::Value;
template<typename A> ScalarConstant(const A &x) : u{x} {}
@ -164,25 +170,26 @@ template<Category CAT> struct ScalarConstant {
// Holds a scalar constant of any intrinsic category and size.
struct GenericScalar {
CLASS_BOILERPLATE(GenericScalar)
template<Category CAT, int KIND>
template<TypeCategory CAT, int KIND>
GenericScalar(const typename Type<CAT, KIND>::Value &x)
: u{ScalarConstant<CAT>{x}} {}
template<Category CAT, int KIND>
template<TypeCategory CAT, int KIND>
GenericScalar(typename Type<CAT, KIND>::Value &&x)
: u{ScalarConstant<CAT>{std::move(x)}} {}
template<typename A> GenericScalar(const A &x) : u{x} {}
template<typename A>
GenericScalar(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
std::variant<ScalarConstant<Category::Integer>,
ScalarConstant<Category::Real>, ScalarConstant<Category::Complex>,
ScalarConstant<Category::Character>, ScalarConstant<Category::Logical>>
std::variant<ScalarConstant<TypeCategory::Integer>,
ScalarConstant<TypeCategory::Real>, ScalarConstant<TypeCategory::Complex>,
ScalarConstant<TypeCategory::Character>,
ScalarConstant<TypeCategory::Logical>>
u;
};
// Represents a type of any supported kind within a particular category.
template<Category CAT> struct AnyKindType {
static constexpr Category category{CAT};
template<TypeCategory CAT> struct AnyKindType {
static constexpr TypeCategory category{CAT};
using Value = ScalarConstant<CAT>;
};
} // namespace Fortran::evaluate

View File

@ -119,8 +119,7 @@ struct GenericExpr;
WRAPPER_CLASS_BOILERPLATE(classname, type); \
}
namespace Fortran {
namespace parser {
namespace Fortran::parser {
// These are the unavoidable recursively-defined productions of Fortran.
// Some references to the representations of their parses require
@ -3701,6 +3700,5 @@ struct OpenMPConstruct {
u;
};
} // namespace parser
} // namespace Fortran
} // namespace Fortran::parser
#endif // FORTRAN_PARSER_PARSE_TREE_H_

View File

@ -26,14 +26,14 @@ int Descriptor::Establish(TypeCode t, std::size_t elementBytes, void *p,
&raw_, p, CFI_attribute_other, t.raw(), elementBytes, rank, extent);
}
int Descriptor::Establish(TypeCode::Form f, int kind, void *p, int rank,
const SubscriptValue *extent) {
int Descriptor::Establish(
TypeCategory c, int kind, void *p, int rank, const SubscriptValue *extent) {
std::size_t elementBytes = kind;
if (f == TypeCode::Form::Complex) {
if (c == TypeCategory::Complex) {
elementBytes *= 2;
}
return ISO::CFI_establish(&raw_, p, CFI_attribute_other,
TypeCode(f, kind).raw(), elementBytes, rank, extent);
TypeCode(c, kind).raw(), elementBytes, rank, extent);
}
int Descriptor::Establish(
@ -53,11 +53,11 @@ Descriptor *Descriptor::Create(TypeCode t, std::size_t elementBytes, void *p,
return result;
}
Descriptor *Descriptor::Create(TypeCode::Form f, int kind, void *p, int rank,
const SubscriptValue *extent) {
Descriptor *Descriptor::Create(
TypeCategory c, int kind, void *p, int rank, const SubscriptValue *extent) {
std::size_t bytes{SizeInBytes(rank)};
Descriptor *result{reinterpret_cast<Descriptor *>(new char[bytes])};
result->Establish(f, kind, p, rank, extent);
result->Establish(c, kind, p, rank, extent);
result->Attributes() |= CREATED;
return result;
}

View File

@ -108,15 +108,15 @@ public:
int Establish(TypeCode t, std::size_t elementBytes, void *p = nullptr,
int rank = maxRank, const SubscriptValue *extent = nullptr);
int Establish(TypeCode::Form f, int kind, void *p = nullptr,
int rank = maxRank, const SubscriptValue *extent = nullptr);
int Establish(TypeCategory, int kind, void *p = nullptr, int rank = maxRank,
const SubscriptValue *extent = nullptr);
int Establish(const DerivedType &dt, void *p = nullptr, int rank = maxRank,
const SubscriptValue *extent = nullptr);
static Descriptor *Create(TypeCode t, std::size_t elementBytes,
void *p = nullptr, int rank = maxRank,
const SubscriptValue *extent = nullptr);
static Descriptor *Create(TypeCode::Form f, int kind, void *p = nullptr,
static Descriptor *Create(TypeCategory, int kind, void *p = nullptr,
int rank = maxRank, const SubscriptValue *extent = nullptr);
static Descriptor *Create(const DerivedType &dt, void *p = nullptr,
int rank = maxRank, const SubscriptValue *extent = nullptr);

View File

@ -16,9 +16,9 @@
namespace Fortran::runtime {
TypeCode::TypeCode(TypeCode::Form f, int kind) {
TypeCode::TypeCode(TypeCategory f, int kind) {
switch (f) {
case Form::Integer:
case TypeCategory::Integer:
switch (kind) {
case 1: raw_ = CFI_type_int8_t; break;
case 2: raw_ = CFI_type_int16_t; break;
@ -27,7 +27,7 @@ TypeCode::TypeCode(TypeCode::Form f, int kind) {
case 16: raw_ = CFI_type_int128_t; break;
}
break;
case Form::Real:
case TypeCategory::Real:
switch (kind) {
case 4: raw_ = CFI_type_float; break;
case 8: raw_ = CFI_type_double; break;
@ -35,7 +35,7 @@ TypeCode::TypeCode(TypeCode::Form f, int kind) {
case 16: raw_ = CFI_type_long_double; break;
}
break;
case Form::Complex:
case TypeCategory::Complex:
switch (kind) {
case 4: raw_ = CFI_type_float_Complex; break;
case 8: raw_ = CFI_type_double_Complex; break;
@ -43,12 +43,12 @@ TypeCode::TypeCode(TypeCode::Form f, int kind) {
case 16: raw_ = CFI_type_long_double_Complex; break;
}
break;
case Form::Character:
case TypeCategory::Character:
if (kind == 1) {
raw_ = CFI_type_cptr;
}
break;
case Form::Logical:
case TypeCategory::Logical:
switch (kind) {
case 1: raw_ = CFI_type_Bool; break;
case 2: raw_ = CFI_type_int16_t; break;
@ -56,7 +56,7 @@ TypeCode::TypeCode(TypeCode::Form f, int kind) {
case 8: raw_ = CFI_type_int64_t; break;
}
break;
case Form::Derived: raw_ = CFI_type_struct; break;
case TypeCategory::Derived: raw_ = CFI_type_struct; break;
}
}

View File

@ -16,16 +16,17 @@
#define FORTRAN_RUNTIME_TYPE_CODE_H_
#include "../include/flang/ISO_Fortran_binding.h"
#include "../lib/common/fortran.h"
namespace Fortran::runtime {
using common::TypeCategory;
class TypeCode {
public:
enum class Form { Integer, Real, Complex, Character, Logical, Derived };
TypeCode() {}
explicit TypeCode(ISO::CFI_type_t t) : raw_{t} {}
TypeCode(Form, int);
TypeCode(TypeCategory, int);
int raw() const { return raw_; }
@ -48,23 +49,23 @@ public:
constexpr bool IsIntrinsic() const { return IsValid() && !IsDerived(); }
constexpr Form GetForm() const {
constexpr TypeCategory Categorize() const {
if (IsInteger()) {
return Form::Integer;
return TypeCategory::Integer;
}
if (IsReal()) {
return Form::Real;
return TypeCategory::Real;
}
if (IsComplex()) {
return Form::Complex;
return TypeCategory::Complex;
}
if (IsCharacter()) {
return Form::Character;
return TypeCategory::Character;
}
if (IsLogical()) {
return Form::Logical;
return TypeCategory::Logical;
}
return Form::Derived;
return TypeCategory::Derived;
}
private:

View File

@ -13,8 +13,8 @@
// limitations under the License.
#include "../../lib/evaluate/expression.h"
#include "../../lib/parser/message.h"
#include "testing.h"
#include "../../lib/parser/message.h"
#include <cstdio>
#include <cstdlib>
#include <sstream>
@ -32,14 +32,16 @@ int main() {
TEST(DefaultIntegerExpr::Result::Dump() == "Integer(4)");
MATCH("666", Dump(DefaultIntegerExpr{666}));
MATCH("(-1)", Dump(-DefaultIntegerExpr{1}));
auto ex1{DefaultIntegerExpr{2} + DefaultIntegerExpr{3} * -DefaultIntegerExpr{4}};
auto ex1{
DefaultIntegerExpr{2} + DefaultIntegerExpr{3} * -DefaultIntegerExpr{4}};
MATCH("(2+(3*(-4)))", Dump(ex1));
Fortran::parser::CharBlock src;
Fortran::parser::ContextualMessages messages{src, nullptr};
FoldingContext context{messages};
ex1.Fold(context);
MATCH("-10", Dump(ex1));
MATCH("(Integer(4)::6.LE.7)", Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
MATCH("(Integer(4)::6.LE.7)",
Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
DefaultIntegerExpr a{1};
DefaultIntegerExpr b{2};
MATCH("(1/2)", Dump(a / b));

View File

@ -18,8 +18,8 @@
template<int KIND> void testKind() {
using Type =
Fortran::evaluate::Type<Fortran::evaluate::Category::Logical, KIND>;
TEST(Type::category == Fortran::evaluate::Category::Logical);
Fortran::evaluate::Type<Fortran::common::TypeCategory::Logical, KIND>;
TEST(Type::category == Fortran::common::TypeCategory::Logical);
TEST(Type::kind == KIND);
TEST(!Type::hasLen);
using Value = typename Type::Value;

View File

@ -19,37 +19,30 @@
#include <cstdlib>
using namespace Fortran::evaluate;
using namespace Fortran::common;
using Real2 = typename Type<Category::Real, 2>::Value;
using Real4 = typename Type<Category::Real, 4>::Value;
using Real8 = typename Type<Category::Real, 8>::Value;
using Real10 = typename Type<Category::Real, 10>::Value;
using Real16 = typename Type<Category::Real, 16>::Value;
using Integer4 = typename Type<Category::Integer, 4>::Value;
using Integer8 = typename Type<Category::Integer, 8>::Value;
using Real2 = typename Type<TypeCategory::Real, 2>::Value;
using Real4 = typename Type<TypeCategory::Real, 4>::Value;
using Real8 = typename Type<TypeCategory::Real, 8>::Value;
using Real10 = typename Type<TypeCategory::Real, 10>::Value;
using Real16 = typename Type<TypeCategory::Real, 16>::Value;
using Integer4 = typename Type<TypeCategory::Integer, 4>::Value;
using Integer8 = typename Type<TypeCategory::Integer, 8>::Value;
void dumpTest() {
struct {
std::uint64_t raw;
const char *expected;
} table[] = {
{ 0x7f876543, "NaN 0x7f876543" },
{ 0x7f800000, "Inf" },
{ 0xff800000, "-Inf" },
{ 0x00000000, "0.0" },
{ 0x80000000, "-0.0" },
{ 0x3f800000, "0x1.0p0" },
{ 0xbf800000, "-0x1.0p0" },
{ 0x40000000, "0x1.0p1" },
{ 0x3f000000, "0x1.0p-1" },
{ 0x7f7fffff, "0x1.fffffep127" },
{ 0x00800000, "0x1.0p-126" },
{ 0x00400000, "0x0.8p-127" },
{ 0x00000001, "0x0.000002p-127" },
{ 0, nullptr }
};
} table[] = {{0x7f876543, "NaN 0x7f876543"}, {0x7f800000, "Inf"},
{0xff800000, "-Inf"}, {0x00000000, "0.0"}, {0x80000000, "-0.0"},
{0x3f800000, "0x1.0p0"}, {0xbf800000, "-0x1.0p0"},
{0x40000000, "0x1.0p1"}, {0x3f000000, "0x1.0p-1"},
{0x7f7fffff, "0x1.fffffep127"}, {0x00800000, "0x1.0p-126"},
{0x00400000, "0x0.8p-127"}, {0x00000001, "0x0.000002p-127"},
{0, nullptr}};
for (int j{0}; table[j].expected != nullptr; ++j) {
TEST(Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j].expected)("%d", j);
TEST(Real4{Integer4{table[j].raw}}.DumpHexadecimal() == table[j].expected)
("%d", j);
}
}