From fef7fcd45f1b8f0af067c853a5387bea5128f3cc Mon Sep 17 00:00:00 2001 From: peter klausler Date: Fri, 1 Feb 2019 13:37:49 -0800 Subject: [PATCH] [flang] More value semantics in Constant<> and GetScalarConstantValue Original-commit: flang-compiler/f18@c7acce46854f815e2a1c53d385d8c39bae23098e Reviewed-on: https://github.com/flang-compiler/f18/pull/271 Tree-same-pre-rewrite: false --- flang/lib/evaluate/constant.cc | 14 ++++++++++++++ flang/lib/evaluate/constant.h | 42 ++++++++++++++++++---------------------- flang/lib/evaluate/expression.cc | 2 +- flang/lib/evaluate/fold.cc | 18 ++++++++--------- flang/lib/evaluate/fold.h | 28 +++++++++++++++++---------- flang/lib/evaluate/type.h | 8 +++++--- flang/test/evaluate/folding.cc | 6 +++--- 7 files changed, 69 insertions(+), 49 deletions(-) diff --git a/flang/lib/evaluate/constant.cc b/flang/lib/evaluate/constant.cc index 2cde28b..3350649 100644 --- a/flang/lib/evaluate/constant.cc +++ b/flang/lib/evaluate/constant.cc @@ -65,6 +65,20 @@ std::ostream &Constant::AsFortran(std::ostream &o) const { return o; } +template +auto Constant::At(const std::vector &index) const -> Value { + CHECK(index.size() == static_cast(Rank())); + std::int64_t stride{1}, offset{0}; + int dim{0}; + for (std::int64_t j : index) { + std::int64_t bound{shape_[dim++]}; + CHECK(j >= 1 && j <= bound); + offset += stride * (j - 1); + stride *= bound; + } + return values_.at(offset); +} + template Constant Constant::SHAPE() const { using IntType = Scalar; std::vector result; diff --git a/flang/lib/evaluate/constant.h b/flang/lib/evaluate/constant.h index 7af13f9..5c73f96 100644 --- a/flang/lib/evaluate/constant.h +++ b/flang/lib/evaluate/constant.h @@ -19,6 +19,7 @@ #include namespace Fortran::evaluate { + // Wraps a constant value in a class templated by its resolved type. // N.B. Generic constants are represented by generic expressions // (like Expr & Expr) wrapping the appropriate @@ -43,35 +44,17 @@ public: 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(); } const std::vector &shape() const { return shape_; } - std::int64_t LEN() const { - if constexpr (T::category != TypeCategory::Character) { - common::die("LEN() of non-character Constant"); - } else if (values_.empty()) { - return 0; - } else { - return static_cast(values_[0].size()); - } - } - const Value &operator*() const { + Value operator*() const { CHECK(values_.size() == 1); return values_.at(0); } - const Value &At(const std::vector &index) { - CHECK(index.size() == static_cast(Rank())); - std::int64_t stride{1}, offset{0}; - int dim{0}; - for (std::int64_t j : index) { - std::int64_t bound{shape_[dim++]}; - CHECK(j >= 1 && j <= bound); - offset += stride * (j - 1); - stride *= bound; - } - return values_.at(offset); - } + // Apply 1-based subscripts + Value At(const std::vector &) const; Constant SHAPE() const; std::ostream &AsFortran(std::ostream &) const; @@ -79,9 +62,22 @@ public: private: std::vector values_; std::vector shape_; - // TODO pmk: make CHARACTER values contiguous + // TODO pmk: make CHARACTER values contiguous (they're strings now) }; +// Would prefer to have this be a member function of Constant enabled +// only for CHARACTER, but std::enable_if<> isn't effective in that context. +template +std::int64_t ConstantLEN( + const Constant> &c) { + if (c.empty()) { + return 0; + } else { + std::vector ones(c.Rank(), 1); + return c.At(ones).size(); + } +} + FOR_EACH_INTRINSIC_KIND(extern template class Constant) } #endif // FORTRAN_EVALUATE_CONSTANT_H_ diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index 5123bca..114250c 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -150,7 +150,7 @@ Expr Expr>::LEN() const { return std::visit( common::visitors{ [](const Constant &c) { - return AsExpr(Constant{c.LEN()}); + return AsExpr(Constant{ConstantLEN(c)}); }, [](const ArrayConstructor &a) { return a.LEN(); }, [](const Parentheses &x) { return x.left().LEN(); }, diff --git a/flang/lib/evaluate/fold.cc b/flang/lib/evaluate/fold.cc index 3f6852f..d24e07e 100644 --- a/flang/lib/evaluate/fold.cc +++ b/flang/lib/evaluate/fold.cc @@ -191,7 +191,7 @@ Expr FoldOperation(FoldingContext &context, Designator &&designator) { if constexpr (T::category == TypeCategory::Character) { if (auto *substring{common::Unwrap(designator.u)}) { if (std::optional> folded{substring->Fold(context)}) { - if (const auto *value{GetScalarConstantValue(*folded)}) { + if (auto value{GetScalarConstantValue(*folded)}) { return Expr{*value}; } } @@ -304,7 +304,7 @@ Expr FoldOperation(FoldingContext &context, ArrayConstructor &&array) { return result; } -// TODO this specializations is a placeholder: don't fold array constructors +// TODO this specialization is a placeholder: don't fold array constructors // of derived type for now Expr FoldOperation( FoldingContext &context, ArrayConstructor &&array) { @@ -358,7 +358,7 @@ Expr FoldOperation( kindExpr = Fold(context, std::move(kindExpr)); using Operand = ResultType; char buffer[64]; - if (const auto *value{GetScalarConstantValue(kindExpr)}) { + if (auto value{GetScalarConstantValue(kindExpr)}) { if constexpr (TO::category == TypeCategory::Integer) { if constexpr (Operand::category == TypeCategory::Integer) { auto converted{Scalar::ConvertSigned(*value)}; @@ -417,7 +417,7 @@ template Expr FoldOperation(FoldingContext &context, Parentheses &&x) { auto &operand{x.left()}; operand = Fold(context, std::move(operand)); - if (const auto *value{GetScalarConstantValue(operand)}) { + if (auto value{GetScalarConstantValue(operand)}) { // Preserve parentheses, even around constants. return Expr{Parentheses{Expr{Constant{*value}}}}; } @@ -428,7 +428,7 @@ template Expr FoldOperation(FoldingContext &context, Negate &&x) { auto &operand{x.left()}; operand = Fold(context, std::move(operand)); - if (const auto *value{GetScalarConstantValue(operand)}) { + if (auto value{GetScalarConstantValue(operand)}) { if constexpr (T::category == TypeCategory::Integer) { auto negated{value->Negate()}; if (negated.overflow) { @@ -451,7 +451,7 @@ Expr> FoldOperation( using Part = Type; auto &operand{x.left()}; operand = Fold(context, std::move(operand)); - if (const auto *value{GetScalarConstantValue(operand)}) { + if (auto value{GetScalarConstantValue(operand)}) { if (x.isImaginaryPart) { return Expr{Constant{value->AIMAG()}}; } else { @@ -467,7 +467,7 @@ Expr> FoldOperation( using Ty = Type; auto &operand{x.left()}; operand = Fold(context, std::move(operand)); - if (const auto *value{GetScalarConstantValue(operand)}) { + if (auto value{GetScalarConstantValue(operand)}) { return Expr{Constant{value->IsTrue()}}; } return Expr{x}; @@ -480,8 +480,8 @@ std::optional, Scalar>> FoldOperands( FoldingContext &context, Expr &x, Expr &y) { x = Fold(context, std::move(x)); // use of std::move() on &x is intentional y = Fold(context, std::move(y)); - if (const auto *xvalue{GetScalarConstantValue(x)}) { - if (const auto *yvalue{GetScalarConstantValue(y)}) { + if (auto xvalue{GetScalarConstantValue(x)}) { + if (auto yvalue{GetScalarConstantValue(y)}) { return {std::make_pair(*xvalue, *yvalue)}; } } diff --git a/flang/lib/evaluate/fold.h b/flang/lib/evaluate/fold.h index 6f99bab..469091d 100644 --- a/flang/lib/evaluate/fold.h +++ b/flang/lib/evaluate/fold.h @@ -50,35 +50,44 @@ std::optional> Fold( // GetScalarConstantValue() isolates the known constant value of // an expression, if it has one. The value can be parenthesized. template -const Scalar *GetScalarConstantValue(const Expr &expr) { +std::optional> GetScalarConstantValue(const Expr &expr) { if (const auto *c{UnwrapExpr>(expr)}) { if (c->size() == 1) { - return &**c; + return **c; } else { - return nullptr; + return std::nullopt; } } else if (const auto *parens{UnwrapExpr>(expr)}) { return GetScalarConstantValue(parens->left()); } else { - return nullptr; + return std::nullopt; } } template -const Scalar *GetScalarConstantValue( +std::optional> GetScalarConstantValue( const Expr> &expr) { if (const auto *kindExpr{UnwrapExpr>(expr)}) { return GetScalarConstantValue(*kindExpr); } - return nullptr; + return std::nullopt; } template -const Scalar *GetScalarConstantValue(const Expr &expr) { +std::optional> GetScalarConstantValue(const Expr &expr) { if (const auto *kindExpr{UnwrapExpr>(expr)}) { return GetScalarConstantValue(*kindExpr); } - return nullptr; + return std::nullopt; +} + +template +std::optional> GetScalarConstantValue(const std::optional &expr) { + if (expr.has_value()) { + return GetScalarConstantValue(*expr); + } else { + return std::nullopt; + } } // Predicate: true when an expression is a constant expression (in the @@ -92,8 +101,7 @@ bool IsConstantExpr(const Expr &); template std::optional ToInt64( const Expr> &expr) { - using Ty = Type; - if (const Scalar *scalar{GetScalarConstantValue(expr)}) { + if (auto scalar{GetScalarConstantValue(expr)}) { return {scalar->ToInt64()}; } else { return std::nullopt; diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 5f3fb30a..1fc5a6a 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -53,9 +53,11 @@ using LogicalResult = Type; using LargestReal = Type; // DynamicType is suitable for use as the result type for -// GetType() functions and member functions. It does *not* -// hold CHARACTER length type parameter expressions -- those -// must be derived via LEN() member functions or packaged +// GetType() functions and member functions; consequently, +// it must be capable of being used in a constexpr context. +// So it does *not* hold anything requiring a destructor, +// such as a CHARACTER length type parameter expression. +// Those must be derived via LEN() member functions or packaged // elsewhere (e.g. as in ArrayConstructor). struct DynamicType { bool operator==(const DynamicType &) const; diff --git a/flang/test/evaluate/folding.cc b/flang/test/evaluate/folding.cc index 7c15d53..e0808d1 100644 --- a/flang/test/evaluate/folding.cc +++ b/flang/test/evaluate/folding.cc @@ -32,9 +32,9 @@ struct TestGetScalarConstantValue { Expr exprFullyTyped{Constant{Scalar{}}}; Expr> exprSomeKind{exprFullyTyped}; Expr exprSomeType{exprSomeKind}; - TEST(GetScalarConstantValue(exprFullyTyped) != nullptr); - TEST(GetScalarConstantValue(exprSomeKind) != nullptr); - TEST(GetScalarConstantValue(exprSomeType) != nullptr); + TEST(GetScalarConstantValue(exprFullyTyped).has_value()); + TEST(GetScalarConstantValue(exprSomeKind).has_value()); + TEST(GetScalarConstantValue(exprSomeType).has_value()); } }; -- 2.7.4