From 650b32ebfec83e29a281cb4654b8531fc6e8760f Mon Sep 17 00:00:00 2001 From: peter klausler Date: Mon, 28 Jan 2019 14:38:17 -0800 Subject: [PATCH] [flang] support Constant arrays Original-commit: flang-compiler/f18@a92d8a404fc44d593890d79d59cf62630399d639 Reviewed-on: https://github.com/flang-compiler/f18/pull/271 Tree-same-pre-rewrite: false --- flang/lib/evaluate/CMakeLists.txt | 1 + flang/lib/evaluate/constant.cc | 66 +++++++++++++++++++++++++++++ flang/lib/evaluate/constant.h | 87 +++++++++++++++++++++++++++++++++++++++ flang/lib/evaluate/expression.cc | 26 +----------- flang/lib/evaluate/expression.h | 1 + flang/lib/evaluate/fold.h | 7 +++- flang/lib/evaluate/tools.h | 1 + flang/lib/evaluate/type.h | 28 +------------ flang/lib/evaluate/variable.h | 1 + flang/lib/semantics/expression.cc | 3 +- 10 files changed, 169 insertions(+), 52 deletions(-) create mode 100644 flang/lib/evaluate/constant.cc create mode 100644 flang/lib/evaluate/constant.h diff --git a/flang/lib/evaluate/CMakeLists.txt b/flang/lib/evaluate/CMakeLists.txt index ce53274..3c0e4e1 100644 --- a/flang/lib/evaluate/CMakeLists.txt +++ b/flang/lib/evaluate/CMakeLists.txt @@ -16,6 +16,7 @@ add_library(FortranEvaluate call.cc common.cc complex.cc + constant.cc decimal.cc expression.cc fold.cc diff --git a/flang/lib/evaluate/constant.cc b/flang/lib/evaluate/constant.cc new file mode 100644 index 0000000..6a8ec01 --- /dev/null +++ b/flang/lib/evaluate/constant.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2019, 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. + +#include "constant.h" +#include "type.h" +#include "../parser/characters.h" + +namespace Fortran::evaluate { +template +std::ostream &Constant::AsFortran(std::ostream &o) const { + if (Rank() > 0) { + o << "reshape([" << GetType().AsFortran() << "::"; + } + for (const auto &value : values_) { + 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 (value.IsTrue()) { + o << ".true."; + } else { + o << ".false."; + } + o << '_' << Result::kind; + } else { + value.u.AsFortran(o); + } + } + if (Rank() > 0) { + o << "],shape="; + char ch{'['}; + for (auto dim : shape_) { + o << ch << dim; + ch = ','; + } + o << "])"; + } + return o; +} + +template Constant Constant::SHAPE() const { + using IntType = Scalar; + std::vector result; + for (std::int64_t dim : shape_) { + result.emplace_back(dim); + } + return {std::move(result), std::vector{Rank()}}; +} + +FOR_EACH_INTRINSIC_KIND(template class Constant) +} diff --git a/flang/lib/evaluate/constant.h b/flang/lib/evaluate/constant.h new file mode 100644 index 0000000..7af13f9 --- /dev/null +++ b/flang/lib/evaluate/constant.h @@ -0,0 +1,87 @@ +// Copyright (c) 2019, 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_EVALUATE_CONSTANT_H_ +#define FORTRAN_EVALUATE_CONSTANT_H_ + +#include "type.h" +#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 +// instantiations of Constant. +template class Constant { + static_assert(std::is_same_v || IsSpecificIntrinsicType); + +public: + using Result = T; + using Value = Scalar; + + CLASS_BOILERPLATE(Constant) + template Constant(const A &x) : values_{x} {} + template + Constant(std::enable_if_t, A> &&x) + : values_{std::move(x)} {} + Constant(std::vector &&x, std::vector &&s) + : values_(std::move(x)), shape_(std::move(s)) {} + + constexpr DynamicType GetType() const { return Result::GetType(); } + int Rank() const { return static_cast(shape_.size()); } + bool operator==(const Constant &that) const { + return shape_ == that.shape_ && values_ == that.values_; + } + 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 { + 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); + } + + Constant SHAPE() const; + std::ostream &AsFortran(std::ostream &) const; + +private: + std::vector values_; + std::vector shape_; + // TODO pmk: make CHARACTER values contiguous +}; + +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 f4e4ff9..3b0519f 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +// Copyright (c) 2018-2019, 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. @@ -18,7 +18,6 @@ #include "tools.h" #include "variable.h" #include "../common/idioms.h" -#include "../parser/characters.h" #include "../parser/message.h" #include #include @@ -84,27 +83,6 @@ std::ostream &LogicalOperation::Infix(std::ostream &o) const { } template -std::ostream &Constant::AsFortran(std::ostream &o) const { - if constexpr (T::category == TypeCategory::Integer) { - return o << value.SignedDecimal() << '_' << T::kind; - } else if constexpr (T::category == TypeCategory::Real || - T::category == TypeCategory::Complex) { - return value.AsFortran(o, T::kind); - } else if constexpr (T::category == TypeCategory::Character) { - return o << T::kind << '_' << parser::QuoteCharacterLiteral(value); - } else if constexpr (T::category == TypeCategory::Logical) { - if (value.IsTrue()) { - o << ".true."; - } else { - o << ".false."; - } - return o << '_' << Result::kind; - } else { - return value.u.AsFortran(o); - } -} - -template std::ostream &Emit(std::ostream &o, const CopyableIndirection> &expr) { return expr->AsFortran(o); } @@ -172,7 +150,7 @@ Expr Expr>::LEN() const { return std::visit( common::visitors{ [](const Constant &c) { - return AsExpr(Constant{c.value.size()}); + return AsExpr(Constant{c.LEN()}); }, [](const ArrayConstructor &a) { return a.LEN(); }, [](const Parentheses &x) { return x.left().LEN(); }, diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index a4071ac..1e2e15f 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -23,6 +23,7 @@ // for equality. #include "common.h" +#include "constant.h" #include "type.h" #include "variable.h" #include "../lib/common/fortran.h" diff --git a/flang/lib/evaluate/fold.h b/flang/lib/evaluate/fold.h index 32155f6..6f99bab 100644 --- a/flang/lib/evaluate/fold.h +++ b/flang/lib/evaluate/fold.h @@ -19,6 +19,7 @@ // evaluation. #include "common.h" +#include "constant.h" #include "expression.h" #include "tools.h" #include "type.h" @@ -51,7 +52,11 @@ std::optional> Fold( template const Scalar *GetScalarConstantValue(const Expr &expr) { if (const auto *c{UnwrapExpr>(expr)}) { - return &c->value; + if (c->size() == 1) { + return &**c; + } else { + return nullptr; + } } else if (const auto *parens{UnwrapExpr>(expr)}) { return GetScalarConstantValue(parens->left()); } else { diff --git a/flang/lib/evaluate/tools.h b/flang/lib/evaluate/tools.h index 67cde04..6b13ddd 100644 --- a/flang/lib/evaluate/tools.h +++ b/flang/lib/evaluate/tools.h @@ -15,6 +15,7 @@ #ifndef FORTRAN_EVALUATE_TOOLS_H_ #define FORTRAN_EVALUATE_TOOLS_H_ +#include "constant.h" #include "expression.h" #include "../common/idioms.h" #include "../common/unwrap.h" diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 678618a..5f3fb30a 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +// Copyright (c) 2018-2019, 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. @@ -232,7 +232,7 @@ using AllIntrinsicTypes = common::CombineTuples; using LengthlessIntrinsicTypes = common::CombineTuples; -// Predicate: does a type represent a specific intrinsic type? +// Predicates: does a type represent a specific intrinsic type? template constexpr bool IsSpecificIntrinsicType{common::HasMember}; @@ -352,29 +352,5 @@ struct SomeType {}; #define FOR_EACH_TYPE_AND_KIND(PREFIX) \ FOR_EACH_INTRINSIC_KIND(PREFIX) \ FOR_EACH_CATEGORY_TYPE(PREFIX) - -// Wraps a constant scalar value of a specific intrinsic type -// in a class with its resolved type. -// N.B. Array constants are represented as array constructors -// and derived type constants are structure constructors; generic -// constants are generic expressions wrapping these constants. -template struct Constant { - static_assert(IsSpecificIntrinsicType); - using Result = T; - using Value = Scalar; - - CLASS_BOILERPLATE(Constant) - template Constant(const A &x) : value{x} {} - template - Constant(std::enable_if_t, A> &&x) - : value(std::move(x)) {} - - constexpr DynamicType GetType() const { return Result::GetType(); } - int Rank() const { return 0; } - bool operator==(const Constant &that) const { return value == that.value; } - std::ostream &AsFortran(std::ostream &) const; - - Value value; -}; } #endif // FORTRAN_EVALUATE_TYPE_H_ diff --git a/flang/lib/evaluate/variable.h b/flang/lib/evaluate/variable.h index 1da5df0..c74bf41 100644 --- a/flang/lib/evaluate/variable.h +++ b/flang/lib/evaluate/variable.h @@ -25,6 +25,7 @@ #include "call.h" #include "common.h" +#include "constant.h" #include "static-data.h" #include "type.h" #include "../common/idioms.h" diff --git a/flang/lib/semantics/expression.cc b/flang/lib/semantics/expression.cc index f43be6e..7a36e67 100644 --- a/flang/lib/semantics/expression.cc +++ b/flang/lib/semantics/expression.cc @@ -890,10 +890,11 @@ static MaybeExpr AnalyzeExpr(ExpressionAnalysisContext &context, using Result = ResultType; auto *cp{std::get_if>(&ckExpr.u)}; CHECK(cp != nullptr); // the parent was parsed as a constant string + CHECK(cp->size() == 1); StaticDataObject::Pointer staticData{StaticDataObject::Create()}; staticData->set_alignment(Result::kind) .set_itemBytes(Result::kind) - .Push(cp->value); + .Push(**cp); Substring substring{std::move(staticData), std::move(lower.value()), std::move(upper.value())}; return AsGenericExpr(Expr{ -- 2.7.4