Skip to content

Commit

Permalink
[flang] Merge pull request flang-compiler/f18#544 from flang-compiler…
Browse files Browse the repository at this point in the history
…/jpr-reshape-only-folding

RESHAPE without shared runtime/front-end descriptor API

Original-commit: flang-compiler/f18@24856b8
Reviewed-on: flang-compiler/f18#544

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

flang-compiler/f18@2ec1d85 Implement RESHAPE folding on Constant<T> only
flang-compiler/f18@5394630 Enable RESHAPE folding tests
flang-compiler/f18@83b2b86 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@2e5c29f add missing file to previous commit...
flang-compiler/f18@9bd5ad9 Document issue #518 workaround
flang-compiler/f18@a4f8f51 Go back to clang-format version 7.01
flang-compiler/f18@e871e58 answer comment regarding naming and interface
flang-compiler/f18@145c7c1 Merge branch 'master' into jpr-reshape-only-folding Too many logical conflicts to simply rebase.
  • Loading branch information
jeanPerier committed Jul 23, 2019
1 parent 1cdcfbc commit 953d93d
Show file tree
Hide file tree
Showing 7 changed files with 789 additions and 489 deletions.
40 changes: 40 additions & 0 deletions flang/documentation/C++style.md
Expand Up @@ -13,6 +13,8 @@ is clear on usage, follow it.
follow it. [Google's](https://google.github.io/styleguide/cppguide.html)
is pretty good and comes with lots of justifications for its rules.
* Reasonable exceptions to these guidelines can be made.
* Be aware of some workarounds for known issues in older C++ compilers that should
still be able to compile f18. They are listed at the end of this document.
## In particular:
### Files
1. File names should use dashes, not underscores. C++ sources have the
Expand Down Expand Up @@ -227,6 +229,8 @@ build time; don't solve build time problems by writing programs that
produce source code when macros and templates suffice; don't write macros
when templates suffice. Templates are statically typed, checked by the
compiler, and are (or should be) visible to debuggers.


### Exceptions to these guidelines
Reasonable exceptions will be allowed; these guidelines cannot anticipate
all situations.
Expand All @@ -237,3 +241,39 @@ in a way that leads to weirdly capitalized abbreviations in names
like `Http`.
Consistency is one of many aspects in the pursuit of clarity,
but not an end in itself.

## C++ compiler bug workarounds
Below is a list of workarounds for C++ compiler bugs met with f18 that, even
if the bugs are fixed in latest C++ compiler versions, need to be applied so
that all desired tool-chains can compile f18.
### Explicitly move noncopyable local variable into optional results

The following code is legal C++ but fails to compile with the
default Ubuntu 18.04 g++ compiler (7.4.0-1ubuntu1~18.0.4.1):

```
class CantBeCopied {
public:
CantBeCopied(const CantBeCopied&) = delete;
CantBeCopied(CantBeCopied&&) = default;
CantBeCopied() {}
};
std::optional<CantBeCopied> fooNOK() {
CantBeCopied result;
return result; // Legal C++, but does not compile with Ubuntu 18.04 default g++
}
std::optional<CantBeCopied> fooOK() {
CantBeCopied result;
return {std::move(result)}; // Compiles OK everywhere
}
```
The underlying bug is actually not specific to `std::optional` but this is the most common
case in f18 where the issue may occur. The actual bug can be reproduced with any class `B`
that has a perfect forwarding constructor taking `CantBeCopied` as argument:
`template<typename CantBeCopied> B(CantBeCopied&& x) x_{std::forward<CantBeCopied>(x)} {}`.
In such scenarios, Ubuntu 18.04 g++ fails to instantiate the move constructor
and to construct the returned value as it should, instead it complains about a
missing copy constructor.

Local result variables do not need to and should not be explicitly moved into optionals
if they have a copy constructor.
3 changes: 3 additions & 0 deletions flang/lib/common/Fortran.h
Expand Up @@ -53,5 +53,8 @@ ENUM_CLASS(IoSpecKind, Access, Action, Advance, Asynchronous, Blank, Decimal,
Convert, // nonstandard
Dispose, // nonstandard
)

// Fortran arrays may have up to 15 dimensions (See Fortran 2018 section 5.4.6).
static constexpr int maxRank{15};
}
#endif // FORTRAN_COMMON_FORTRAN_H_
92 changes: 86 additions & 6 deletions flang/lib/evaluate/constant.cc
Expand Up @@ -61,22 +61,53 @@ ConstantSubscript ConstantBounds::SubscriptsToOffset(
return offset;
}

bool ConstantBounds::IncrementSubscripts(ConstantSubscripts &indices) const {
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) {
auto lb{lbounds_[j]};
CHECK(indices[j] >= lb);
if (++indices[j] < lb + shape_[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[j] == lb + shape_[j]);
indices[j] = lb;
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)
Expand Down Expand Up @@ -108,6 +139,22 @@ auto ConstantBase<RESULT, ELEMENT>::Reshape(
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));
Expand All @@ -118,6 +165,12 @@ 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(
Expand Down Expand Up @@ -190,6 +243,27 @@ auto Constant<Type<TypeCategory::Character, KIND>>::Reshape(
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()}} {}
Expand Down Expand Up @@ -233,5 +307,11 @@ auto Constant<SomeDerived>::Reshape(ConstantSubscripts &&dims) const
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
}
26 changes: 23 additions & 3 deletions flang/lib/evaluate/constant.h
Expand Up @@ -43,6 +43,14 @@ inline int GetRank(const ConstantSubscripts &s) {

std::size_t TotalElementCount(const ConstantSubscripts &);

// Validate dimension re-ordering like ORDER in RESHAPE.
// On success, return a vector that can be used as dimOrder in
// ConstantBound::IncrementSubscripts.
std::optional<std::vector<int>> ValidateDimensionOrder(
int rank, const std::vector<int> &order);

bool IsValidShape(const ConstantSubscripts &);

class ConstantBounds {
public:
ConstantBounds() = default;
Expand All @@ -55,9 +63,13 @@ class ConstantBounds {
int Rank() const { return GetRank(shape_); }
Constant<SubscriptInteger> SHAPE() const;

// Increments a vector of subscripts in Fortran array order (first dimension
// varying most quickly). Returns false when last element was visited.
bool IncrementSubscripts(ConstantSubscripts &) const;
// If no optional dimension order argument is passed, increments a vector of
// subscripts in Fortran array order (first dimension varying most quickly).
// Otherwise, increments the vector of subscripts according to the given
// dimension order (dimension dimOrder[0] varying most quickly. Dimensions
// indexing is zero based here.) Returns false when last element was visited.
bool IncrementSubscripts(
ConstantSubscripts &, const std::vector<int> *dimOrder = nullptr) const;

protected:
ConstantSubscript SubscriptsToOffset(const ConstantSubscripts &) const;
Expand Down Expand Up @@ -100,6 +112,8 @@ class ConstantBase : public ConstantBounds {

protected:
std::vector<Element> Reshape(const ConstantSubscripts &) const;
std::size_t CopyFrom(const ConstantBase &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);

Result result_;
std::vector<Element> values_;
Expand All @@ -126,6 +140,8 @@ template<typename T> class Constant : public ConstantBase<T> {
Element At(const ConstantSubscripts &) const;

Constant Reshape(ConstantSubscripts &&) const;
std::size_t CopyFrom(const Constant &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
};

template<int KIND>
Expand Down Expand Up @@ -164,6 +180,8 @@ class Constant<Type<TypeCategory::Character, KIND>> : public ConstantBounds {
static constexpr DynamicType GetType() {
return {TypeCategory::Character, KIND};
}
std::size_t CopyFrom(const Constant &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);

private:
Scalar<Result> values_; // one contiguous string
Expand Down Expand Up @@ -196,6 +214,8 @@ class Constant<SomeDerived>
StructureConstructor At(const ConstantSubscripts &) const;

Constant Reshape(ConstantSubscripts &&) const;
std::size_t CopyFrom(const Constant &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
};

FOR_EACH_LENGTHLESS_INTRINSIC_KIND(extern template class ConstantBase, )
Expand Down

0 comments on commit 953d93d

Please sign in to comment.