llvm/flang/lib/evaluate/constant.cc
jeanPerier 953d93dbe8 [flang] Merge pull request flang-compiler/f18#544 from flang-compiler/jpr-reshape-only-folding
RESHAPE without shared runtime/front-end descriptor API

Original-commit: flang-compiler/f18@24856b8238
Reviewed-on: https://github.com/flang-compiler/f18/pull/544

Due to a conflicting rebase during the linearizing of flang-compiler/f18, this commit squashes a number of other commits:

flang-compiler/f18@2ec1d85d39 Implement RESHAPE folding on Constant<T> only
flang-compiler/f18@5394630539 Enable RESHAPE folding tests
flang-compiler/f18@83b2b86253 Answer review comment + Add a common path for intrsinic function folding before specializing the folding per type. + Make reshape folding return an "invalid" intrinsic after errors are met so that warnings do not get re-generated. + Misc style changes
flang-compiler/f18@2e5c29f280 add missing file to previous commit...
flang-compiler/f18@9bd5ad9875 Document issue #518 workaround
flang-compiler/f18@a4f8f51831 Go back to clang-format version 7.01
flang-compiler/f18@e871e58a52 answer comment regarding naming and interface
flang-compiler/f18@145c7c1ece Merge branch 'master' into jpr-reshape-only-folding Too many logical conflicts to simply rebase.
2019-07-23 05:36:17 -07:00

317 lines
10 KiB
C++

// 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 "expression.h"
#include "shape.h"
#include "type.h"
#include <string>
namespace Fortran::evaluate {
std::size_t TotalElementCount(const ConstantSubscripts &shape) {
std::size_t size{1};
for (auto dim : shape) {
CHECK(dim >= 0);
size *= dim;
}
return size;
}
ConstantBounds::ConstantBounds(const ConstantSubscripts &shape)
: shape_(shape), lbounds_(shape_.size(), 1) {}
ConstantBounds::ConstantBounds(ConstantSubscripts &&shape)
: shape_(std::move(shape)), lbounds_(shape_.size(), 1) {}
ConstantBounds::~ConstantBounds() = default;
void ConstantBounds::set_lbounds(ConstantSubscripts &&lb) {
CHECK(lb.size() == shape_.size());
lbounds_ = std::move(lb);
}
Constant<SubscriptInteger> ConstantBounds::SHAPE() const {
return AsConstantShape(shape_);
}
ConstantSubscript ConstantBounds::SubscriptsToOffset(
const ConstantSubscripts &index) const {
CHECK(GetRank(index) == GetRank(shape_));
ConstantSubscript stride{1}, offset{0};
int dim{0};
for (auto j : index) {
auto lb{lbounds_[dim]};
auto extent{shape_[dim++]};
CHECK(j >= lb && j < lb + extent);
offset += stride * (j - lb);
stride *= extent;
}
return offset;
}
bool ConstantBounds::IncrementSubscripts(
ConstantSubscripts &indices, const std::vector<int> *dimOrder) const {
int rank{GetRank(shape_)};
CHECK(GetRank(indices) == rank);
CHECK(!dimOrder || static_cast<int>(dimOrder->size()) == rank);
for (int j{0}; j < rank; ++j) {
ConstantSubscript k{dimOrder ? (*dimOrder)[j] : j};
auto lb{lbounds_[k]};
CHECK(indices[k] >= lb);
if (++indices[k] < lb + shape_[k]) {
return true;
} else {
CHECK(indices[k] == lb + shape_[k]);
indices[k] = lb;
}
}
return false; // all done
}
std::optional<std::vector<int>> ValidateDimensionOrder(
int rank, const std::vector<int> &order) {
std::vector<int> dimOrder(rank);
if (static_cast<int>(order.size()) == rank) {
std::bitset<common::maxRank> seenDimensions;
for (int j{0}; j < rank; ++j) {
int dim{order[j]};
if (dim < 1 || dim > rank || seenDimensions.test(dim - 1)) {
return std::nullopt;
}
dimOrder[dim - 1] = j;
seenDimensions.set(dim - 1);
}
return dimOrder;
} else {
return std::nullopt;
}
}
bool IsValidShape(const ConstantSubscripts &shape) {
for (ConstantSubscript extent : shape) {
if (extent < 0) {
return false;
}
}
return shape.size() <= common::maxRank;
}
template<typename RESULT, typename ELEMENT>
ConstantBase<RESULT, ELEMENT>::ConstantBase(
std::vector<Element> &&x, ConstantSubscripts &&sh, Result res)
: ConstantBounds(std::move(sh)), result_{res}, values_(std::move(x)) {
CHECK(size() == TotalElementCount(shape()));
}
template<typename RESULT, typename ELEMENT>
ConstantBase<RESULT, ELEMENT>::~ConstantBase() {}
template<typename RESULT, typename ELEMENT>
bool ConstantBase<RESULT, ELEMENT>::operator==(const ConstantBase &that) const {
return shape() == that.shape() && values_ == that.values_;
}
template<typename RESULT, typename ELEMENT>
auto ConstantBase<RESULT, ELEMENT>::Reshape(
const ConstantSubscripts &dims) const -> std::vector<Element> {
std::size_t n{TotalElementCount(dims)};
CHECK(!empty() || n == 0);
std::vector<Element> elements;
auto iter{values().cbegin()};
while (n-- > 0) {
elements.push_back(*iter);
if (++iter == values().cend()) {
iter = values().cbegin();
}
}
return elements;
}
template<typename RESULT, typename ELEMENT>
std::size_t ConstantBase<RESULT, ELEMENT>::CopyFrom(
const ConstantBase<RESULT, ELEMENT> &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder) {
std::size_t copied{0};
ConstantSubscripts sourceSubscripts{source.lbounds()};
while (copied < count) {
values_.at(SubscriptsToOffset(resultSubscripts)) =
source.values_.at(source.SubscriptsToOffset(sourceSubscripts));
copied++;
source.IncrementSubscripts(sourceSubscripts);
IncrementSubscripts(resultSubscripts, dimOrder);
}
return copied;
}
template<typename T>
auto Constant<T>::At(const ConstantSubscripts &index) const -> Element {
return Base::values_.at(Base::SubscriptsToOffset(index));
}
template<typename T>
auto Constant<T>::Reshape(ConstantSubscripts &&dims) const -> Constant {
return {Base::Reshape(dims), std::move(dims)};
}
template<typename T>
std::size_t Constant<T>::CopyFrom(const Constant<T> &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder) {
return Base::CopyFrom(source, count, resultSubscripts, dimOrder);
}
// Constant<Type<TypeCategory::Character, KIND> specializations
template<int KIND>
Constant<Type<TypeCategory::Character, KIND>>::Constant(
const Scalar<Result> &str)
: values_{str}, length_{static_cast<ConstantSubscript>(values_.size())} {}
template<int KIND>
Constant<Type<TypeCategory::Character, KIND>>::Constant(Scalar<Result> &&str)
: values_{std::move(str)}, length_{static_cast<ConstantSubscript>(
values_.size())} {}
template<int KIND>
Constant<Type<TypeCategory::Character, KIND>>::Constant(ConstantSubscript len,
std::vector<Scalar<Result>> &&strings, ConstantSubscripts &&sh)
: ConstantBounds(std::move(sh)), length_{len} {
CHECK(strings.size() == TotalElementCount(shape()));
values_.assign(strings.size() * length_,
static_cast<typename Scalar<Result>::value_type>(' '));
ConstantSubscript at{0};
for (const auto &str : strings) {
auto strLen{static_cast<ConstantSubscript>(str.size())};
if (strLen > length_) {
values_.replace(at, length_, str.substr(0, length_));
} else {
values_.replace(at, strLen, str);
}
at += length_;
}
CHECK(at == static_cast<ConstantSubscript>(values_.size()));
}
template<int KIND> Constant<Type<TypeCategory::Character, KIND>>::~Constant() {}
template<int KIND>
bool Constant<Type<TypeCategory::Character, KIND>>::empty() const {
return size() == 0;
}
template<int KIND>
std::size_t Constant<Type<TypeCategory::Character, KIND>>::size() const {
if (length_ == 0) {
return TotalElementCount(shape());
} else {
return static_cast<ConstantSubscript>(values_.size()) / length_;
}
}
template<int KIND>
auto Constant<Type<TypeCategory::Character, KIND>>::At(
const ConstantSubscripts &index) const -> Scalar<Result> {
auto offset{SubscriptsToOffset(index)};
return values_.substr(offset * length_, length_);
}
template<int KIND>
auto Constant<Type<TypeCategory::Character, KIND>>::Reshape(
ConstantSubscripts &&dims) const -> Constant<Result> {
std::size_t n{TotalElementCount(dims)};
CHECK(!empty() || n == 0);
std::vector<Element> elements;
ConstantSubscript at{0},
limit{static_cast<ConstantSubscript>(values_.size())};
while (n-- > 0) {
elements.push_back(values_.substr(at, length_));
at += length_;
if (at == limit) { // subtle: at > limit somehow? substr() will catch it
at = 0;
}
}
return {length_, std::move(elements), std::move(dims)};
}
template<int KIND>
std::size_t Constant<Type<TypeCategory::Character, KIND>>::CopyFrom(
const Constant<Type<TypeCategory::Character, KIND>> &source,
std::size_t count, ConstantSubscripts &resultSubscripts,
const std::vector<int> *dimOrder) {
CHECK(length_ == source.length_);
std::size_t copied{0};
std::size_t elementBytes{length_ * sizeof(decltype(values_[0]))};
ConstantSubscripts sourceSubscripts{source.lbounds()};
while (copied < count) {
auto *dest{&values_.at(SubscriptsToOffset(resultSubscripts) * length_)};
const auto *src{&source.values_.at(
source.SubscriptsToOffset(sourceSubscripts) * length_)};
std::memcpy(dest, src, elementBytes);
copied++;
source.IncrementSubscripts(sourceSubscripts);
IncrementSubscripts(resultSubscripts, dimOrder);
}
return copied;
}
// Constant<SomeDerived> specialization
Constant<SomeDerived>::Constant(const StructureConstructor &x)
: Base{x.values(), Result{x.derivedTypeSpec()}} {}
Constant<SomeDerived>::Constant(StructureConstructor &&x)
: Base{std::move(x.values()), Result{x.derivedTypeSpec()}} {}
Constant<SomeDerived>::Constant(const semantics::DerivedTypeSpec &spec,
std::vector<StructureConstructorValues> &&x, ConstantSubscripts &&s)
: Base{std::move(x), std::move(s), Result{spec}} {}
static std::vector<StructureConstructorValues> AcquireValues(
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, ConstantSubscripts &&shape)
: Base{AcquireValues(std::move(x)), std::move(shape), Result{spec}} {}
std::optional<StructureConstructor>
Constant<SomeDerived>::GetScalarValue() const {
if (Rank() == 0) {
return StructureConstructor{result().derivedTypeSpec(), values_.at(0)};
} else {
return std::nullopt;
}
}
StructureConstructor Constant<SomeDerived>::At(
const ConstantSubscripts &index) const {
return {result().derivedTypeSpec(), values_.at(SubscriptsToOffset(index))};
}
auto Constant<SomeDerived>::Reshape(ConstantSubscripts &&dims) const
-> Constant {
return {result().derivedTypeSpec(), Base::Reshape(dims), std::move(dims)};
}
std::size_t Constant<SomeDerived>::CopyFrom(const Constant<SomeDerived> &source,
std::size_t count, ConstantSubscripts &resultSubscripts,
const std::vector<int> *dimOrder) {
return Base::CopyFrom(source, count, resultSubscripts, dimOrder);
}
INSTANTIATE_CONSTANT_TEMPLATES
}