[flang] checkpoint array/struct constructor work

Original-commit: flang-compiler/f18@b0a574fa35
Reviewed-on: https://github.com/flang-compiler/f18/pull/287
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-02-08 10:39:10 -08:00
parent 25807d88f4
commit 4313f4c762
10 changed files with 217 additions and 130 deletions

View File

@ -1,5 +1,5 @@
<!--
Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
-->
As a general principle, this compiler will accept by default and
@ -79,3 +79,4 @@ Extensions and legacy features deliberately not supported
* `B` suffix on unquoted octal constants
* `Z` prefix on unquoted hexadecimal constants (dangerous)
* `T` and `F` as abbreviations for `.TRUE.` and `.FALSE.` (dangerous)
* Use of host FORMAT labels in internal subprograms (PGI-only feature)

View File

@ -19,10 +19,11 @@
namespace Fortran::evaluate {
template<typename T> ConstantBase<T>::~ConstantBase() {}
template<typename RESULT, typename VALUE>
ConstantBase<RESULT, VALUE>::~ConstantBase() {}
template<typename T>
std::ostream &ConstantBase<T>::AsFortran(std::ostream &o) const {
template<typename RESULT, typename VALUE>
std::ostream &ConstantBase<RESULT, VALUE>::AsFortran(std::ostream &o) const {
if (Rank() > 1) {
o << "reshape(";
}
@ -36,14 +37,14 @@ std::ostream &ConstantBase<T>::AsFortran(std::ostream &o) const {
} else {
o << ',';
}
if constexpr (T::category == TypeCategory::Integer) {
o << value.SignedDecimal() << '_' << T::kind;
} else if constexpr (T::category == TypeCategory::Real ||
T::category == TypeCategory::Complex) {
value.AsFortran(o, T::kind);
} else if constexpr (T::category == TypeCategory::Character) {
o << T::kind << '_' << parser::QuoteCharacterLiteral(value);
} else if constexpr (T::category == TypeCategory::Logical) {
if constexpr (Result::category == TypeCategory::Integer) {
o << value.SignedDecimal() << '_' << Result::kind;
} else if constexpr (Result::category == TypeCategory::Real ||
Result::category == TypeCategory::Complex) {
value.AsFortran(o, Result::kind);
} else if constexpr (Result::category == TypeCategory::Character) {
o << Result::kind << '_' << parser::QuoteCharacterLiteral(value);
} else if constexpr (Result::category == TypeCategory::Logical) {
if (value.IsTrue()) {
o << ".true.";
} else {
@ -51,7 +52,7 @@ std::ostream &ConstantBase<T>::AsFortran(std::ostream &o) const {
}
o << '_' << Result::kind;
} else {
value.AsFortran(o);
StructureConstructor{AsConstant().derivedTypeSpec(), value}.AsFortran(o);
}
}
if (Rank() > 0) {
@ -69,9 +70,9 @@ std::ostream &ConstantBase<T>::AsFortran(std::ostream &o) const {
return o;
}
template<typename T>
auto ConstantBase<T>::At(const std::vector<std::int64_t> &index) const
-> Value {
template<typename RESULT, typename VALUE>
auto ConstantBase<RESULT, VALUE>::At(
const std::vector<std::int64_t> &index) const -> Value {
CHECK(index.size() == static_cast<std::size_t>(Rank()));
std::int64_t stride{1}, offset{0};
int dim{0};
@ -84,7 +85,8 @@ auto ConstantBase<T>::At(const std::vector<std::int64_t> &index) const
return values_.at(offset);
}
template<typename T> Constant<SubscriptInteger> ConstantBase<T>::SHAPE() const {
template<typename RESULT, typename VALUE>
Constant<SubscriptInteger> ConstantBase<RESULT, VALUE>::SHAPE() const {
using IntType = Scalar<SubscriptInteger>;
std::vector<IntType> result;
for (std::int64_t dim : shape_) {
@ -93,10 +95,30 @@ template<typename T> Constant<SubscriptInteger> ConstantBase<T>::SHAPE() const {
return {std::move(result), std::vector<std::int64_t>{Rank()}};
}
Constant<SomeDerived>::Constant(const StructureConstructor &x)
: Base{x.values()}, derivedTypeSpec_{&x.derivedTypeSpec()} {}
Constant<SomeDerived>::Constant(StructureConstructor &&x)
: Base{std::move(x.values())}, derivedTypeSpec_{&x.derivedTypeSpec()} {}
Constant<SomeDerived>::Constant(const semantics::DerivedTypeSpec &spec,
std::vector<StructureConstructorValues> &&x, std::vector<std::int64_t> &&s)
: Base{std::move(x), std::move(s)}, derivedTypeSpec_{&spec} {}
static std::vector<StructureConstructorValues> GetValues(
std::vector<StructureConstructor> &&x) {
std::vector<StructureConstructorValues> result;
for (auto &&structure : std::move(x)) {
result.emplace_back(std::move(structure.values()));
}
return result;
}
Constant<SomeDerived>::Constant(const semantics::DerivedTypeSpec &spec,
std::vector<StructureConstructor> &&x, std::vector<std::int64_t> &&s)
: Base{std::move(x), std::move(s)}, spec_{&spec} {}
: Base{GetValues(std::move(x)), std::move(s)}, derivedTypeSpec_{&spec} {}
FOR_EACH_SPECIFIC_TYPE(template class ConstantBase)
FOR_EACH_INTRINSIC_KIND(template class ConstantBase)
template class ConstantBase<SomeDerived, StructureConstructorValues>;
FOR_EACH_INTRINSIC_KIND(template class Constant)
}

View File

@ -16,6 +16,7 @@
#define FORTRAN_EVALUATE_CONSTANT_H_
#include "type.h"
#include <map>
#include <ostream>
namespace Fortran::evaluate {
@ -27,10 +28,10 @@ namespace Fortran::evaluate {
template<typename> class Constant;
template<typename RESULT> class ConstantBase {
template<typename RESULT, typename VALUE = Scalar<RESULT>> class ConstantBase {
public:
using Result = RESULT;
using Value = Scalar<Result>;
using Value = VALUE;
template<typename A> ConstantBase(const A &x) : values_{x} {}
template<typename A>
@ -97,30 +98,37 @@ public:
// TODO pmk: make CHARACTER values contiguous (they're strings now)
};
template<> class Constant<SomeDerived> : public ConstantBase<SomeDerived> {
using StructureConstructorValues =
std::map<const semantics::Symbol *, CopyableIndirection<Expr<SomeType>>>;
template<>
class Constant<SomeDerived>
: public ConstantBase<SomeDerived, StructureConstructorValues> {
public:
using Result = SomeDerived;
using Base = ConstantBase<Result>;
template<typename A>
Constant(const semantics::DerivedTypeSpec &spec, const A &x)
: Base{x}, spec_{&spec} {}
template<typename A>
Constant(const semantics::DerivedTypeSpec &spec,
std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: Base{std::move(x)}, spec_{&spec} {}
using Base = ConstantBase<Result, StructureConstructorValues>;
Constant(const StructureConstructor &);
Constant(StructureConstructor &&);
Constant(const semantics::DerivedTypeSpec &, std::vector<Value> &&,
std::vector<std::int64_t> &&);
Constant(const semantics::DerivedTypeSpec &,
std::vector<StructureConstructor> &&, std::vector<std::int64_t> &&);
CLASS_BOILERPLATE(Constant)
const semantics::DerivedTypeSpec &derivedTypeSpec() const {
return *derivedTypeSpec_;
}
DynamicType GetType() const {
return DynamicType{TypeCategory::Derived, 0, spec_};
return DynamicType{TypeCategory::Derived, 0, derivedTypeSpec_};
}
private:
const semantics::DerivedTypeSpec *spec_;
const semantics::DerivedTypeSpec *derivedTypeSpec_;
};
FOR_EACH_SPECIFIC_TYPE(extern template class ConstantBase)
FOR_EACH_INTRINSIC_KIND(extern template class ConstantBase)
extern template class ConstantBase<SomeDerived, StructureConstructorValues>;
FOR_EACH_INTRINSIC_KIND(extern template class Constant)
}
#endif // FORTRAN_EVALUATE_CONSTANT_H_

View File

@ -130,6 +130,12 @@ std::ostream &ArrayConstructor<Type<TypeCategory::Character, KIND>>::AsFortran(
return o << ']';
}
std::ostream &ArrayConstructor<SomeDerived>::AsFortran(std::ostream &o) const {
o << '[' << GetType().AsFortran() << "::";
Emit(o, values);
return o << ']';
}
template<typename RESULT>
std::ostream &ExpressionBase<RESULT>::AsFortran(std::ostream &o) const {
std::visit(
@ -234,7 +240,7 @@ bool ArrayConstructorValues<R>::operator==(
template<typename R>
bool ArrayConstructor<R>::operator==(const ArrayConstructor<R> &that) const {
return type == that.type && values == that.values;
return values == that.values;
}
template<int KIND>
@ -243,6 +249,78 @@ bool ArrayConstructor<Type<TypeCategory::Character, KIND>>::operator==(
return length == that.length && values == that.values;
}
bool ArrayConstructor<SomeDerived>::operator==(
const ArrayConstructor<SomeDerived> &that) const {
return derivedTypeSpec_ == that.derivedTypeSpec_ && values == that.values;
}
StructureConstructor::StructureConstructor(
const semantics::DerivedTypeSpec &spec,
const StructureConstructorValues &values)
: derivedTypeSpec_{&spec}, values_{values} {}
StructureConstructor::StructureConstructor(
const semantics::DerivedTypeSpec &spec, StructureConstructorValues &&values)
: derivedTypeSpec_{&spec}, values_{std::move(values)} {}
StructureConstructor::StructureConstructor(const StructureConstructor &that)
: derivedTypeSpec_{that.derivedTypeSpec_}, values_{that.values_} {}
StructureConstructor::StructureConstructor(StructureConstructor &&that)
: derivedTypeSpec_{that.derivedTypeSpec_}, values_{std::move(that.values_)} {}
StructureConstructor::~StructureConstructor() {}
StructureConstructor &StructureConstructor::operator=(
const StructureConstructor &that) {
derivedTypeSpec_ = that.derivedTypeSpec_;
values_ = that.values_;
return *this;
}
StructureConstructor &StructureConstructor::operator=(
StructureConstructor &&that) {
derivedTypeSpec_ = that.derivedTypeSpec_;
values_ = std::move(that.values_);
return *this;
}
bool StructureConstructor::operator==(const StructureConstructor &that) const {
return derivedTypeSpec_ == that.derivedTypeSpec_ && values_ == that.values_;
}
DynamicType StructureConstructor::GetType() const {
return {TypeCategory::Derived, 0, derivedTypeSpec_};
}
StructureConstructor &StructureConstructor::Add(
const Symbol &symbol, Expr<SomeType> &&expr) {
values_.emplace(&symbol, std::move(expr));
return *this;
}
std::ostream &StructureConstructor::AsFortran(std::ostream &o) const {
DerivedTypeSpecAsFortran(o, *derivedTypeSpec_);
if (values_.empty()) {
o << '(';
} else {
char ch{'('};
for (const auto &[symbol, value] : values_) {
value->AsFortran(o << ch << symbol->name().ToString() << '=');
ch = ',';
}
}
return o << ')';
}
std::ostream &DerivedTypeSpecAsFortran(
std::ostream &o, const semantics::DerivedTypeSpec &spec) {
o << "TYPE("s << spec.typeSymbol().name().ToString();
if (!spec.parameters().empty()) {
char ch{'('};
for (const auto &[name, value] : spec.parameters()) {
value.GetExplicit()->AsFortran(o << ch << name.ToString() << '=');
ch = ',';
}
o << ')';
}
return o;
}
bool GenericExprWrapper::operator==(const GenericExprWrapper &that) const {
return v == that.v;
}
@ -257,7 +335,7 @@ FOR_EACH_REAL_KIND(template struct Relational)
FOR_EACH_CHARACTER_KIND(template struct Relational)
template struct Relational<SomeType>;
FOR_EACH_TYPE_AND_KIND(template class ExpressionBase)
FOR_EACH_SPECIFIC_TYPE(template struct ArrayConstructor)
FOR_EACH_INTRINSIC_KIND(template struct ArrayConstructor)
}
// For reclamation of analyzed expressions to which owning pointers have

View File

@ -425,18 +425,15 @@ template<typename RESULT> struct ArrayConstructorValues {
std::vector<ArrayConstructorValue<Result>> values;
};
// TODO pmk: use a common base class as with Constant
template<typename RESULT> struct ArrayConstructor {
using Result = RESULT;
CLASS_BOILERPLATE(ArrayConstructor)
ArrayConstructor(Result &&t, ArrayConstructorValues<Result> &&v)
: type{std::move(t)}, values{std::move(v)} {
CHECK(type.category != TypeCategory::Character);
}
ArrayConstructor(ArrayConstructorValues<Result> &&v) : values{std::move(v)} {}
bool operator==(const ArrayConstructor<RESULT> &) const;
DynamicType GetType() const { return type.GetType(); }
static constexpr DynamicType GetType() { return Result::GetType(); }
static constexpr int Rank() { return 1; }
std::ostream &AsFortran(std::ostream &) const;
Result type;
ArrayConstructorValues<Result> values;
};
@ -445,8 +442,8 @@ struct ArrayConstructor<Type<TypeCategory::Character, KIND>> {
using Result = Type<TypeCategory::Character, KIND>;
CLASS_BOILERPLATE(ArrayConstructor)
ArrayConstructor(
ArrayConstructorValues<Result> &&v, Expr<SubscriptInteger> &&len)
: values{std::move(v)}, length{std::move(len)} {}
Expr<SubscriptInteger> &&len, ArrayConstructorValues<Result> &&v)
: length{std::move(len)}, values{std::move(v)} {}
~ArrayConstructor();
bool operator==(const ArrayConstructor<Result> &) const;
static constexpr DynamicType GetType() { return Result::GetType(); }
@ -454,8 +451,27 @@ struct ArrayConstructor<Type<TypeCategory::Character, KIND>> {
std::ostream &AsFortran(std::ostream &) const;
const Expr<SubscriptInteger> &LEN() const { return *length; }
ArrayConstructorValues<Result> values;
CopyableIndirection<Expr<SubscriptInteger>> length;
ArrayConstructorValues<Result> values;
};
template<> struct ArrayConstructor<SomeDerived> {
using Result = SomeDerived;
CLASS_BOILERPLATE(ArrayConstructor)
ArrayConstructor(const semantics::DerivedTypeSpec &spec,
ArrayConstructorValues<Result> &&v)
: derivedTypeSpec_{&spec}, values{std::move(v)} {}
bool operator==(const ArrayConstructor<Result> &) const;
const semantics::DerivedTypeSpec &derivedTypeSpec() const {
return *derivedTypeSpec_;
}
DynamicType GetType() const {
return DynamicType{TypeCategory::Derived, 0, derivedTypeSpec_};
}
static constexpr int Rank() { return 1; }
std::ostream &AsFortran(std::ostream &) const;
const semantics::DerivedTypeSpec *derivedTypeSpec_;
ArrayConstructorValues<Result> values;
};
// Expression representations for each type category.
@ -635,15 +651,16 @@ FOR_EACH_LOGICAL_KIND(extern template class Expr)
class StructureConstructor {
public:
using Values = std::list<std::pair<const semantics::Symbol *,
CopyableIndirection<Expr<SomeType>>>>;
// N.B. CLASS_BOILERPLATE() can't be used here due to forward reference
// to Expr<SomeType> preventing the use of "= default" constructors and
// assignment operators.
StructureConstructor() = delete;
explicit StructureConstructor(const semantics::DerivedTypeSpec &spec)
: derivedTypeSpec_{&spec} {}
StructureConstructor(
const semantics::DerivedTypeSpec &, const StructureConstructorValues &);
StructureConstructor(
const semantics::DerivedTypeSpec &, StructureConstructorValues &&);
StructureConstructor(const StructureConstructor &);
StructureConstructor(StructureConstructor &&);
~StructureConstructor();
@ -653,8 +670,8 @@ public:
const semantics::DerivedTypeSpec &derivedTypeSpec() const {
return *derivedTypeSpec_;
}
Values &values() { return values_; }
const Values &values() const { return values_; }
StructureConstructorValues &values() { return values_; }
const StructureConstructorValues &values() const { return values_; }
bool operator==(const StructureConstructor &) const;
StructureConstructor &Add(const semantics::Symbol &, Expr<SomeType> &&);
@ -664,7 +681,7 @@ public:
private:
const semantics::DerivedTypeSpec *derivedTypeSpec_;
Values values_;
StructureConstructorValues values_;
};
// An expression whose result has a derived type.
@ -741,8 +758,11 @@ struct GenericExprWrapper {
Expr<SomeType> v;
};
std::ostream &DerivedTypeSpecAsFortran(
std::ostream &, const semantics::DerivedTypeSpec &);
FOR_EACH_CATEGORY_TYPE(extern template class Expr)
FOR_EACH_TYPE_AND_KIND(extern template class ExpressionBase)
FOR_EACH_SPECIFIC_TYPE(extern template struct ArrayConstructor)
FOR_EACH_INTRINSIC_KIND(extern template struct ArrayConstructor)
}
#endif // FORTRAN_EVALUATE_EXPRESSION_H_

View File

@ -230,10 +230,10 @@ public:
Expr<T> FoldArray(ArrayConstructor<T> &&array) {
if (FoldArray(array.values)) {
std::int64_t n = elements_.size();
auto n{static_cast<std::int64_t>(elements_.size())};
if constexpr (std::is_same_v<T, SomeDerived>) {
return Expr<T>{Constant<T>{array.type.spec(), std::move(elements_),
std::vector<std::int64_t>{n}}};
return Expr<T>{Constant<T>{array.derivedTypeSpec(),
std::move(elements_), std::vector<std::int64_t>{n}}};
} else {
return Expr<T>{
Constant<T>{std::move(elements_), std::vector<std::int64_t>{n}}};
@ -252,7 +252,11 @@ private:
int rank{c->Rank()};
std::vector<std::int64_t> index(shape.size(), 1);
for (std::size_t n{c->size()}; n-- > 0;) {
elements_.push_back(c->At(index));
if constexpr (std::is_same_v<T, SomeDerived>) {
elements_.emplace_back(c->derivedTypeSpec(), c->At(index));
} else {
elements_.emplace_back(c->At(index));
}
for (int d{0}; d < rank; ++d) {
if (++index[d] <= shape[d]) {
break;
@ -315,8 +319,7 @@ Expr<SomeDerived> FoldOperation(
for (auto &&[symbol, value] : std::move(structure.values())) {
result.Add(*symbol, Fold(context, std::move(*value)));
}
return Expr<SomeDerived>{
Constant<SomeDerived>{result.derivedTypeSpec(), result}};
return Expr<SomeDerived>{Constant<SomeDerived>{result}};
}
// Substitute a bare type parameter reference with its value if it has one now

View File

@ -21,7 +21,6 @@
#include "../semantics/type.h"
#include <algorithm>
#include <optional>
#include <ostream>
#include <sstream>
#include <string>
@ -185,69 +184,9 @@ bool SomeKind<TypeCategory::Derived>::operator==(
return spec_ == that.spec_ && descriptor_ == that.descriptor_;
}
static std::ostream &DerivedTypeSpecAsFortran(
std::ostream &o, const semantics::DerivedTypeSpec &spec) {
o << "TYPE("s << spec.typeSymbol().name().ToString();
if (!spec.parameters().empty()) {
char ch{'('};
for (const auto &[name, value] : spec.parameters()) {
value.GetExplicit()->AsFortran(o << ch << name.ToString() << '=');
ch = ',';
}
o << ')';
}
return o;
}
std::string SomeDerived::AsFortran() const {
std::stringstream out;
DerivedTypeSpecAsFortran(out, spec());
return out.str();
}
StructureConstructor::StructureConstructor(const StructureConstructor &that)
: derivedTypeSpec_{that.derivedTypeSpec_}, values_{that.values_} {}
StructureConstructor::StructureConstructor(StructureConstructor &&that)
: derivedTypeSpec_{that.derivedTypeSpec_}, values_{std::move(that.values_)} {}
StructureConstructor::~StructureConstructor() {}
StructureConstructor &StructureConstructor::operator=(
const StructureConstructor &that) {
derivedTypeSpec_ = that.derivedTypeSpec_;
values_ = that.values_;
return *this;
}
StructureConstructor &StructureConstructor::operator=(
StructureConstructor &&that) {
derivedTypeSpec_ = that.derivedTypeSpec_;
values_ = std::move(that.values_);
return *this;
}
bool StructureConstructor::operator==(const StructureConstructor &that) const {
return derivedTypeSpec_ == that.derivedTypeSpec_ && values_ == that.values_;
}
DynamicType StructureConstructor::GetType() const {
return {TypeCategory::Derived, 0, derivedTypeSpec_};
}
StructureConstructor &StructureConstructor::Add(
const Symbol &symbol, Expr<SomeType> &&expr) {
values_.emplace_back(&symbol, std::move(expr));
return *this;
}
std::ostream &StructureConstructor::AsFortran(std::ostream &o) const {
DerivedTypeSpecAsFortran(o, *derivedTypeSpec_);
if (values_.empty()) {
o << '(';
} else {
char ch{'('};
for (const auto &[symbol, value] : values_) {
value->AsFortran(o << ch << symbol->name().ToString() << '=');
ch = ',';
}
}
return o << ')';
}
}

View File

@ -288,6 +288,9 @@ using SomeDerived = SomeKind<TypeCategory::Derived>;
using SomeCategory = std::tuple<SomeInteger, SomeReal, SomeComplex,
SomeCharacter, SomeLogical, SomeDerived>;
using AllTypes =
common::CombineTuples<AllIntrinsicTypes, std::tuple<SomeDerived>>;
template<typename T> using Scalar = typename std::decay_t<T>::Scalar;
// When Scalar<T> is S, then TypeOf<S> is T.

View File

@ -1284,20 +1284,25 @@ ArrayConstructorValues<T> MakeSpecific(
struct ArrayConstructorTypeVisitor {
using Result = MaybeExpr;
using Types = LengthlessIntrinsicTypes;
using Types = AllTypes;
template<typename T> Result Test() {
if (type.category == T::category && type.kind == T::kind) {
if constexpr (T::category == TypeCategory::Character) {
CHECK(type.length.has_value());
if (type.category == T::category) {
if constexpr (T::category == TypeCategory::Derived) {
CHECK(type.derived != nullptr);
return AsMaybeExpr(ArrayConstructor<T>{
MakeSpecific<T>(std::move(values)), std::move(*type.length)});
} else {
return AsMaybeExpr(
ArrayConstructor<T>{T{}, MakeSpecific<T>(std::move(values))});
*type.derived, MakeSpecific<T>(std::move(values))});
} else if (type.kind == T::kind) {
if constexpr (T::category == TypeCategory::Character) {
CHECK(type.length.has_value());
return AsMaybeExpr(ArrayConstructor<T>{
std::move(*type.length), MakeSpecific<T>(std::move(values))});
} else {
return AsMaybeExpr(
ArrayConstructor<T>{MakeSpecific<T>(std::move(values))});
}
}
} else {
return std::nullopt;
}
return std::nullopt;
}
DynamicTypeWithLength type;
ArrayConstructorValues<SomeType> values;

View File

@ -113,7 +113,15 @@ set(MODFILE_TESTS
)
set(LABEL_TESTS
label*.[Ff]90
# label*.[Ff]90 # 01, 05, 06, 07 loop with current master
label02.f90
label03.f90
label04.f90
label08.f90
label09.f90
label10.f90
label11.f90
label12.f90
)
set(DOCONCURRENT_TESTS