From 286d7a21593f48ef72d4205036017d326281e3b8 Mon Sep 17 00:00:00 2001 From: peter klausler Date: Thu, 18 Jun 2020 14:37:59 -0700 Subject: [PATCH] [flang] DATA statement processing (part 2/4): Initial images Summary: Defines a representation for the initialized memory image of a variable. This image is populated by DATA statement processing as designator elements are put into correspondence with values, then converted into an initializer in the symbol table so that lowering can pass the initial image to the code generator. Reviewers: tskeith, PeteSteinfeld, sscalpone, jdoerfert, DavidTruby Reviewed By: tskeith Subscribers: mgorny, llvm-commits, flang-commits Tags: #flang, #llvm Differential Revision: https://reviews.llvm.org/D82131 --- flang/include/flang/Evaluate/initial-image.h | 85 +++++++++++++ flang/lib/Evaluate/CMakeLists.txt | 1 + flang/lib/Evaluate/initial-image.cpp | 183 +++++++++++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 flang/include/flang/Evaluate/initial-image.h create mode 100644 flang/lib/Evaluate/initial-image.cpp diff --git a/flang/include/flang/Evaluate/initial-image.h b/flang/include/flang/Evaluate/initial-image.h new file mode 100644 index 0000000..33c890b --- /dev/null +++ b/flang/include/flang/Evaluate/initial-image.h @@ -0,0 +1,85 @@ +//===-------include/flang/Evaluate/initial-image.h ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_EVALUATE_INITIAL_IMAGE_H_ +#define FORTRAN_EVALUATE_INITIAL_IMAGE_H_ + +// Represents the initialized storage of an object during DATA statement +// processing, including the conversion of that image to a constant +// initializer for a symbol. + +#include "expression.h" +#include +#include +#include + +namespace Fortran::evaluate { + +class InitialImage { +public: + explicit InitialImage(std::size_t bytes) : data_(bytes) {} + + std::size_t size() const { return data_.size(); } + + template bool Add(ConstantSubscript, std::size_t, const A &) { + return false; + } + template + bool Add(ConstantSubscript offset, std::size_t bytes, const Constant &x) { + CHECK(offset >= 0 && offset + bytes <= data_.size()); + auto elementBytes{x.GetType().MeasureSizeInBytes()}; + CHECK(elementBytes && bytes == x.values().size() * *elementBytes); + std::memcpy(&data_.at(offset), &x.values().at(0), bytes); + return true; + } + template + bool Add(ConstantSubscript offset, std::size_t bytes, + const Constant> &x) { + CHECK(offset >= 0 && offset + bytes <= data_.size()); + auto elements{TotalElementCount(x.shape())}; + auto elementBytes{bytes > 0 ? bytes / elements : 0}; + CHECK(elements * elementBytes == bytes); + for (auto at{x.lbounds()}; elements-- > 0; x.IncrementSubscripts(at)) { + auto scalar{x.At(at)}; // this is a std string; size() in chars + // Subtle: an initializer for a substring may have been + // expanded to the length of the entire string. + CHECK(scalar.size() * KIND == elementBytes || + (elements == 0 && scalar.size() * KIND > elementBytes)); + std::memcpy(&data_[offset], scalar.data(), elementBytes); + offset += elementBytes; + } + return true; + } + bool Add(ConstantSubscript, std::size_t, const Constant &); + template + bool Add(ConstantSubscript offset, std::size_t bytes, const Expr &x) { + return std::visit( + [&](const auto &y) { return Add(offset, bytes, y); }, x.u); + } + + void AddPointer(ConstantSubscript, const Expr &); + + // Conversions to constant initializers + std::optional> AsConstant(FoldingContext &, + const DynamicType &, const ConstantSubscripts &, + ConstantSubscript offset = 0) const; + std::optional> AsConstantDataPointer( + const DynamicType &, ConstantSubscript offset = 0) const; + const ProcedureDesignator &AsConstantProcPointer( + ConstantSubscript offset = 0) const; + + friend class AsConstantHelper; + friend class AsConstantDataPointerHelper; + +private: + std::vector data_; + std::map> pointers_; +}; + +} // namespace Fortran::evaluate +#endif // FORTRAN_EVALUATE_INITIAL_IMAGE_H_ diff --git a/flang/lib/Evaluate/CMakeLists.txt b/flang/lib/Evaluate/CMakeLists.txt index 7911b50..ddcdc80 100644 --- a/flang/lib/Evaluate/CMakeLists.txt +++ b/flang/lib/Evaluate/CMakeLists.txt @@ -16,6 +16,7 @@ add_flang_library(FortranEvaluate fold-real.cpp formatting.cpp host.cpp + initial-image.cpp integer.cpp intrinsics.cpp intrinsics-library.cpp diff --git a/flang/lib/Evaluate/initial-image.cpp b/flang/lib/Evaluate/initial-image.cpp new file mode 100644 index 0000000..a32d359 --- /dev/null +++ b/flang/lib/Evaluate/initial-image.cpp @@ -0,0 +1,183 @@ +//===-- lib/Evaluate/initial-image.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "flang/Evaluate/initial-image.h" +#include "flang/Semantics/scope.h" +#include "flang/Semantics/tools.h" + +namespace Fortran::evaluate { + +bool InitialImage::Add(ConstantSubscript offset, std::size_t bytes, + const Constant &x) { + CHECK(offset >= 0 && offset + bytes <= data_.size()); + auto elements{TotalElementCount(x.shape())}; + auto elementBytes{bytes > 0 ? bytes / elements : 0}; + CHECK(elements * elementBytes == bytes); + auto at{x.lbounds()}; + for (auto elements{TotalElementCount(x.shape())}; elements-- > 0; + x.IncrementSubscripts(at)) { + auto scalar{x.At(at)}; + // TODO: length type parameter values? + for (const auto &[symbolRef, indExpr] : scalar) { + const Symbol &component{*symbolRef}; + CHECK(component.offset() + component.size() <= elementBytes); + if (IsPointer(component)) { + AddPointer(offset + component.offset(), indExpr.value()); + } else if (!Add(offset + component.offset(), component.size(), + indExpr.value())) { + return false; + } + } + offset += elementBytes; + } + return true; +} + +void InitialImage::AddPointer( + ConstantSubscript offset, const Expr &pointer) { + pointers_.emplace(offset, pointer); +} + +// Classes used with common::SearchTypes() to (re)construct Constant<> values +// of the right type to initialize each symbol from the values that have +// been placed into its initialization image by DATA statements. +class AsConstantHelper { +public: + using Result = std::optional>; + using Types = AllTypes; + AsConstantHelper(FoldingContext &context, const DynamicType &type, + const ConstantSubscripts &extents, const InitialImage &image, + ConstantSubscript offset = 0) + : context_{context}, type_{type}, image_{image}, extents_{extents}, + offset_{offset} { + CHECK(!type.IsPolymorphic()); + } + template Result Test() { + if (T::category != type_.category()) { + return std::nullopt; + } + if constexpr (T::category != TypeCategory::Derived) { + if (T::kind != type_.kind()) { + return std::nullopt; + } + } + using Const = Constant; + using Scalar = typename Const::Element; + std::size_t elements{TotalElementCount(extents_)}; + std::vector typedValue(elements); + auto stride{type_.MeasureSizeInBytes()}; + CHECK(stride > 0); + CHECK(offset_ + elements * *stride <= image_.data_.size()); + if constexpr (T::category == TypeCategory::Derived) { + const semantics::DerivedTypeSpec &derived{type_.GetDerivedTypeSpec()}; + for (auto iter : DEREF(derived.scope())) { + const Symbol &component{*iter.second}; + bool isPointer{IsPointer(component)}; + if (component.has() || + component.has()) { + auto componentType{DynamicType::From(component)}; + CHECK(componentType); + auto at{offset_ + component.offset()}; + if (isPointer) { + for (std::size_t j{0}; j < elements; ++j, at += *stride) { + Result value{image_.AsConstantDataPointer(*componentType, at)}; + CHECK(value); + typedValue[j].emplace(component, std::move(*value)); + } + } else { + auto componentExtents{GetConstantExtents(context_, component)}; + CHECK(componentExtents); + for (std::size_t j{0}; j < elements; ++j, at += *stride) { + Result value{image_.AsConstant( + context_, *componentType, *componentExtents, at)}; + CHECK(value); + typedValue[j].emplace(component, std::move(*value)); + } + } + } + } + return AsGenericExpr( + Const{derived, std::move(typedValue), std::move(extents_)}); + } else if constexpr (T::category == TypeCategory::Character) { + auto length{static_cast(*stride) / T::kind}; + for (std::size_t j{0}; j < elements; ++j) { + using Char = typename Scalar::value_type; + const Char *data{reinterpret_cast( + &image_.data_[offset_ + j * *stride])}; + typedValue[j].assign(data, length); + } + return AsGenericExpr( + Const{length, std::move(typedValue), std::move(extents_)}); + } else { + // Lengthless intrinsic type + CHECK(sizeof(Scalar) <= *stride); + for (std::size_t j{0}; j < elements; ++j) { + std::memcpy(&typedValue[j], &image_.data_[offset_ + j * *stride], + sizeof(Scalar)); + } + return AsGenericExpr(Const{std::move(typedValue), std::move(extents_)}); + } + } + +private: + FoldingContext &context_; + const DynamicType &type_; + const InitialImage &image_; + ConstantSubscripts extents_; // a copy + ConstantSubscript offset_; +}; + +std::optional> InitialImage::AsConstant(FoldingContext &context, + const DynamicType &type, const ConstantSubscripts &extents, + ConstantSubscript offset) const { + return common::SearchTypes( + AsConstantHelper{context, type, extents, *this, offset}); +} + +class AsConstantDataPointerHelper { +public: + using Result = std::optional>; + using Types = AllTypes; + AsConstantDataPointerHelper(const DynamicType &type, + const InitialImage &image, ConstantSubscript offset = 0) + : type_{type}, image_{image}, offset_{offset} {} + template Result Test() { + if (T::category != type_.category()) { + return std::nullopt; + } + if constexpr (T::category != TypeCategory::Derived) { + if (T::kind != type_.kind()) { + return std::nullopt; + } + } + auto iter{image_.pointers_.find(offset_)}; + if (iter == image_.pointers_.end()) { + return AsGenericExpr(NullPointer{}); + } + return iter->second; + } + +private: + const DynamicType &type_; + const InitialImage &image_; + ConstantSubscript offset_; +}; + +std::optional> InitialImage::AsConstantDataPointer( + const DynamicType &type, ConstantSubscript offset) const { + return common::SearchTypes(AsConstantDataPointerHelper{type, *this, offset}); +} + +const ProcedureDesignator &InitialImage::AsConstantProcPointer( + ConstantSubscript offset) const { + auto iter{pointers_.find(0)}; + CHECK(iter != pointers_.end()); + return DEREF(std::get_if(&iter->second.u)); +} + +} // namespace Fortran::evaluate -- 2.7.4