forked from OSchip/llvm-project
[flang] remove arg->intValue field
Original-commit: flang-compiler/f18@721dc92022 Reviewed-on: https://github.com/flang-compiler/f18/pull/212 Tree-same-pre-rewrite: false
This commit is contained in:
parent
a62636f634
commit
f7f2a73a43
|
@ -19,6 +19,7 @@
|
|||
// once here to avoid redundancy and needless translation.
|
||||
|
||||
#include "idioms.h"
|
||||
#include <cinttypes>
|
||||
|
||||
namespace Fortran::common {
|
||||
|
||||
|
|
|
@ -35,8 +35,7 @@ struct ActualArgument {
|
|||
std::optional<parser::CharBlock> keyword;
|
||||
bool isAssumedRank{false};
|
||||
bool isAlternateReturn{false};
|
||||
std::optional<int> vectorSize; // TODO: pmk replace with function on value
|
||||
std::optional<int> intValue; // TODO: pmk replace with function on value
|
||||
std::optional<int> vectorSize; // TODO
|
||||
CopyableIndirection<Expr<SomeType>> value;
|
||||
};
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ template<typename RESULT>
|
|||
auto ExpressionBase<RESULT>::Fold(FoldingContext &context)
|
||||
-> std::optional<Constant<Result>> {
|
||||
using Const = Constant<Result>;
|
||||
if constexpr (Result::isSpecificType) {
|
||||
if constexpr (Result::isSpecificIntrinsicType) {
|
||||
// Folding an expression of known type category and kind.
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Const> {
|
||||
|
@ -97,7 +97,7 @@ auto ExpressionBase<RESULT>::Fold(FoldingContext &context)
|
|||
[&](auto &x) -> std::optional<Const> {
|
||||
if constexpr (IsFoldableTrait<std::decay_t<decltype(x)>>) {
|
||||
if (auto c{x.Fold(context)}) {
|
||||
if constexpr (ResultType<decltype(*c)>::isSpecificType) {
|
||||
if constexpr (ResultType<decltype(*c)>::isSpecificIntrinsicType) {
|
||||
return {Const{c->value}};
|
||||
} else {
|
||||
return {Const{common::MoveVariant<GenericScalar>(c->value.u)}};
|
||||
|
@ -500,7 +500,7 @@ Expr<SubscriptInteger> Expr<Type<TypeCategory::Character, KIND>>::LEN() const {
|
|||
template<typename RESULT>
|
||||
auto ExpressionBase<RESULT>::ScalarValue() const
|
||||
-> std::optional<Scalar<Result>> {
|
||||
if constexpr (Result::isSpecificType) {
|
||||
if constexpr (Result::isSpecificIntrinsicType) {
|
||||
if (auto *c{std::get_if<Constant<Result>>(&derived().u)}) {
|
||||
return {c->value};
|
||||
}
|
||||
|
@ -541,12 +541,8 @@ Expr<SomeType>::~Expr() {}
|
|||
|
||||
template<typename A>
|
||||
std::optional<DynamicType> ExpressionBase<A>::GetType() const {
|
||||
if constexpr (Result::isSpecificType) {
|
||||
if constexpr (Result::category == TypeCategory::Derived) {
|
||||
return std::visit([](const auto &x) { return x.GetType(); }, derived().u);
|
||||
} else {
|
||||
return Result::GetType();
|
||||
}
|
||||
if constexpr (Result::isSpecificIntrinsicType) {
|
||||
return Result::GetType();
|
||||
} else {
|
||||
return std::visit(
|
||||
[](const auto &x) -> std::optional<DynamicType> {
|
||||
|
|
|
@ -79,7 +79,7 @@ template<typename T> struct Constant {
|
|||
Constant(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
: value(std::move(x)) {}
|
||||
constexpr std::optional<DynamicType> GetType() const {
|
||||
if constexpr (Result::isSpecificType) {
|
||||
if constexpr (Result::isSpecificIntrinsicType) {
|
||||
return Result::GetType();
|
||||
} else {
|
||||
return value.GetType();
|
||||
|
@ -115,8 +115,7 @@ class Operation {
|
|||
public:
|
||||
using Derived = DERIVED;
|
||||
using Result = RESULT;
|
||||
static_assert(Result::isSpecificType);
|
||||
static_assert(Result::category != TypeCategory::Derived);
|
||||
static_assert(Result::isSpecificIntrinsicType);
|
||||
static constexpr std::size_t operands{sizeof...(OPERANDS)};
|
||||
template<int J> using Operand = std::tuple_element_t<J, OperandTypes>;
|
||||
using IsFoldableTrait = std::true_type;
|
||||
|
|
|
@ -76,6 +76,7 @@ enum class KindCode {
|
|||
effectiveKind, // for function results: same "kindArg", possibly defaulted
|
||||
dimArg, // this argument is DIM=
|
||||
same, // match any kind; all "same" kinds must be equal
|
||||
likeMultiply, // for DOT_PRODUCT and MATMUL
|
||||
};
|
||||
|
||||
struct TypePattern {
|
||||
|
@ -104,6 +105,7 @@ static constexpr TypePattern AnyNumeric{Numeric, KindCode::any};
|
|||
static constexpr TypePattern AnyChar{Char, KindCode::any};
|
||||
static constexpr TypePattern AnyLogical{Logical, KindCode::any};
|
||||
static constexpr TypePattern AnyRelatable{Relatable, KindCode::any};
|
||||
static constexpr TypePattern Anything{AnyType, KindCode::any};
|
||||
|
||||
// Match some kind of some intrinsic type(s); all "Same" values must match,
|
||||
// even when not in the same category (e.g., SameComplex and SameReal).
|
||||
|
@ -123,6 +125,10 @@ static constexpr TypePattern SameDerivedType{
|
|||
CategorySet{TypeCategory::Derived}, KindCode::same};
|
||||
static constexpr TypePattern SameType{AnyType, KindCode::same};
|
||||
|
||||
// For DOT_PRODUCT and MATMUL, the result type depends on the arguments
|
||||
static constexpr TypePattern ResultLogical{Logical, KindCode::likeMultiply};
|
||||
static constexpr TypePattern ResultNumeric{Numeric, KindCode::likeMultiply};
|
||||
|
||||
// Result types with known category and KIND=
|
||||
static constexpr TypePattern KINDInt{Int, KindCode::effectiveKind};
|
||||
static constexpr TypePattern KINDReal{Real, KindCode::effectiveKind};
|
||||
|
@ -214,9 +220,17 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
{"bessel_j0", {{"x", SameReal}}, SameReal},
|
||||
{"bessel_j1", {{"x", SameReal}}, SameReal},
|
||||
{"bessel_jn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
|
||||
{"bessel_jn",
|
||||
{{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
|
||||
{"x", SameReal, Rank::scalar}},
|
||||
SameReal, Rank::vector},
|
||||
{"bessel_y0", {{"x", SameReal}}, SameReal},
|
||||
{"bessel_y1", {{"x", SameReal}}, SameReal},
|
||||
{"bessel_yn", {{"n", AnyInt}, {"x", SameReal}}, SameReal},
|
||||
{"bessel_yn",
|
||||
{{"n1", AnyInt, Rank::scalar}, {"n2", AnyInt, Rank::scalar},
|
||||
{"x", SameReal, Rank::scalar}},
|
||||
SameReal, Rank::vector},
|
||||
{"bge",
|
||||
{{"i", AnyInt, Rank::elementalOrBOZ},
|
||||
{"j", AnyInt, Rank::elementalOrBOZ}},
|
||||
|
@ -241,6 +255,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
{{"x", SameIntOrReal, Rank::elementalOrBOZ},
|
||||
{"y", SameIntOrReal, Rank::elementalOrBOZ}, DefaultingKIND},
|
||||
KINDComplex},
|
||||
{"command_argument_count", {}, DftInt, Rank::scalar},
|
||||
{"conjg", {{"z", SameComplex}}, SameComplex},
|
||||
{"cos", {{"x", SameFloating}}, SameFloating},
|
||||
{"cosh", {{"x", SameFloating}}, SameFloating},
|
||||
|
@ -251,6 +266,18 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
OptionalDIM},
|
||||
SameType, Rank::array},
|
||||
{"dim", {{"x", SameIntOrReal}, {"y", SameIntOrReal}}, SameIntOrReal},
|
||||
{"dot_product",
|
||||
{{"vector_a", AnyLogical, Rank::vector},
|
||||
{"vector_b", AnyLogical, Rank::vector}},
|
||||
ResultLogical, Rank::scalar},
|
||||
{"dot_product",
|
||||
{{"vector_a", AnyComplex, Rank::vector},
|
||||
{"vector_b", AnyNumeric, Rank::vector}},
|
||||
ResultNumeric, Rank::scalar}, // conjugates vector_a
|
||||
{"dot_product",
|
||||
{{"vector_a", AnyIntOrReal, Rank::vector},
|
||||
{"vector_b", AnyNumeric, Rank::vector}},
|
||||
ResultNumeric, Rank::scalar},
|
||||
{"dprod", {{"x", DftReal}, {"y", DftReal}}, DoublePrecision},
|
||||
{"dshiftl",
|
||||
{{"i", SameInt}, {"j", SameInt, Rank::elementalOrBOZ},
|
||||
|
@ -334,6 +361,12 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
SameInt},
|
||||
{"is_iostat_end", {{"i", AnyInt}}, DftLogical},
|
||||
{"is_iostat_eor", {{"i", AnyInt}}, DftLogical},
|
||||
{"lbound", {{"array", Anything, Rank::anyOrAssumedRank}, DefaultingKIND},
|
||||
KINDInt, Rank::vector},
|
||||
{"lbound",
|
||||
{{"array", Anything, Rank::anyOrAssumedRank},
|
||||
{"dim", {Int, KindCode::dimArg}, Rank::scalar}, DefaultingKIND},
|
||||
KINDInt, Rank::scalar},
|
||||
{"leadz", {{"i", AnyInt}}, DftInt},
|
||||
{"len", {{"string", AnyChar}, DefaultingKIND}, KINDInt},
|
||||
{"len_trim", {{"string", AnyChar}, DefaultingKIND}, KINDInt},
|
||||
|
@ -345,6 +378,30 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
{"log10", {{"x", SameReal}}, SameReal},
|
||||
{"logical", {{"l", AnyLogical}, DefaultingKIND}, KINDLogical},
|
||||
{"log_gamma", {{"x", SameReal}}, SameReal},
|
||||
{"matmul",
|
||||
{{"array_a", AnyLogical, Rank::vector},
|
||||
{"array_b", AnyLogical, Rank::matrix}},
|
||||
ResultLogical, Rank::vector},
|
||||
{"matmul",
|
||||
{{"array_a", AnyLogical, Rank::matrix},
|
||||
{"array_b", AnyLogical, Rank::vector}},
|
||||
ResultLogical, Rank::vector},
|
||||
{"matmul",
|
||||
{{"array_a", AnyLogical, Rank::matrix},
|
||||
{"array_b", AnyLogical, Rank::matrix}},
|
||||
ResultLogical, Rank::matrix},
|
||||
{"matmul",
|
||||
{{"array_a", AnyNumeric, Rank::vector},
|
||||
{"array_b", AnyNumeric, Rank::matrix}},
|
||||
ResultNumeric, Rank::vector},
|
||||
{"matmul",
|
||||
{{"array_a", AnyNumeric, Rank::matrix},
|
||||
{"array_b", AnyNumeric, Rank::vector}},
|
||||
ResultNumeric, Rank::vector},
|
||||
{"matmul",
|
||||
{{"array_a", AnyNumeric, Rank::matrix},
|
||||
{"array_b", AnyNumeric, Rank::matrix}},
|
||||
ResultNumeric, Rank::matrix},
|
||||
{"maskl", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
|
||||
{"maskr", {{"i", AnyInt}, DefaultingKIND}, KINDInt},
|
||||
{"maxloc",
|
||||
|
@ -377,6 +434,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
{"norm2", {{"x", SameReal, Rank::array}, OptionalDIM}, SameReal,
|
||||
Rank::dimReduced},
|
||||
{"not", {{"i", SameInt}}, SameInt},
|
||||
// pmk WIP continue here in transformationals with NULL
|
||||
{"out_of_range",
|
||||
{{"x", SameIntOrReal}, {"mold", AnyIntOrReal, Rank::scalar}},
|
||||
DftLogical},
|
||||
|
@ -418,6 +476,12 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
{"sign", {{"a", SameIntOrReal}, {"b", SameIntOrReal}}, SameIntOrReal},
|
||||
{"sin", {{"x", SameFloating}}, SameFloating},
|
||||
{"sinh", {{"x", SameFloating}}, SameFloating},
|
||||
{"size", {{"array", Anything, Rank::anyOrAssumedRank}, DefaultingKIND},
|
||||
KINDInt, Rank::vector},
|
||||
{"size",
|
||||
{{"array", Anything, Rank::anyOrAssumedRank},
|
||||
{"dim", {Int, KindCode::dimArg}, Rank::scalar}, DefaultingKIND},
|
||||
KINDInt, Rank::scalar},
|
||||
{"spacing", {{"x", SameReal}}, SameReal},
|
||||
{"spread",
|
||||
{{"source", SameType, Rank::known},
|
||||
|
@ -430,7 +494,28 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
|
|||
{"tan", {{"x", SameFloating}}, SameFloating},
|
||||
{"tanh", {{"x", SameFloating}}, SameFloating},
|
||||
{"trailz", {{"i", AnyInt}}, DftInt},
|
||||
// TODO: pmk: continue here with TRANSFER
|
||||
{"transfer",
|
||||
{{"source", Anything, Rank::known}, {"mold", SameType, Rank::scalar}},
|
||||
SameType, Rank::scalar},
|
||||
{"transfer",
|
||||
{{"source", Anything, Rank::known}, {"mold", SameType, Rank::array}},
|
||||
SameType, Rank::vector},
|
||||
{"transfer",
|
||||
{{"source", Anything, Rank::known}, {"mold", SameType, Rank::known},
|
||||
{"size", AnyInt, Rank::scalar}},
|
||||
SameType, Rank::vector},
|
||||
{"transpose", {{"matrix", SameType, Rank::matrix}}, SameType, Rank::matrix},
|
||||
{"trim", {{"string", AnyChar, Rank::scalar}}, SameChar, Rank::scalar},
|
||||
{"ubound", {{"array", Anything, Rank::anyOrAssumedRank}, DefaultingKIND},
|
||||
KINDInt, Rank::vector},
|
||||
{"ubound",
|
||||
{{"array", Anything, Rank::anyOrAssumedRank},
|
||||
{"dim", {Int, KindCode::dimArg}, Rank::scalar}, DefaultingKIND},
|
||||
KINDInt, Rank::scalar},
|
||||
{"unpack",
|
||||
{{"vector", SameType, Rank::vector}, {"mask", AnyLogical, Rank::array},
|
||||
{"field", SameType, Rank::conformable}},
|
||||
SameType, Rank::conformable},
|
||||
{"verify",
|
||||
{{"string", SameChar}, {"set", SameChar},
|
||||
{"back", AnyLogical, Rank::elemental, Optionality::optional},
|
||||
|
@ -629,11 +714,13 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
|
|||
break;
|
||||
case KindCode::any: argOk = true; break;
|
||||
case KindCode::kindArg:
|
||||
CHECK(type->category == TypeCategory::Integer);
|
||||
CHECK(kindArg == nullptr);
|
||||
kindArg = arg;
|
||||
argOk = arg->intValue.has_value();
|
||||
argOk = true;
|
||||
break;
|
||||
case KindCode::dimArg:
|
||||
CHECK(type->category == TypeCategory::Integer);
|
||||
hasDimArg = true;
|
||||
argOk = true;
|
||||
break;
|
||||
|
@ -732,7 +819,6 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
|
|||
}
|
||||
}
|
||||
|
||||
// At this point, the call is acceptable.
|
||||
// Calculate the characteristics of the function result, if any
|
||||
if (result.categorySet.empty()) {
|
||||
CHECK(result.kindCode == KindCode::none);
|
||||
|
@ -775,9 +861,21 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
|
|||
CHECK(kindDummyArg != nullptr);
|
||||
CHECK(result.categorySet == CategorySet{resultType.category});
|
||||
if (kindArg != nullptr) {
|
||||
CHECK(kindArg->intValue.has_value());
|
||||
resultType.kind = *kindArg->intValue;
|
||||
// TODO pmk: validate this kind!!
|
||||
if (auto *jExpr{std::get_if<Expr<SomeInteger>>(&kindArg->value->u)}) {
|
||||
CHECK(jExpr->Rank() == 0);
|
||||
if (auto value{jExpr->ScalarValue()}) {
|
||||
if (auto code{value->ToInt64()}) {
|
||||
if (IsValidKindOfIntrinsicType(resultType.category, *code)) {
|
||||
resultType.kind = *code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
messages.Say("'kind' argument must be a constant scalar integer "
|
||||
"whose value is a supported kind for the "
|
||||
"intrinsic result type"_err_en_US);
|
||||
return std::nullopt;
|
||||
} else if (kindDummyArg->optionality == Optionality::defaultsToSameKind) {
|
||||
CHECK(sameArg != nullptr);
|
||||
resultType = *sameArg->GetType();
|
||||
|
@ -787,6 +885,13 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
|
|||
resultType.kind = defaults.DefaultKind(resultType.category);
|
||||
}
|
||||
break;
|
||||
case KindCode::likeMultiply:
|
||||
CHECK(dummies >= 2);
|
||||
CHECK(actualForDummy[0] != nullptr);
|
||||
CHECK(actualForDummy[1] != nullptr);
|
||||
resultType = actualForDummy[0]->GetType()->ResultTypeForMultiply(
|
||||
*actualForDummy[1]->GetType());
|
||||
break;
|
||||
case KindCode::typeless:
|
||||
case KindCode::teamType:
|
||||
case KindCode::any:
|
||||
|
@ -798,6 +903,7 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
|
|||
default: CRASH_NO_CASE;
|
||||
}
|
||||
|
||||
// At this point, the call is acceptable.
|
||||
// Determine the rank of the function result.
|
||||
int resultRank{0};
|
||||
switch (rank) {
|
||||
|
@ -805,6 +911,10 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
|
|||
case Rank::scalar: resultRank = 0; break;
|
||||
case Rank::vector: resultRank = 1; break;
|
||||
case Rank::matrix: resultRank = 2; break;
|
||||
case Rank::conformable:
|
||||
CHECK(arrayArg != nullptr);
|
||||
resultRank = arrayArg->Rank();
|
||||
break;
|
||||
case Rank::dimReduced:
|
||||
CHECK(arrayArg != nullptr);
|
||||
resultRank = hasDimArg ? arrayArg->Rank() - 1 : 0;
|
||||
|
@ -823,7 +933,6 @@ std::optional<SpecificIntrinsic> IntrinsicInterface::Match(
|
|||
case Rank::array:
|
||||
case Rank::known:
|
||||
case Rank::anyOrAssumedRank:
|
||||
case Rank::conformable:
|
||||
case Rank::dimRemoved:
|
||||
common::die("INTERNAL: bad Rank code on intrinsic '%s' result", name);
|
||||
break;
|
||||
|
|
|
@ -368,7 +368,7 @@ Expr<SomeLogical> LogicalNegation(Expr<SomeLogical> &&x) {
|
|||
template<typename T>
|
||||
Expr<LogicalResult> PackageRelation(
|
||||
RelationalOperator opr, Expr<T> &&x, Expr<T> &&y) {
|
||||
static_assert(T::isSpecificType);
|
||||
static_assert(T::isSpecificIntrinsicType);
|
||||
return Expr<LogicalResult>{
|
||||
Relational<SomeType>{Relational<T>{opr, std::move(x), std::move(y)}}};
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ Expr<SomeComplex> MakeComplex(Expr<Type<TypeCategory::Real, KIND>> &&re,
|
|||
|
||||
template<typename TO, TypeCategory FROMCAT>
|
||||
Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
|
||||
static_assert(TO::isSpecificType);
|
||||
static_assert(TO::isSpecificIntrinsicType);
|
||||
if constexpr (FROMCAT != TO::category) {
|
||||
if constexpr (TO::category == TypeCategory::Complex) {
|
||||
using Part = typename TO::Part;
|
||||
|
@ -134,7 +134,7 @@ Expr<TO> ConvertToType(Expr<SomeKind<FROMCAT>> &&x) {
|
|||
}
|
||||
|
||||
template<typename TO> Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
|
||||
static_assert(TO::isSpecificType);
|
||||
static_assert(TO::isSpecificIntrinsicType);
|
||||
using Value = typename Constant<TO>::Value;
|
||||
if constexpr (TO::category == TypeCategory::Integer) {
|
||||
return Expr<TO>{Constant<TO>{Value::ConvertUnsigned(std::move(x)).value}};
|
||||
|
@ -290,7 +290,7 @@ template<typename A> Expr<TypeOf<A>> ScalarConstantToExpr(const A &x) {
|
|||
// for COMPLEX.
|
||||
template<template<typename> class OPR, typename SPECIFIC>
|
||||
Expr<SPECIFIC> Combine(Expr<SPECIFIC> &&x, Expr<SPECIFIC> &&y) {
|
||||
static_assert(SPECIFIC::isSpecificType);
|
||||
static_assert(SPECIFIC::isSpecificIntrinsicType);
|
||||
if constexpr (SPECIFIC::category == TypeCategory::Complex &&
|
||||
(std::is_same_v<OPR<DefaultReal>, Add<DefaultReal>> ||
|
||||
std::is_same_v<OPR<DefaultReal>, Subtract<DefaultReal>>)) {
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include "type.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../semantics/symbol.h"
|
||||
#include "../semantics/type.h"
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
|
@ -26,10 +28,13 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol &symbol) {
|
|||
if (auto *details{symbol.detailsIf<semantics::ObjectEntityDetails>()}) {
|
||||
if (details->type().has_value()) {
|
||||
switch (details->type()->category()) {
|
||||
case semantics::DeclTypeSpec::Category::Intrinsic:
|
||||
return std::make_optional(
|
||||
DynamicType{details->type()->intrinsicTypeSpec().category(),
|
||||
details->type()->intrinsicTypeSpec().kind()});
|
||||
case semantics::DeclTypeSpec::Category::Intrinsic: {
|
||||
TypeCategory category{details->type()->intrinsicTypeSpec().category()};
|
||||
int kind{details->type()->intrinsicTypeSpec().kind()};
|
||||
if (IsValidKindOfIntrinsicType(category, kind)) {
|
||||
return std::make_optional(DynamicType{category, kind});
|
||||
}
|
||||
} break;
|
||||
case semantics::DeclTypeSpec::Category::TypeDerived:
|
||||
case semantics::DeclTypeSpec::Category::ClassDerived:
|
||||
return std::make_optional(DynamicType{
|
||||
|
@ -41,6 +46,48 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol &symbol) {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
DynamicType DynamicType::ResultTypeForMultiply(const DynamicType &that) const {
|
||||
switch (category) {
|
||||
case TypeCategory::Integer:
|
||||
switch (that.category) {
|
||||
case TypeCategory::Integer:
|
||||
return DynamicType{TypeCategory::Integer, std::max(kind, that.kind)};
|
||||
case TypeCategory::Real:
|
||||
case TypeCategory::Complex: return that;
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
break;
|
||||
case TypeCategory::Real:
|
||||
switch (that.category) {
|
||||
case TypeCategory::Integer: return *this;
|
||||
case TypeCategory::Real:
|
||||
return DynamicType{TypeCategory::Real, std::max(kind, that.kind)};
|
||||
case TypeCategory::Complex:
|
||||
return DynamicType{TypeCategory::Complex, std::max(kind, that.kind)};
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
break;
|
||||
case TypeCategory::Complex:
|
||||
switch (that.category) {
|
||||
case TypeCategory::Integer: return *this;
|
||||
case TypeCategory::Real:
|
||||
case TypeCategory::Complex:
|
||||
return DynamicType{TypeCategory::Complex, std::max(kind, that.kind)};
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
break;
|
||||
case TypeCategory::Logical:
|
||||
switch (that.category) {
|
||||
case TypeCategory::Logical:
|
||||
return DynamicType{TypeCategory::Logical, std::max(kind, that.kind)};
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
break;
|
||||
default: CRASH_NO_CASE;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
int IntrinsicTypeDefaultKinds::DefaultKind(TypeCategory category) const {
|
||||
switch (category) {
|
||||
case TypeCategory::Integer: return defaultIntegerKind;
|
||||
|
|
|
@ -53,6 +53,8 @@ struct DynamicType {
|
|||
return EnumToString(category) + '(' + std::to_string(kind) + ')';
|
||||
}
|
||||
|
||||
DynamicType ResultTypeForMultiply(const DynamicType &) const;
|
||||
|
||||
TypeCategory category;
|
||||
int kind{0};
|
||||
const semantics::DerivedTypeSpec *derived{nullptr};
|
||||
|
@ -65,7 +67,9 @@ std::optional<DynamicType> GetSymbolType(const semantics::Symbol &);
|
|||
template<TypeCategory CATEGORY, int KIND = 0> class Type;
|
||||
|
||||
template<TypeCategory CATEGORY, int KIND> struct TypeBase {
|
||||
static constexpr bool isSpecificType{true};
|
||||
// Only types that represent a known kind of one of the five intrinsic
|
||||
// data types will have set this flag to true.
|
||||
static constexpr bool isSpecificIntrinsicType{true};
|
||||
static constexpr DynamicType dynamicType{CATEGORY, KIND};
|
||||
static constexpr std::optional<DynamicType> GetType() {
|
||||
return {dynamicType};
|
||||
|
@ -190,33 +194,39 @@ using SubscriptInteger = Type<TypeCategory::Integer, 8>;
|
|||
using LogicalResult = Type<TypeCategory::Logical, 1>;
|
||||
using LargestReal = Type<TypeCategory::Real, 16>;
|
||||
|
||||
// A predicate that is true when a kind value is a kind that could possibly
|
||||
// be supported for an intrinsic type category on some target instruction
|
||||
// set architecture.
|
||||
static constexpr bool IsValidKindOfIntrinsicType(
|
||||
TypeCategory category, std::int64_t kind) {
|
||||
switch (category) {
|
||||
case TypeCategory::Integer:
|
||||
return kind == 1 || kind == 2 || kind == 4 || kind == 8 || kind == 16;
|
||||
case TypeCategory::Real:
|
||||
case TypeCategory::Complex:
|
||||
return kind == 2 || kind == 4 || kind == 8 || kind == 10 || kind == 16;
|
||||
case TypeCategory::Character:
|
||||
return kind == 1; // TODO: || kind == 2 || kind == 4;
|
||||
case TypeCategory::Logical:
|
||||
return kind == 1 || kind == 2 || kind == 4 || kind == 8;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
// For each intrinsic type category CAT, CategoryTypes<CAT> is an instantiation
|
||||
// of std::tuple<Type<CAT, K>> that comprises every kind value K in that
|
||||
// category that could possibly be supported on any target.
|
||||
template<TypeCategory CATEGORY, int... KINDS>
|
||||
using CategoryTypesTuple = std::tuple<Type<CATEGORY, KINDS>...>;
|
||||
template<TypeCategory CATEGORY, int KIND>
|
||||
using CategoryKindTuple =
|
||||
std::conditional_t<IsValidKindOfIntrinsicType(CATEGORY, KIND),
|
||||
std::tuple<Type<CATEGORY, KIND>>, std::tuple<>>;
|
||||
|
||||
template<TypeCategory CATEGORY, int... KINDS>
|
||||
using CategoryTypesHelper =
|
||||
common::CombineTuples<CategoryKindTuple<CATEGORY, KINDS>...>;
|
||||
|
||||
template<TypeCategory CATEGORY> struct CategoryTypesHelper;
|
||||
template<> struct CategoryTypesHelper<TypeCategory::Integer> {
|
||||
using type = CategoryTypesTuple<TypeCategory::Integer, 1, 2, 4, 8, 16>;
|
||||
};
|
||||
template<> struct CategoryTypesHelper<TypeCategory::Real> {
|
||||
using type = CategoryTypesTuple<TypeCategory::Real, 2, 4, 8, 10, 16>;
|
||||
};
|
||||
template<> struct CategoryTypesHelper<TypeCategory::Complex> {
|
||||
using type = CategoryTypesTuple<TypeCategory::Complex, 2, 4, 8, 10, 16>;
|
||||
};
|
||||
template<> struct CategoryTypesHelper<TypeCategory::Character> {
|
||||
using type = CategoryTypesTuple<TypeCategory::Character, 1>; // TODO: 2 & 4
|
||||
};
|
||||
template<> struct CategoryTypesHelper<TypeCategory::Logical> {
|
||||
using type = CategoryTypesTuple<TypeCategory::Logical, 1, 2, 4, 8>;
|
||||
};
|
||||
template<> struct CategoryTypesHelper<TypeCategory::Derived> {
|
||||
using type = std::tuple<>;
|
||||
};
|
||||
template<TypeCategory CATEGORY>
|
||||
using CategoryTypes = typename CategoryTypesHelper<CATEGORY>::type;
|
||||
using CategoryTypes = CategoryTypesHelper<CATEGORY, 1, 2, 4, 8, 10, 16, 32>;
|
||||
|
||||
using IntegerTypes = CategoryTypes<TypeCategory::Integer>;
|
||||
using RealTypes = CategoryTypes<TypeCategory::Real>;
|
||||
|
@ -312,14 +322,14 @@ using GenericScalar = SomeScalar<AllIntrinsicTypes>;
|
|||
|
||||
// Represents a type of any supported kind within a particular category.
|
||||
template<TypeCategory CATEGORY> struct SomeKind {
|
||||
static constexpr bool isSpecificType{false};
|
||||
static constexpr bool isSpecificIntrinsicType{false};
|
||||
static constexpr TypeCategory category{CATEGORY};
|
||||
using Scalar = SomeKindScalar<category>;
|
||||
};
|
||||
|
||||
template<> class SomeKind<TypeCategory::Derived> {
|
||||
public:
|
||||
static constexpr bool isSpecificType{true};
|
||||
static constexpr bool isSpecificIntrinsicType{true};
|
||||
static constexpr TypeCategory category{TypeCategory::Derived};
|
||||
using Scalar = void;
|
||||
|
||||
|
@ -347,7 +357,7 @@ using SomeDerived = SomeKind<TypeCategory::Derived>;
|
|||
using SomeCategory = std::tuple<SomeInteger, SomeReal, SomeComplex,
|
||||
SomeCharacter, SomeLogical, SomeDerived>;
|
||||
struct SomeType {
|
||||
static constexpr bool isSpecificType{false};
|
||||
static constexpr bool isSpecificIntrinsicType{false};
|
||||
using Scalar = GenericScalar;
|
||||
};
|
||||
|
||||
|
|
|
@ -234,7 +234,8 @@ template<typename A> class Designator {
|
|||
|
||||
public:
|
||||
using Result = A;
|
||||
static_assert(Result::isSpecificType);
|
||||
static_assert(Result::isSpecificIntrinsicType ||
|
||||
std::is_same_v<Result, SomeKind<TypeCategory::Derived>>);
|
||||
EVALUATE_UNION_CLASS_BOILERPLATE(Designator)
|
||||
Designator(const DataRef &that) : u{common::MoveVariant<Variant>(that.u)} {}
|
||||
Designator(DataRef &&that)
|
||||
|
@ -315,7 +316,8 @@ protected:
|
|||
|
||||
template<typename A> struct FunctionRef : public UntypedFunctionRef {
|
||||
using Result = A;
|
||||
static_assert(Result::isSpecificType);
|
||||
static_assert(Result::isSpecificIntrinsicType ||
|
||||
std::is_same_v<Result, SomeKind<TypeCategory::Derived>>);
|
||||
// Subtlety: There is a distinction that must be maintained here between an
|
||||
// actual argument expression that *is* a variable and one that is not,
|
||||
// e.g. between X and (X). The parser attempts to parse each argument
|
||||
|
@ -339,7 +341,8 @@ template<typename A> struct FunctionRef : public UntypedFunctionRef {
|
|||
|
||||
template<typename A> struct Variable {
|
||||
using Result = A;
|
||||
static_assert(Result::isSpecificType);
|
||||
static_assert(Result::isSpecificIntrinsicType ||
|
||||
std::is_same_v<Result, SomeKind<TypeCategory::Derived>>);
|
||||
EVALUATE_UNION_CLASS_BOILERPLATE(Variable)
|
||||
std::optional<DynamicType> GetType() const {
|
||||
return std::visit([](const auto &x) { return x.GetType(); }, u);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
template<int KIND> void testKind() {
|
||||
using Type =
|
||||
Fortran::evaluate::Type<Fortran::common::TypeCategory::Logical, KIND>;
|
||||
TEST(Type::isSpecificType);
|
||||
TEST(Type::isSpecificIntrinsicType);
|
||||
TEST(Type::category == Fortran::common::TypeCategory::Logical);
|
||||
TEST(Type::kind == KIND);
|
||||
using Value = Fortran::evaluate::Scalar<Type>;
|
||||
|
|
Loading…
Reference in New Issue