[flang] Rework Constant<character>

Original-commit: flang-compiler/f18@fc807bfd7d
Reviewed-on: https://github.com/flang-compiler/f18/pull/287
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2019-02-11 14:56:03 -08:00
parent 5b79ffc5f6
commit 83a8530612
6 changed files with 183 additions and 54 deletions

View File

@ -133,5 +133,9 @@ template<typename A> struct ListItemCount {
return Fortran::common::EnumIndexToString( \ return Fortran::common::EnumIndexToString( \
static_cast<int>(e), #__VA_ARGS__); \ static_cast<int>(e), #__VA_ARGS__); \
} }
// Given a const reference to a value, return a copy of the value.
template<typename A> A Clone(const A &x) { return x; }
} }
#endif // FORTRAN_COMMON_IDIOMS_H_ #endif // FORTRAN_COMMON_IDIOMS_H_

View File

@ -16,12 +16,26 @@
#include "expression.h" #include "expression.h"
#include "type.h" #include "type.h"
#include "../parser/characters.h" #include "../parser/characters.h"
#include <algorithm>
namespace Fortran::evaluate { namespace Fortran::evaluate {
template<typename RESULT, typename VALUE> template<typename RESULT, typename VALUE>
ConstantBase<RESULT, VALUE>::~ConstantBase() {} ConstantBase<RESULT, VALUE>::~ConstantBase() {}
static void ShapeAsFortran(
std::ostream &o, const std::vector<std::int64_t> &shape) {
if (shape.size() > 1) {
o << ",shape=";
char ch{'['};
for (auto dim : shape) {
o << ch << dim;
ch = ',';
}
o << "])";
}
}
template<typename RESULT, typename VALUE> template<typename RESULT, typename VALUE>
std::ostream &ConstantBase<RESULT, VALUE>::AsFortran(std::ostream &o) const { std::ostream &ConstantBase<RESULT, VALUE>::AsFortran(std::ostream &o) const {
if (Rank() > 1) { if (Rank() > 1) {
@ -58,43 +72,116 @@ std::ostream &ConstantBase<RESULT, VALUE>::AsFortran(std::ostream &o) const {
if (Rank() > 0) { if (Rank() > 0) {
o << ']'; o << ']';
} }
if (Rank() > 1) { ShapeAsFortran(o, shape_);
o << ",shape=";
char ch{'['};
for (auto dim : shape_) {
o << ch << dim;
ch = ',';
}
o << "])";
}
return o; return o;
} }
template<typename RESULT, typename VALUE> static std::int64_t SubscriptsToOffset(const std::vector<std::int64_t> &index,
auto ConstantBase<RESULT, VALUE>::At( const std::vector<std::int64_t> &shape) {
const std::vector<std::int64_t> &index) const -> Value { CHECK(index.size() == shape.size());
CHECK(index.size() == static_cast<std::size_t>(Rank()));
std::int64_t stride{1}, offset{0}; std::int64_t stride{1}, offset{0};
int dim{0}; int dim{0};
for (std::int64_t j : index) { for (std::int64_t j : index) {
std::int64_t bound{shape_[dim++]}; std::int64_t bound{shape[dim++]};
CHECK(j >= 1 && j <= bound); CHECK(j >= 1 && j <= bound);
offset += stride * (j - 1); offset += stride * (j - 1);
stride *= bound; stride *= bound;
} }
return values_.at(offset); return offset;
}
template<typename RESULT, typename VALUE>
auto ConstantBase<RESULT, VALUE>::At(
const std::vector<std::int64_t> &index) const -> ScalarValue {
return values_.at(SubscriptsToOffset(index, shape_));
}
static Constant<SubscriptInteger> ShapeAsConstant(
const std::vector<std::int64_t> &shape) {
using IntType = Scalar<SubscriptInteger>;
std::vector<IntType> result;
for (std::int64_t dim : shape) {
result.emplace_back(dim);
}
return {std::move(result),
std::vector<std::int64_t>{static_cast<std::int64_t>(shape.size())}};
} }
template<typename RESULT, typename VALUE> template<typename RESULT, typename VALUE>
Constant<SubscriptInteger> ConstantBase<RESULT, VALUE>::SHAPE() const { Constant<SubscriptInteger> ConstantBase<RESULT, VALUE>::SHAPE() const {
using IntType = Scalar<SubscriptInteger>; return ShapeAsConstant(shape_);
std::vector<IntType> result;
for (std::int64_t dim : shape_) {
result.emplace_back(dim);
}
return {std::move(result), std::vector<std::int64_t>{Rank()}};
} }
// Constant<Type<TypeCategory::Character, KIND> specializations
template<int KIND>
Constant<Type<TypeCategory::Character, KIND>>::Constant(const ScalarValue &str)
: values_{str}, length_{static_cast<std::int64_t>(values_.size())} {}
template<int KIND>
Constant<Type<TypeCategory::Character, KIND>>::Constant(ScalarValue &&str)
: values_{std::move(str)}, length_{
static_cast<std::int64_t>(values_.size())} {}
template<int KIND>
Constant<Type<TypeCategory::Character, KIND>>::Constant(std::int64_t len,
std::vector<ScalarValue> &&strings, std::vector<std::int64_t> &&dims)
: length_{len} {
values_.assign(strings.size() * length_,
static_cast<typename ScalarValue::value_type>(' '));
std::int64_t at{0};
for (const auto &str : strings) {
values_.replace(
at, std::min(length_, static_cast<std::int64_t>(str.size())), str);
at += length_;
}
CHECK(at == static_cast<std::int64_t>(values_.size()));
}
template<int KIND> Constant<Type<TypeCategory::Character, KIND>>::~Constant() {}
template<int KIND>
auto Constant<Type<TypeCategory::Character, KIND>>::At(
const std::vector<std::int64_t> &index) const -> ScalarValue {
auto offset{SubscriptsToOffset(index, shape_)};
return values_.substr(offset, length_);
}
template<int KIND>
Constant<SubscriptInteger>
Constant<Type<TypeCategory::Character, KIND>>::SHAPE() const {
return ShapeAsConstant(shape_);
}
template<int KIND>
std::ostream &Constant<Type<TypeCategory::Character, KIND>>::AsFortran(
std::ostream &o) const {
if (Rank() > 1) {
o << "reshape(";
}
if (Rank() > 0) {
o << '[' << GetType().AsFortran() << "::";
}
bool first{true};
auto total{static_cast<std::int64_t>(size())};
for (std::int64_t at{0}; at < total; at += length_) {
ScalarValue value{values_.substr(at, length_)};
if (first) {
first = false;
} else {
o << ',';
}
o << Result::kind << '_' << parser::QuoteCharacterLiteral(value);
}
if (Rank() > 0) {
o << ']';
}
ShapeAsFortran(o, shape_);
return o;
}
// Constant<SomeDerived> specialization
Constant<SomeDerived>::Constant(const StructureConstructor &x) Constant<SomeDerived>::Constant(const StructureConstructor &x)
: Base{x.values()}, derivedTypeSpec_{&x.derivedTypeSpec()} {} : Base{x.values()}, derivedTypeSpec_{&x.derivedTypeSpec()} {}
@ -118,7 +205,7 @@ Constant<SomeDerived>::Constant(const semantics::DerivedTypeSpec &spec,
std::vector<StructureConstructor> &&x, std::vector<std::int64_t> &&s) std::vector<StructureConstructor> &&x, std::vector<std::int64_t> &&s)
: Base{GetValues(std::move(x)), std::move(s)}, derivedTypeSpec_{&spec} {} : Base{GetValues(std::move(x)), std::move(s)}, derivedTypeSpec_{&spec} {}
FOR_EACH_INTRINSIC_KIND(template class ConstantBase) FOR_EACH_LENGTHLESS_INTRINSIC_KIND(template class ConstantBase)
template class ConstantBase<SomeDerived, StructureConstructorValues>; template class ConstantBase<SomeDerived, StructureConstructorValues>;
FOR_EACH_INTRINSIC_KIND(template class Constant) FOR_EACH_INTRINSIC_KIND(template class Constant)
} }

View File

@ -22,23 +22,31 @@
namespace Fortran::evaluate { namespace Fortran::evaluate {
// Wraps a constant value in a class templated by its resolved type. // Wraps a constant value in a class templated by its resolved type.
// N.B. Generic constants are represented by generic expressions // This Constant<> template class should be instantiated only for
// (like Expr<SomeInteger> & Expr<SomeType>) wrapping the appropriate // concrete intrinsic types and SomeDerived. There is no instance
// instantiations of Constant. // Constant<Expr<SomeType>> since there is no way to constrain each
// element of its array to hold the same type. To represent a generic
// constants, use a generic expression like Expr<SomeInteger> &
// Expr<SomeType>) to wrap the appropriate instantiation of Constant<>.
template<typename> class Constant; template<typename> class Constant;
template<typename RESULT, typename VALUE = Scalar<RESULT>> class ConstantBase { // Constant<> is specialized for Character kinds and SomeDerived.
// The non-Character intrinsic types, and SomeDerived, share enough
// common behavior that they use this common base class.
template<typename RESULT, typename SCALAR = Scalar<RESULT>> class ConstantBase {
static_assert(RESULT::category != TypeCategory::Character);
public: public:
using Result = RESULT; using Result = RESULT;
using Value = VALUE; using ScalarValue = SCALAR;
template<typename A> ConstantBase(const A &x) : values_{x} {} template<typename A> ConstantBase(const A &x) : values_{x} {}
template<typename A> template<typename A>
ConstantBase(std::enable_if_t<!std::is_reference_v<A>, A> &&x) ConstantBase(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: values_{std::move(x)} {} : values_{std::move(x)} {}
ConstantBase(std::vector<Value> &&x, std::vector<std::int64_t> &&s) ConstantBase(std::vector<ScalarValue> &&x, std::vector<std::int64_t> &&dims)
: values_(std::move(x)), shape_(std::move(s)) {} : values_(std::move(x)), shape_(std::move(dims)) {}
~ConstantBase(); ~ConstantBase();
int Rank() const { return static_cast<int>(shape_.size()); } int Rank() const { return static_cast<int>(shape_.size()); }
@ -49,19 +57,19 @@ public:
std::size_t size() const { return values_.size(); } std::size_t size() const { return values_.size(); }
const std::vector<std::int64_t> &shape() const { return shape_; } const std::vector<std::int64_t> &shape() const { return shape_; }
Value operator*() const { ScalarValue operator*() const {
CHECK(values_.size() == 1); CHECK(values_.size() == 1);
return values_.at(0); return values_.at(0);
} }
// Apply 1-based subscripts // Apply 1-based subscripts
Value At(const std::vector<std::int64_t> &) const; ScalarValue At(const std::vector<std::int64_t> &) const;
Constant<SubscriptInteger> SHAPE() const; Constant<SubscriptInteger> SHAPE() const;
std::ostream &AsFortran(std::ostream &) const; std::ostream &AsFortran(std::ostream &) const;
protected: protected:
std::vector<Value> values_; std::vector<ScalarValue> values_;
std::vector<std::int64_t> shape_; std::vector<std::int64_t> shape_;
private: private:
@ -75,27 +83,49 @@ private:
template<typename T> class Constant : public ConstantBase<T> { template<typename T> class Constant : public ConstantBase<T> {
public: public:
using Result = T; using Result = T;
using ConstantBase<Result>::ConstantBase; using ScalarValue = Scalar<Result>;
using ConstantBase<Result, ScalarValue>::ConstantBase;
CLASS_BOILERPLATE(Constant) CLASS_BOILERPLATE(Constant)
static constexpr DynamicType GetType() { return Result::GetType(); } static constexpr DynamicType GetType() { return Result::GetType(); }
}; };
template<int KIND> template<int KIND> class Constant<Type<TypeCategory::Character, KIND>> {
class Constant<Type<TypeCategory::Character, KIND>>
: public ConstantBase<Type<TypeCategory::Character, KIND>> {
public: public:
using Result = Type<TypeCategory::Character, KIND>; using Result = Type<TypeCategory::Character, KIND>;
using ConstantBase<Result>::ConstantBase; using ScalarValue = Scalar<Result>;
CLASS_BOILERPLATE(Constant) CLASS_BOILERPLATE(Constant)
explicit Constant(const ScalarValue &);
explicit Constant(ScalarValue &&);
Constant(
std::int64_t, std::vector<ScalarValue> &&, std::vector<std::int64_t> &&);
~Constant();
int Rank() const { return static_cast<int>(shape_.size()); }
bool operator==(const Constant &that) const {
return shape_ == that.shape_ && values_ == that.values_;
}
bool empty() const { return values_.empty(); }
std::size_t size() const { return values_.size() / length_; }
const std::vector<std::int64_t> &shape() const { return shape_; }
std::int64_t LEN() const { return length_; }
ScalarValue operator*() const {
CHECK(static_cast<std::int64_t>(values_.size()) == length_);
return values_;
}
// Apply 1-based subscripts
ScalarValue At(const std::vector<std::int64_t> &) const;
Constant<SubscriptInteger> SHAPE() const;
std::ostream &AsFortran(std::ostream &) const;
static constexpr DynamicType GetType() { return Result::GetType(); } static constexpr DynamicType GetType() { return Result::GetType(); }
std::int64_t LEN() const {
if (this->values_.empty()) { private:
return 0; ScalarValue values_; // one contiguous string
} else { std::int64_t length_;
return static_cast<std::int64_t>(this->values_.front().size()); std::vector<std::int64_t> shape_;
}
}
// TODO pmk: make CHARACTER values contiguous (they're strings now)
}; };
using StructureConstructorValues = using StructureConstructorValues =
@ -109,7 +139,7 @@ public:
using Base = ConstantBase<Result, StructureConstructorValues>; using Base = ConstantBase<Result, StructureConstructorValues>;
Constant(const StructureConstructor &); Constant(const StructureConstructor &);
Constant(StructureConstructor &&); Constant(StructureConstructor &&);
Constant(const semantics::DerivedTypeSpec &, std::vector<Value> &&, Constant(const semantics::DerivedTypeSpec &, std::vector<ScalarValue> &&,
std::vector<std::int64_t> &&); std::vector<std::int64_t> &&);
Constant(const semantics::DerivedTypeSpec &, Constant(const semantics::DerivedTypeSpec &,
std::vector<StructureConstructor> &&, std::vector<std::int64_t> &&); std::vector<StructureConstructor> &&, std::vector<std::int64_t> &&);
@ -127,7 +157,7 @@ private:
const semantics::DerivedTypeSpec *derivedTypeSpec_; const semantics::DerivedTypeSpec *derivedTypeSpec_;
}; };
FOR_EACH_INTRINSIC_KIND(extern template class ConstantBase) FOR_EACH_LENGTHLESS_INTRINSIC_KIND(extern template class ConstantBase)
extern template class ConstantBase<SomeDerived, StructureConstructorValues>; extern template class ConstantBase<SomeDerived, StructureConstructorValues>;
FOR_EACH_INTRINSIC_KIND(extern template class Constant) FOR_EACH_INTRINSIC_KIND(extern template class Constant)
} }

View File

@ -72,7 +72,7 @@ Component FoldOperation(FoldingContext &context, Component &&component) {
Triplet FoldOperation(FoldingContext &context, Triplet &&triplet) { Triplet FoldOperation(FoldingContext &context, Triplet &&triplet) {
return {Fold(context, triplet.lower()), Fold(context, triplet.upper()), return {Fold(context, triplet.lower()), Fold(context, triplet.upper()),
Fold(context, Expr<SubscriptInteger>{triplet.stride()})}; Fold(context, common::Clone(triplet.stride()))};
} }
Subscript FoldOperation(FoldingContext &context, Subscript &&subscript) { Subscript FoldOperation(FoldingContext &context, Subscript &&subscript) {
@ -234,18 +234,23 @@ public:
if constexpr (std::is_same_v<T, SomeDerived>) { if constexpr (std::is_same_v<T, SomeDerived>) {
return Expr<T>{Constant<T>{array.derivedTypeSpec(), return Expr<T>{Constant<T>{array.derivedTypeSpec(),
std::move(elements_), std::vector<std::int64_t>{n}}}; std::move(elements_), std::vector<std::int64_t>{n}}};
} else if constexpr (T::category == TypeCategory::Character) {
auto length{Fold(context_, common::Clone(array.LEN()))};
if (std::optional<std::int64_t> lengthValue{ToInt64(length)}) {
return Expr<T>{Constant<T>{*lengthValue, std::move(elements_),
std::vector<std::int64_t>{n}}};
}
} else { } else {
return Expr<T>{ return Expr<T>{
Constant<T>{std::move(elements_), std::vector<std::int64_t>{n}}}; Constant<T>{std::move(elements_), std::vector<std::int64_t>{n}}};
} }
} else {
return Expr<T>{std::move(array)};
} }
return Expr<T>{std::move(array)};
} }
private: private:
bool FoldArray(const CopyableIndirection<Expr<T>> &expr) { bool FoldArray(const CopyableIndirection<Expr<T>> &expr) {
Expr<T> folded{Fold(context_, Expr<T>{*expr})}; Expr<T> folded{Fold(context_, common::Clone(*expr))};
if (auto *c{UnwrapExpr<Constant<T>>(folded)}) { if (auto *c{UnwrapExpr<Constant<T>>(folded)}) {
// Copy elements in Fortran array element order // Copy elements in Fortran array element order
std::vector<std::int64_t> shape{c->shape()}; std::vector<std::int64_t> shape{c->shape()};

View File

@ -212,7 +212,7 @@ Expr<TO> ConvertToType(Expr<Type<FROMCAT, FROMKIND>> &&x) {
template<typename TO> Expr<TO> ConvertToType(BOZLiteralConstant &&x) { template<typename TO> Expr<TO> ConvertToType(BOZLiteralConstant &&x) {
static_assert(IsSpecificIntrinsicType<TO>); static_assert(IsSpecificIntrinsicType<TO>);
using Value = typename Constant<TO>::Value; using Value = typename Constant<TO>::ScalarValue;
if constexpr (TO::category == TypeCategory::Integer) { if constexpr (TO::category == TypeCategory::Integer) {
return Expr<TO>{Constant<TO>{Value::ConvertUnsigned(std::move(x)).value}}; return Expr<TO>{Constant<TO>{Value::ConvertUnsigned(std::move(x)).value}};
} else { } else {

View File

@ -336,15 +336,18 @@ template<typename CONST> using TypeOf = typename TypeOfHelper<CONST>::type;
#define FOR_EACH_LOGICAL_KIND(PREFIX) \ #define FOR_EACH_LOGICAL_KIND(PREFIX) \
EXPAND_FOR_EACH_LOGICAL_KIND(FOR_EACH_LOGICAL_KIND_HELP, PREFIX) EXPAND_FOR_EACH_LOGICAL_KIND(FOR_EACH_LOGICAL_KIND_HELP, PREFIX)
#define FOR_EACH_INTRINSIC_KIND(PREFIX) \ #define FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX) \
FOR_EACH_INTEGER_KIND(PREFIX) \ FOR_EACH_INTEGER_KIND(PREFIX) \
FOR_EACH_REAL_KIND(PREFIX) \ FOR_EACH_REAL_KIND(PREFIX) \
FOR_EACH_COMPLEX_KIND(PREFIX) \ FOR_EACH_COMPLEX_KIND(PREFIX) \
FOR_EACH_CHARACTER_KIND(PREFIX) \
FOR_EACH_LOGICAL_KIND(PREFIX) FOR_EACH_LOGICAL_KIND(PREFIX)
#define FOR_EACH_INTRINSIC_KIND(PREFIX) \
FOR_EACH_LENGTHLESS_INTRINSIC_KIND(PREFIX) \
FOR_EACH_CHARACTER_KIND(PREFIX)
#define FOR_EACH_SPECIFIC_TYPE(PREFIX) \ #define FOR_EACH_SPECIFIC_TYPE(PREFIX) \
FOR_EACH_INTRINSIC_KIND(PREFIX) \ FOR_EACH_INTRINSIC_KIND(PREFIX) \
PREFIX<SomeDerived>; PREFIX<SomeDerived>;
#define FOR_EACH_CATEGORY_TYPE(PREFIX) \ #define FOR_EACH_CATEGORY_TYPE(PREFIX) \
PREFIX<SomeInteger>; \ PREFIX<SomeInteger>; \
PREFIX<SomeReal>; \ PREFIX<SomeReal>; \