1f9704f0cSValentin Clement //===-- IterationSpace.cpp ------------------------------------------------===// 2f9704f0cSValentin Clement // 3f9704f0cSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f9704f0cSValentin Clement // See https://llvm.org/LICENSE.txt for license information. 5f9704f0cSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f9704f0cSValentin Clement // 7f9704f0cSValentin Clement //===----------------------------------------------------------------------===// 8f9704f0cSValentin Clement // 9f9704f0cSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 10f9704f0cSValentin Clement // 11f9704f0cSValentin Clement //===----------------------------------------------------------------------===// 12f9704f0cSValentin Clement 13f9704f0cSValentin Clement #include "flang/Lower/IterationSpace.h" 14f9704f0cSValentin Clement #include "flang/Evaluate/expression.h" 15f9704f0cSValentin Clement #include "flang/Lower/AbstractConverter.h" 16f9704f0cSValentin Clement #include "flang/Lower/Support/Utils.h" 17f9704f0cSValentin Clement #include "llvm/Support/Debug.h" 18f9704f0cSValentin Clement 19f9704f0cSValentin Clement #define DEBUG_TYPE "flang-lower-iteration-space" 20f9704f0cSValentin Clement 21f9704f0cSValentin Clement namespace { 22f9704f0cSValentin Clement // Fortran::evaluate::Expr are functional values organized like an AST. A 23f9704f0cSValentin Clement // Fortran::evaluate::Expr is meant to be moved and cloned. Using the front end 24f9704f0cSValentin Clement // tools can often cause copies and extra wrapper classes to be added to any 25f9704f0cSValentin Clement // Fortran::evalute::Expr. These values should not be assumed or relied upon to 26f9704f0cSValentin Clement // have an *object* identity. They are deeply recursive, irregular structures 27f9704f0cSValentin Clement // built from a large number of classes which do not use inheritance and 28f9704f0cSValentin Clement // necessitate a large volume of boilerplate code as a result. 29f9704f0cSValentin Clement // 30f9704f0cSValentin Clement // Contrastingly, LLVM data structures make ubiquitous assumptions about an 31f9704f0cSValentin Clement // object's identity via pointers to the object. An object's location in memory 32f9704f0cSValentin Clement // is thus very often an identifying relation. 33f9704f0cSValentin Clement 34f9704f0cSValentin Clement // This class defines a hash computation of a Fortran::evaluate::Expr tree value 35f9704f0cSValentin Clement // so it can be used with llvm::DenseMap. The Fortran::evaluate::Expr need not 36f9704f0cSValentin Clement // have the same address. 37f9704f0cSValentin Clement class HashEvaluateExpr { 38f9704f0cSValentin Clement public: 39f9704f0cSValentin Clement // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an 40f9704f0cSValentin Clement // identity property. 41f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::semantics::Symbol &x) { 42f9704f0cSValentin Clement return static_cast<unsigned>(reinterpret_cast<std::intptr_t>(&x)); 43f9704f0cSValentin Clement } 44f9704f0cSValentin Clement template <typename A, bool COPY> 45f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::common::Indirection<A, COPY> &x) { 46f9704f0cSValentin Clement return getHashValue(x.value()); 47f9704f0cSValentin Clement } 48f9704f0cSValentin Clement template <typename A> 49f9704f0cSValentin Clement static unsigned getHashValue(const std::optional<A> &x) { 50f9704f0cSValentin Clement if (x.has_value()) 51f9704f0cSValentin Clement return getHashValue(x.value()); 52f9704f0cSValentin Clement return 0u; 53f9704f0cSValentin Clement } 54f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Subscript &x) { 55f9704f0cSValentin Clement return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); 56f9704f0cSValentin Clement } 57f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Triplet &x) { 58f9704f0cSValentin Clement return getHashValue(x.lower()) - getHashValue(x.upper()) * 5u - 59f9704f0cSValentin Clement getHashValue(x.stride()) * 11u; 60f9704f0cSValentin Clement } 61f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Component &x) { 62f9704f0cSValentin Clement return getHashValue(x.base()) * 83u - getHashValue(x.GetLastSymbol()); 63f9704f0cSValentin Clement } 64f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::ArrayRef &x) { 65f9704f0cSValentin Clement unsigned subs = 1u; 66f9704f0cSValentin Clement for (const Fortran::evaluate::Subscript &v : x.subscript()) 67f9704f0cSValentin Clement subs -= getHashValue(v); 68f9704f0cSValentin Clement return getHashValue(x.base()) * 89u - subs; 69f9704f0cSValentin Clement } 70f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::CoarrayRef &x) { 71f9704f0cSValentin Clement unsigned subs = 1u; 72f9704f0cSValentin Clement for (const Fortran::evaluate::Subscript &v : x.subscript()) 73f9704f0cSValentin Clement subs -= getHashValue(v); 74f9704f0cSValentin Clement unsigned cosubs = 3u; 75f9704f0cSValentin Clement for (const Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger> &v : 76f9704f0cSValentin Clement x.cosubscript()) 77f9704f0cSValentin Clement cosubs -= getHashValue(v); 78f9704f0cSValentin Clement unsigned syms = 7u; 79f9704f0cSValentin Clement for (const Fortran::evaluate::SymbolRef &v : x.base()) 80f9704f0cSValentin Clement syms += getHashValue(v); 81f9704f0cSValentin Clement return syms * 97u - subs - cosubs + getHashValue(x.stat()) + 257u + 82f9704f0cSValentin Clement getHashValue(x.team()); 83f9704f0cSValentin Clement } 84f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::NamedEntity &x) { 85f9704f0cSValentin Clement if (x.IsSymbol()) 86f9704f0cSValentin Clement return getHashValue(x.GetFirstSymbol()) * 11u; 87f9704f0cSValentin Clement return getHashValue(x.GetComponent()) * 13u; 88f9704f0cSValentin Clement } 89f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::DataRef &x) { 90f9704f0cSValentin Clement return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); 91f9704f0cSValentin Clement } 92f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::ComplexPart &x) { 93f9704f0cSValentin Clement return getHashValue(x.complex()) - static_cast<unsigned>(x.part()); 94f9704f0cSValentin Clement } 95f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC1, int KIND, 96f9704f0cSValentin Clement Fortran::common::TypeCategory TC2> 97f9704f0cSValentin Clement static unsigned getHashValue( 98f9704f0cSValentin Clement const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2> 99f9704f0cSValentin Clement &x) { 100f9704f0cSValentin Clement return getHashValue(x.left()) - (static_cast<unsigned>(TC1) + 2u) - 101f9704f0cSValentin Clement (static_cast<unsigned>(KIND) + 5u); 102f9704f0cSValentin Clement } 103f9704f0cSValentin Clement template <int KIND> 104f9704f0cSValentin Clement static unsigned 105f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::ComplexComponent<KIND> &x) { 106f9704f0cSValentin Clement return getHashValue(x.left()) - 107f9704f0cSValentin Clement (static_cast<unsigned>(x.isImaginaryPart) + 1u) * 3u; 108f9704f0cSValentin Clement } 109f9704f0cSValentin Clement template <typename T> 110f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Parentheses<T> &x) { 111f9704f0cSValentin Clement return getHashValue(x.left()) * 17u; 112f9704f0cSValentin Clement } 113f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 114f9704f0cSValentin Clement static unsigned getHashValue( 115f9704f0cSValentin Clement const Fortran::evaluate::Negate<Fortran::evaluate::Type<TC, KIND>> &x) { 116f9704f0cSValentin Clement return getHashValue(x.left()) - (static_cast<unsigned>(TC) + 5u) - 117f9704f0cSValentin Clement (static_cast<unsigned>(KIND) + 7u); 118f9704f0cSValentin Clement } 119f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 120f9704f0cSValentin Clement static unsigned getHashValue( 121f9704f0cSValentin Clement const Fortran::evaluate::Add<Fortran::evaluate::Type<TC, KIND>> &x) { 122f9704f0cSValentin Clement return (getHashValue(x.left()) + getHashValue(x.right())) * 23u + 123f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); 124f9704f0cSValentin Clement } 125f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 126f9704f0cSValentin Clement static unsigned getHashValue( 127f9704f0cSValentin Clement const Fortran::evaluate::Subtract<Fortran::evaluate::Type<TC, KIND>> &x) { 128f9704f0cSValentin Clement return (getHashValue(x.left()) - getHashValue(x.right())) * 19u + 129f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); 130f9704f0cSValentin Clement } 131f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 132f9704f0cSValentin Clement static unsigned getHashValue( 133f9704f0cSValentin Clement const Fortran::evaluate::Multiply<Fortran::evaluate::Type<TC, KIND>> &x) { 134f9704f0cSValentin Clement return (getHashValue(x.left()) + getHashValue(x.right())) * 29u + 135f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); 136f9704f0cSValentin Clement } 137f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 138f9704f0cSValentin Clement static unsigned getHashValue( 139f9704f0cSValentin Clement const Fortran::evaluate::Divide<Fortran::evaluate::Type<TC, KIND>> &x) { 140f9704f0cSValentin Clement return (getHashValue(x.left()) - getHashValue(x.right())) * 31u + 141f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); 142f9704f0cSValentin Clement } 143f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 144f9704f0cSValentin Clement static unsigned getHashValue( 145f9704f0cSValentin Clement const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x) { 146f9704f0cSValentin Clement return (getHashValue(x.left()) - getHashValue(x.right())) * 37u + 147f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); 148f9704f0cSValentin Clement } 149f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 150f9704f0cSValentin Clement static unsigned getHashValue( 151f9704f0cSValentin Clement const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x) { 152f9704f0cSValentin Clement return (getHashValue(x.left()) + getHashValue(x.right())) * 41u + 153f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND) + 154f9704f0cSValentin Clement static_cast<unsigned>(x.ordering) * 7u; 155f9704f0cSValentin Clement } 156f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 157f9704f0cSValentin Clement static unsigned getHashValue( 158f9704f0cSValentin Clement const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> 159f9704f0cSValentin Clement &x) { 160f9704f0cSValentin Clement return (getHashValue(x.left()) - getHashValue(x.right())) * 43u + 161f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); 162f9704f0cSValentin Clement } 163f9704f0cSValentin Clement template <int KIND> 164f9704f0cSValentin Clement static unsigned 165f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::ComplexConstructor<KIND> &x) { 166f9704f0cSValentin Clement return (getHashValue(x.left()) - getHashValue(x.right())) * 47u + 167f9704f0cSValentin Clement static_cast<unsigned>(KIND); 168f9704f0cSValentin Clement } 169f9704f0cSValentin Clement template <int KIND> 170f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Concat<KIND> &x) { 171f9704f0cSValentin Clement return (getHashValue(x.left()) - getHashValue(x.right())) * 53u + 172f9704f0cSValentin Clement static_cast<unsigned>(KIND); 173f9704f0cSValentin Clement } 174f9704f0cSValentin Clement template <int KIND> 175f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::SetLength<KIND> &x) { 176f9704f0cSValentin Clement return (getHashValue(x.left()) - getHashValue(x.right())) * 59u + 177f9704f0cSValentin Clement static_cast<unsigned>(KIND); 178f9704f0cSValentin Clement } 179f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) { 180f9704f0cSValentin Clement return getHashValue(sym.get()); 181f9704f0cSValentin Clement } 182f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Substring &x) { 183f9704f0cSValentin Clement return 61u * std::visit([&](const auto &p) { return getHashValue(p); }, 184f9704f0cSValentin Clement x.parent()) - 185f9704f0cSValentin Clement getHashValue(x.lower()) - (getHashValue(x.lower()) + 1u); 186f9704f0cSValentin Clement } 187f9704f0cSValentin Clement static unsigned 188f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::StaticDataObject::Pointer &x) { 189f9704f0cSValentin Clement return llvm::hash_value(x->name()); 190f9704f0cSValentin Clement } 191f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::SpecificIntrinsic &x) { 192f9704f0cSValentin Clement return llvm::hash_value(x.name); 193f9704f0cSValentin Clement } 194f9704f0cSValentin Clement template <typename A> 195f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Constant<A> &x) { 196f9704f0cSValentin Clement // FIXME: Should hash the content. 197f9704f0cSValentin Clement return 103u; 198f9704f0cSValentin Clement } 199f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::ActualArgument &x) { 200f9704f0cSValentin Clement if (const Fortran::evaluate::Symbol *sym = x.GetAssumedTypeDummy()) 201f9704f0cSValentin Clement return getHashValue(*sym); 202f9704f0cSValentin Clement return getHashValue(*x.UnwrapExpr()); 203f9704f0cSValentin Clement } 204f9704f0cSValentin Clement static unsigned 205f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::ProcedureDesignator &x) { 206f9704f0cSValentin Clement return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); 207f9704f0cSValentin Clement } 208f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::ProcedureRef &x) { 209f9704f0cSValentin Clement unsigned args = 13u; 210f9704f0cSValentin Clement for (const std::optional<Fortran::evaluate::ActualArgument> &v : 211f9704f0cSValentin Clement x.arguments()) 212f9704f0cSValentin Clement args -= getHashValue(v); 213f9704f0cSValentin Clement return getHashValue(x.proc()) * 101u - args; 214f9704f0cSValentin Clement } 215f9704f0cSValentin Clement template <typename A> 216f9704f0cSValentin Clement static unsigned 217f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::ArrayConstructor<A> &x) { 218f9704f0cSValentin Clement // FIXME: hash the contents. 219f9704f0cSValentin Clement return 127u; 220f9704f0cSValentin Clement } 221f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::ImpliedDoIndex &x) { 222f9704f0cSValentin Clement return llvm::hash_value(toStringRef(x.name).str()) * 131u; 223f9704f0cSValentin Clement } 224f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::TypeParamInquiry &x) { 225f9704f0cSValentin Clement return getHashValue(x.base()) * 137u - getHashValue(x.parameter()) * 3u; 226f9704f0cSValentin Clement } 227f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::DescriptorInquiry &x) { 228f9704f0cSValentin Clement return getHashValue(x.base()) * 139u - 229f9704f0cSValentin Clement static_cast<unsigned>(x.field()) * 13u + 230f9704f0cSValentin Clement static_cast<unsigned>(x.dimension()); 231f9704f0cSValentin Clement } 232f9704f0cSValentin Clement static unsigned 233f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::StructureConstructor &x) { 234f9704f0cSValentin Clement // FIXME: hash the contents. 235f9704f0cSValentin Clement return 149u; 236f9704f0cSValentin Clement } 237f9704f0cSValentin Clement template <int KIND> 238f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Not<KIND> &x) { 239f9704f0cSValentin Clement return getHashValue(x.left()) * 61u + static_cast<unsigned>(KIND); 240f9704f0cSValentin Clement } 241f9704f0cSValentin Clement template <int KIND> 242f9704f0cSValentin Clement static unsigned 243f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::LogicalOperation<KIND> &x) { 244f9704f0cSValentin Clement unsigned result = getHashValue(x.left()) + getHashValue(x.right()); 245f9704f0cSValentin Clement return result * 67u + static_cast<unsigned>(x.logicalOperator) * 5u; 246f9704f0cSValentin Clement } 247f9704f0cSValentin Clement template <Fortran::common::TypeCategory TC, int KIND> 248f9704f0cSValentin Clement static unsigned getHashValue( 249f9704f0cSValentin Clement const Fortran::evaluate::Relational<Fortran::evaluate::Type<TC, KIND>> 250f9704f0cSValentin Clement &x) { 251f9704f0cSValentin Clement return (getHashValue(x.left()) + getHashValue(x.right())) * 71u + 252f9704f0cSValentin Clement static_cast<unsigned>(TC) + static_cast<unsigned>(KIND) + 253f9704f0cSValentin Clement static_cast<unsigned>(x.opr) * 11u; 254f9704f0cSValentin Clement } 255f9704f0cSValentin Clement template <typename A> 256f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Expr<A> &x) { 257f9704f0cSValentin Clement return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); 258f9704f0cSValentin Clement } 259f9704f0cSValentin Clement static unsigned getHashValue( 260f9704f0cSValentin Clement const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x) { 261f9704f0cSValentin Clement return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); 262f9704f0cSValentin Clement } 263f9704f0cSValentin Clement template <typename A> 264f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::Designator<A> &x) { 265f9704f0cSValentin Clement return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); 266f9704f0cSValentin Clement } 267f9704f0cSValentin Clement template <int BITS> 268f9704f0cSValentin Clement static unsigned 269f9704f0cSValentin Clement getHashValue(const Fortran::evaluate::value::Integer<BITS> &x) { 270f9704f0cSValentin Clement return static_cast<unsigned>(x.ToSInt()); 271f9704f0cSValentin Clement } 272f9704f0cSValentin Clement static unsigned getHashValue(const Fortran::evaluate::NullPointer &x) { 273f9704f0cSValentin Clement return ~179u; 274f9704f0cSValentin Clement } 275f9704f0cSValentin Clement }; 276f9704f0cSValentin Clement } // namespace 277f9704f0cSValentin Clement 278f9704f0cSValentin Clement unsigned Fortran::lower::getHashValue( 279f9704f0cSValentin Clement const Fortran::lower::ExplicitIterSpace::ArrayBases &x) { 280f9704f0cSValentin Clement return std::visit( 281f9704f0cSValentin Clement [&](const auto *p) { return HashEvaluateExpr::getHashValue(*p); }, x); 282f9704f0cSValentin Clement } 283f9704f0cSValentin Clement 284f9704f0cSValentin Clement unsigned Fortran::lower::getHashValue(Fortran::lower::FrontEndExpr x) { 285f9704f0cSValentin Clement return HashEvaluateExpr::getHashValue(*x); 286f9704f0cSValentin Clement } 287f9704f0cSValentin Clement 288f9704f0cSValentin Clement namespace { 289f9704f0cSValentin Clement // Define the is equals test for using Fortran::evaluate::Expr values with 290f9704f0cSValentin Clement // llvm::DenseMap. 291f9704f0cSValentin Clement class IsEqualEvaluateExpr { 292f9704f0cSValentin Clement public: 293f9704f0cSValentin Clement // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an 294f9704f0cSValentin Clement // identity property. 295f9704f0cSValentin Clement static bool isEqual(const Fortran::semantics::Symbol &x, 296f9704f0cSValentin Clement const Fortran::semantics::Symbol &y) { 297f9704f0cSValentin Clement return isEqual(&x, &y); 298f9704f0cSValentin Clement } 299f9704f0cSValentin Clement static bool isEqual(const Fortran::semantics::Symbol *x, 300f9704f0cSValentin Clement const Fortran::semantics::Symbol *y) { 301f9704f0cSValentin Clement return x == y; 302f9704f0cSValentin Clement } 303f9704f0cSValentin Clement template <typename A, bool COPY> 304f9704f0cSValentin Clement static bool isEqual(const Fortran::common::Indirection<A, COPY> &x, 305f9704f0cSValentin Clement const Fortran::common::Indirection<A, COPY> &y) { 306f9704f0cSValentin Clement return isEqual(x.value(), y.value()); 307f9704f0cSValentin Clement } 308f9704f0cSValentin Clement template <typename A> 309f9704f0cSValentin Clement static bool isEqual(const std::optional<A> &x, const std::optional<A> &y) { 310f9704f0cSValentin Clement if (x.has_value() && y.has_value()) 311f9704f0cSValentin Clement return isEqual(x.value(), y.value()); 312f9704f0cSValentin Clement return !x.has_value() && !y.has_value(); 313f9704f0cSValentin Clement } 314f9704f0cSValentin Clement template <typename A> 315f9704f0cSValentin Clement static bool isEqual(const std::vector<A> &x, const std::vector<A> &y) { 316f9704f0cSValentin Clement if (x.size() != y.size()) 317f9704f0cSValentin Clement return false; 318f9704f0cSValentin Clement const std::size_t size = x.size(); 319f9704f0cSValentin Clement for (std::remove_const_t<decltype(size)> i = 0; i < size; ++i) 320f9704f0cSValentin Clement if (!isEqual(x[i], y[i])) 321f9704f0cSValentin Clement return false; 322f9704f0cSValentin Clement return true; 323f9704f0cSValentin Clement } 324f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Subscript &x, 325f9704f0cSValentin Clement const Fortran::evaluate::Subscript &y) { 326f9704f0cSValentin Clement return std::visit( 327f9704f0cSValentin Clement [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); 328f9704f0cSValentin Clement } 329f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Triplet &x, 330f9704f0cSValentin Clement const Fortran::evaluate::Triplet &y) { 331f9704f0cSValentin Clement return isEqual(x.lower(), y.lower()) && isEqual(x.upper(), y.upper()) && 332f9704f0cSValentin Clement isEqual(x.stride(), y.stride()); 333f9704f0cSValentin Clement } 334f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Component &x, 335f9704f0cSValentin Clement const Fortran::evaluate::Component &y) { 336f9704f0cSValentin Clement return isEqual(x.base(), y.base()) && 337f9704f0cSValentin Clement isEqual(x.GetLastSymbol(), y.GetLastSymbol()); 338f9704f0cSValentin Clement } 339f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ArrayRef &x, 340f9704f0cSValentin Clement const Fortran::evaluate::ArrayRef &y) { 341f9704f0cSValentin Clement return isEqual(x.base(), y.base()) && isEqual(x.subscript(), y.subscript()); 342f9704f0cSValentin Clement } 343f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::CoarrayRef &x, 344f9704f0cSValentin Clement const Fortran::evaluate::CoarrayRef &y) { 345f9704f0cSValentin Clement return isEqual(x.base(), y.base()) && 346f9704f0cSValentin Clement isEqual(x.subscript(), y.subscript()) && 347f9704f0cSValentin Clement isEqual(x.cosubscript(), y.cosubscript()) && 348f9704f0cSValentin Clement isEqual(x.stat(), y.stat()) && isEqual(x.team(), y.team()); 349f9704f0cSValentin Clement } 350f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::NamedEntity &x, 351f9704f0cSValentin Clement const Fortran::evaluate::NamedEntity &y) { 352f9704f0cSValentin Clement if (x.IsSymbol() && y.IsSymbol()) 353f9704f0cSValentin Clement return isEqual(x.GetFirstSymbol(), y.GetFirstSymbol()); 354f9704f0cSValentin Clement return !x.IsSymbol() && !y.IsSymbol() && 355f9704f0cSValentin Clement isEqual(x.GetComponent(), y.GetComponent()); 356f9704f0cSValentin Clement } 357f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::DataRef &x, 358f9704f0cSValentin Clement const Fortran::evaluate::DataRef &y) { 359f9704f0cSValentin Clement return std::visit( 360f9704f0cSValentin Clement [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); 361f9704f0cSValentin Clement } 362f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ComplexPart &x, 363f9704f0cSValentin Clement const Fortran::evaluate::ComplexPart &y) { 364f9704f0cSValentin Clement return isEqual(x.complex(), y.complex()) && x.part() == y.part(); 365f9704f0cSValentin Clement } 366f9704f0cSValentin Clement template <typename A, Fortran::common::TypeCategory TC2> 367f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Convert<A, TC2> &x, 368f9704f0cSValentin Clement const Fortran::evaluate::Convert<A, TC2> &y) { 369f9704f0cSValentin Clement return isEqual(x.left(), y.left()); 370f9704f0cSValentin Clement } 371f9704f0cSValentin Clement template <int KIND> 372f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ComplexComponent<KIND> &x, 373f9704f0cSValentin Clement const Fortran::evaluate::ComplexComponent<KIND> &y) { 374f9704f0cSValentin Clement return isEqual(x.left(), y.left()) && 375f9704f0cSValentin Clement x.isImaginaryPart == y.isImaginaryPart; 376f9704f0cSValentin Clement } 377f9704f0cSValentin Clement template <typename T> 378f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Parentheses<T> &x, 379f9704f0cSValentin Clement const Fortran::evaluate::Parentheses<T> &y) { 380f9704f0cSValentin Clement return isEqual(x.left(), y.left()); 381f9704f0cSValentin Clement } 382f9704f0cSValentin Clement template <typename A> 383f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Negate<A> &x, 384f9704f0cSValentin Clement const Fortran::evaluate::Negate<A> &y) { 385f9704f0cSValentin Clement return isEqual(x.left(), y.left()); 386f9704f0cSValentin Clement } 387f9704f0cSValentin Clement template <typename A> 388f9704f0cSValentin Clement static bool isBinaryEqual(const A &x, const A &y) { 389f9704f0cSValentin Clement return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); 390f9704f0cSValentin Clement } 391f9704f0cSValentin Clement template <typename A> 392f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Add<A> &x, 393f9704f0cSValentin Clement const Fortran::evaluate::Add<A> &y) { 394f9704f0cSValentin Clement return isBinaryEqual(x, y); 395f9704f0cSValentin Clement } 396f9704f0cSValentin Clement template <typename A> 397f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Subtract<A> &x, 398f9704f0cSValentin Clement const Fortran::evaluate::Subtract<A> &y) { 399f9704f0cSValentin Clement return isBinaryEqual(x, y); 400f9704f0cSValentin Clement } 401f9704f0cSValentin Clement template <typename A> 402f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Multiply<A> &x, 403f9704f0cSValentin Clement const Fortran::evaluate::Multiply<A> &y) { 404f9704f0cSValentin Clement return isBinaryEqual(x, y); 405f9704f0cSValentin Clement } 406f9704f0cSValentin Clement template <typename A> 407f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Divide<A> &x, 408f9704f0cSValentin Clement const Fortran::evaluate::Divide<A> &y) { 409f9704f0cSValentin Clement return isBinaryEqual(x, y); 410f9704f0cSValentin Clement } 411f9704f0cSValentin Clement template <typename A> 412f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Power<A> &x, 413f9704f0cSValentin Clement const Fortran::evaluate::Power<A> &y) { 414f9704f0cSValentin Clement return isBinaryEqual(x, y); 415f9704f0cSValentin Clement } 416f9704f0cSValentin Clement template <typename A> 417f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Extremum<A> &x, 418f9704f0cSValentin Clement const Fortran::evaluate::Extremum<A> &y) { 419f9704f0cSValentin Clement return isBinaryEqual(x, y); 420f9704f0cSValentin Clement } 421f9704f0cSValentin Clement template <typename A> 422f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::RealToIntPower<A> &x, 423f9704f0cSValentin Clement const Fortran::evaluate::RealToIntPower<A> &y) { 424f9704f0cSValentin Clement return isBinaryEqual(x, y); 425f9704f0cSValentin Clement } 426f9704f0cSValentin Clement template <int KIND> 427f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ComplexConstructor<KIND> &x, 428f9704f0cSValentin Clement const Fortran::evaluate::ComplexConstructor<KIND> &y) { 429f9704f0cSValentin Clement return isBinaryEqual(x, y); 430f9704f0cSValentin Clement } 431f9704f0cSValentin Clement template <int KIND> 432f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Concat<KIND> &x, 433f9704f0cSValentin Clement const Fortran::evaluate::Concat<KIND> &y) { 434f9704f0cSValentin Clement return isBinaryEqual(x, y); 435f9704f0cSValentin Clement } 436f9704f0cSValentin Clement template <int KIND> 437f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::SetLength<KIND> &x, 438f9704f0cSValentin Clement const Fortran::evaluate::SetLength<KIND> &y) { 439f9704f0cSValentin Clement return isBinaryEqual(x, y); 440f9704f0cSValentin Clement } 441f9704f0cSValentin Clement static bool isEqual(const Fortran::semantics::SymbolRef &x, 442f9704f0cSValentin Clement const Fortran::semantics::SymbolRef &y) { 443f9704f0cSValentin Clement return isEqual(x.get(), y.get()); 444f9704f0cSValentin Clement } 445f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Substring &x, 446f9704f0cSValentin Clement const Fortran::evaluate::Substring &y) { 447f9704f0cSValentin Clement return std::visit( 448f9704f0cSValentin Clement [&](const auto &p, const auto &q) { return isEqual(p, q); }, 449f9704f0cSValentin Clement x.parent(), y.parent()) && 450f9704f0cSValentin Clement isEqual(x.lower(), y.lower()) && isEqual(x.lower(), y.lower()); 451f9704f0cSValentin Clement } 452f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::StaticDataObject::Pointer &x, 453f9704f0cSValentin Clement const Fortran::evaluate::StaticDataObject::Pointer &y) { 454f9704f0cSValentin Clement return x->name() == y->name(); 455f9704f0cSValentin Clement } 456f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::SpecificIntrinsic &x, 457f9704f0cSValentin Clement const Fortran::evaluate::SpecificIntrinsic &y) { 458f9704f0cSValentin Clement return x.name == y.name; 459f9704f0cSValentin Clement } 460f9704f0cSValentin Clement template <typename A> 461f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Constant<A> &x, 462f9704f0cSValentin Clement const Fortran::evaluate::Constant<A> &y) { 463f9704f0cSValentin Clement return x == y; 464f9704f0cSValentin Clement } 465f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ActualArgument &x, 466f9704f0cSValentin Clement const Fortran::evaluate::ActualArgument &y) { 467f9704f0cSValentin Clement if (const Fortran::evaluate::Symbol *xs = x.GetAssumedTypeDummy()) { 468f9704f0cSValentin Clement if (const Fortran::evaluate::Symbol *ys = y.GetAssumedTypeDummy()) 469f9704f0cSValentin Clement return isEqual(*xs, *ys); 470f9704f0cSValentin Clement return false; 471f9704f0cSValentin Clement } 472f9704f0cSValentin Clement return !y.GetAssumedTypeDummy() && 473f9704f0cSValentin Clement isEqual(*x.UnwrapExpr(), *y.UnwrapExpr()); 474f9704f0cSValentin Clement } 475f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ProcedureDesignator &x, 476f9704f0cSValentin Clement const Fortran::evaluate::ProcedureDesignator &y) { 477f9704f0cSValentin Clement return std::visit( 478f9704f0cSValentin Clement [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); 479f9704f0cSValentin Clement } 480f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ProcedureRef &x, 481f9704f0cSValentin Clement const Fortran::evaluate::ProcedureRef &y) { 482f9704f0cSValentin Clement return isEqual(x.proc(), y.proc()) && isEqual(x.arguments(), y.arguments()); 483f9704f0cSValentin Clement } 484f9704f0cSValentin Clement template <typename A> 485f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ArrayConstructor<A> &x, 486f9704f0cSValentin Clement const Fortran::evaluate::ArrayConstructor<A> &y) { 487f9704f0cSValentin Clement llvm::report_fatal_error("not implemented"); 488f9704f0cSValentin Clement } 489f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::ImpliedDoIndex &x, 490f9704f0cSValentin Clement const Fortran::evaluate::ImpliedDoIndex &y) { 491f9704f0cSValentin Clement return toStringRef(x.name) == toStringRef(y.name); 492f9704f0cSValentin Clement } 493f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::TypeParamInquiry &x, 494f9704f0cSValentin Clement const Fortran::evaluate::TypeParamInquiry &y) { 495f9704f0cSValentin Clement return isEqual(x.base(), y.base()) && isEqual(x.parameter(), y.parameter()); 496f9704f0cSValentin Clement } 497f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::DescriptorInquiry &x, 498f9704f0cSValentin Clement const Fortran::evaluate::DescriptorInquiry &y) { 499f9704f0cSValentin Clement return isEqual(x.base(), y.base()) && x.field() == y.field() && 500f9704f0cSValentin Clement x.dimension() == y.dimension(); 501f9704f0cSValentin Clement } 502f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::StructureConstructor &x, 503f9704f0cSValentin Clement const Fortran::evaluate::StructureConstructor &y) { 504f9704f0cSValentin Clement llvm::report_fatal_error("not implemented"); 505f9704f0cSValentin Clement } 506f9704f0cSValentin Clement template <int KIND> 507f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Not<KIND> &x, 508f9704f0cSValentin Clement const Fortran::evaluate::Not<KIND> &y) { 509f9704f0cSValentin Clement return isEqual(x.left(), y.left()); 510f9704f0cSValentin Clement } 511f9704f0cSValentin Clement template <int KIND> 512f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::LogicalOperation<KIND> &x, 513f9704f0cSValentin Clement const Fortran::evaluate::LogicalOperation<KIND> &y) { 514f9704f0cSValentin Clement return isEqual(x.left(), y.left()) && isEqual(x.right(), x.right()); 515f9704f0cSValentin Clement } 516f9704f0cSValentin Clement template <typename A> 517f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Relational<A> &x, 518f9704f0cSValentin Clement const Fortran::evaluate::Relational<A> &y) { 519f9704f0cSValentin Clement return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); 520f9704f0cSValentin Clement } 521f9704f0cSValentin Clement template <typename A> 522f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Expr<A> &x, 523f9704f0cSValentin Clement const Fortran::evaluate::Expr<A> &y) { 524f9704f0cSValentin Clement return std::visit( 525f9704f0cSValentin Clement [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); 526f9704f0cSValentin Clement } 527f9704f0cSValentin Clement static bool 528f9704f0cSValentin Clement isEqual(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x, 529f9704f0cSValentin Clement const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &y) { 530f9704f0cSValentin Clement return std::visit( 531f9704f0cSValentin Clement [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); 532f9704f0cSValentin Clement } 533f9704f0cSValentin Clement template <typename A> 534f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::Designator<A> &x, 535f9704f0cSValentin Clement const Fortran::evaluate::Designator<A> &y) { 536f9704f0cSValentin Clement return std::visit( 537f9704f0cSValentin Clement [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); 538f9704f0cSValentin Clement } 539f9704f0cSValentin Clement template <int BITS> 540f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::value::Integer<BITS> &x, 541f9704f0cSValentin Clement const Fortran::evaluate::value::Integer<BITS> &y) { 542f9704f0cSValentin Clement return x == y; 543f9704f0cSValentin Clement } 544f9704f0cSValentin Clement static bool isEqual(const Fortran::evaluate::NullPointer &x, 545f9704f0cSValentin Clement const Fortran::evaluate::NullPointer &y) { 546f9704f0cSValentin Clement return true; 547f9704f0cSValentin Clement } 548f9704f0cSValentin Clement template <typename A, typename B, 549f9704f0cSValentin Clement std::enable_if_t<!std::is_same_v<A, B>, bool> = true> 550f9704f0cSValentin Clement static bool isEqual(const A &, const B &) { 551f9704f0cSValentin Clement return false; 552f9704f0cSValentin Clement } 553f9704f0cSValentin Clement }; 554f9704f0cSValentin Clement } // namespace 555f9704f0cSValentin Clement 556f9704f0cSValentin Clement bool Fortran::lower::isEqual( 557f9704f0cSValentin Clement const Fortran::lower::ExplicitIterSpace::ArrayBases &x, 558f9704f0cSValentin Clement const Fortran::lower::ExplicitIterSpace::ArrayBases &y) { 559f9704f0cSValentin Clement return std::visit( 560f9704f0cSValentin Clement Fortran::common::visitors{ 561f9704f0cSValentin Clement // Fortran::semantics::Symbol * are the exception here. These pointers 562f9704f0cSValentin Clement // have identity; if two Symbol * values are the same (different) then 563f9704f0cSValentin Clement // they are the same (different) logical symbol. 564f9704f0cSValentin Clement [&](Fortran::lower::FrontEndSymbol p, 565f9704f0cSValentin Clement Fortran::lower::FrontEndSymbol q) { return p == q; }, 566f9704f0cSValentin Clement [&](const auto *p, const auto *q) { 567f9704f0cSValentin Clement if constexpr (std::is_same_v<decltype(p), decltype(q)>) { 568f9704f0cSValentin Clement LLVM_DEBUG(llvm::dbgs() 569f9704f0cSValentin Clement << "is equal: " << p << ' ' << q << ' ' 570f9704f0cSValentin Clement << IsEqualEvaluateExpr::isEqual(*p, *q) << '\n'); 571f9704f0cSValentin Clement return IsEqualEvaluateExpr::isEqual(*p, *q); 572f9704f0cSValentin Clement } else { 573f9704f0cSValentin Clement // Different subtree types are never equal. 574f9704f0cSValentin Clement return false; 575f9704f0cSValentin Clement } 576f9704f0cSValentin Clement }}, 577f9704f0cSValentin Clement x, y); 578f9704f0cSValentin Clement } 579f9704f0cSValentin Clement 580f9704f0cSValentin Clement bool Fortran::lower::isEqual(Fortran::lower::FrontEndExpr x, 581f9704f0cSValentin Clement Fortran::lower::FrontEndExpr y) { 582f9704f0cSValentin Clement auto empty = llvm::DenseMapInfo<Fortran::lower::FrontEndExpr>::getEmptyKey(); 583f9704f0cSValentin Clement auto tombstone = 584f9704f0cSValentin Clement llvm::DenseMapInfo<Fortran::lower::FrontEndExpr>::getTombstoneKey(); 585f9704f0cSValentin Clement if (x == empty || y == empty || x == tombstone || y == tombstone) 586f9704f0cSValentin Clement return x == y; 587f9704f0cSValentin Clement return x == y || IsEqualEvaluateExpr::isEqual(*x, *y); 588f9704f0cSValentin Clement } 589f9704f0cSValentin Clement 590f9704f0cSValentin Clement namespace { 591f9704f0cSValentin Clement 592f9704f0cSValentin Clement /// This class can recover the base array in an expression that contains 593f9704f0cSValentin Clement /// explicit iteration space symbols. Most of the class can be ignored as it is 594f9704f0cSValentin Clement /// boilerplate Fortran::evaluate::Expr traversal. 595f9704f0cSValentin Clement class ArrayBaseFinder { 596f9704f0cSValentin Clement public: 597f9704f0cSValentin Clement using RT = bool; 598f9704f0cSValentin Clement 599f9704f0cSValentin Clement ArrayBaseFinder(llvm::ArrayRef<Fortran::lower::FrontEndSymbol> syms) 600f9704f0cSValentin Clement : controlVars(syms.begin(), syms.end()) {} 601f9704f0cSValentin Clement 602f9704f0cSValentin Clement template <typename T> 603f9704f0cSValentin Clement void operator()(const T &x) { 604f9704f0cSValentin Clement (void)find(x); 605f9704f0cSValentin Clement } 606f9704f0cSValentin Clement 607f9704f0cSValentin Clement /// Get the list of bases. 608f9704f0cSValentin Clement llvm::ArrayRef<Fortran::lower::ExplicitIterSpace::ArrayBases> 609f9704f0cSValentin Clement getBases() const { 610f9704f0cSValentin Clement LLVM_DEBUG(llvm::dbgs() 611f9704f0cSValentin Clement << "number of array bases found: " << bases.size() << '\n'); 612f9704f0cSValentin Clement return bases; 613f9704f0cSValentin Clement } 614f9704f0cSValentin Clement 615f9704f0cSValentin Clement private: 616f9704f0cSValentin Clement // First, the cases that are of interest. 617f9704f0cSValentin Clement RT find(const Fortran::semantics::Symbol &symbol) { 618f9704f0cSValentin Clement if (symbol.Rank() > 0) { 619f9704f0cSValentin Clement bases.push_back(&symbol); 620f9704f0cSValentin Clement return true; 621f9704f0cSValentin Clement } 622f9704f0cSValentin Clement return {}; 623f9704f0cSValentin Clement } 624f9704f0cSValentin Clement RT find(const Fortran::evaluate::Component &x) { 625f9704f0cSValentin Clement auto found = find(x.base()); 626f9704f0cSValentin Clement if (!found && x.base().Rank() == 0 && x.Rank() > 0) { 627f9704f0cSValentin Clement bases.push_back(&x); 628f9704f0cSValentin Clement return true; 629f9704f0cSValentin Clement } 630f9704f0cSValentin Clement return found; 631f9704f0cSValentin Clement } 632f9704f0cSValentin Clement RT find(const Fortran::evaluate::ArrayRef &x) { 633f9704f0cSValentin Clement for (const auto &sub : x.subscript()) 634f9704f0cSValentin Clement (void)find(sub); 635f9704f0cSValentin Clement if (x.base().IsSymbol()) { 636f9704f0cSValentin Clement if (x.Rank() > 0 || intersection(x.subscript())) { 637f9704f0cSValentin Clement bases.push_back(&x); 638f9704f0cSValentin Clement return true; 639f9704f0cSValentin Clement } 640f9704f0cSValentin Clement return {}; 641f9704f0cSValentin Clement } 642f9704f0cSValentin Clement auto found = find(x.base()); 643f9704f0cSValentin Clement if (!found && ((x.base().Rank() == 0 && x.Rank() > 0) || 644f9704f0cSValentin Clement intersection(x.subscript()))) { 645f9704f0cSValentin Clement bases.push_back(&x); 646f9704f0cSValentin Clement return true; 647f9704f0cSValentin Clement } 648f9704f0cSValentin Clement return found; 649f9704f0cSValentin Clement } 650f9704f0cSValentin Clement RT find(const Fortran::evaluate::Triplet &x) { 651f9704f0cSValentin Clement if (const auto *lower = x.GetLower()) 652f9704f0cSValentin Clement (void)find(*lower); 653f9704f0cSValentin Clement if (const auto *upper = x.GetUpper()) 654f9704f0cSValentin Clement (void)find(*upper); 655f9704f0cSValentin Clement return find(x.GetStride()); 656f9704f0cSValentin Clement } 657f9704f0cSValentin Clement RT find(const Fortran::evaluate::IndirectSubscriptIntegerExpr &x) { 658f9704f0cSValentin Clement return find(x.value()); 659f9704f0cSValentin Clement } 660f9704f0cSValentin Clement RT find(const Fortran::evaluate::Subscript &x) { return find(x.u); } 661f9704f0cSValentin Clement RT find(const Fortran::evaluate::DataRef &x) { return find(x.u); } 662f9704f0cSValentin Clement RT find(const Fortran::evaluate::CoarrayRef &x) { 663f9704f0cSValentin Clement assert(false && "coarray reference"); 664f9704f0cSValentin Clement return {}; 665f9704f0cSValentin Clement } 666f9704f0cSValentin Clement 667f9704f0cSValentin Clement template <typename A> 668f9704f0cSValentin Clement bool intersection(const A &subscripts) { 669f9704f0cSValentin Clement return Fortran::lower::symbolsIntersectSubscripts(controlVars, subscripts); 670f9704f0cSValentin Clement } 671f9704f0cSValentin Clement 672f9704f0cSValentin Clement // The rest is traversal boilerplate and can be ignored. 673f9704f0cSValentin Clement RT find(const Fortran::evaluate::Substring &x) { return find(x.parent()); } 674f9704f0cSValentin Clement template <typename A> 675f9704f0cSValentin Clement RT find(const Fortran::semantics::SymbolRef x) { 676f9704f0cSValentin Clement return find(*x); 677f9704f0cSValentin Clement } 678f9704f0cSValentin Clement RT find(const Fortran::evaluate::NamedEntity &x) { 679f9704f0cSValentin Clement if (x.IsSymbol()) 680f9704f0cSValentin Clement return find(x.GetFirstSymbol()); 681f9704f0cSValentin Clement return find(x.GetComponent()); 682f9704f0cSValentin Clement } 683f9704f0cSValentin Clement 684f9704f0cSValentin Clement template <typename A, bool C> 685f9704f0cSValentin Clement RT find(const Fortran::common::Indirection<A, C> &x) { 686f9704f0cSValentin Clement return find(x.value()); 687f9704f0cSValentin Clement } 688f9704f0cSValentin Clement template <typename A> 689f9704f0cSValentin Clement RT find(const std::unique_ptr<A> &x) { 690f9704f0cSValentin Clement return find(x.get()); 691f9704f0cSValentin Clement } 692f9704f0cSValentin Clement template <typename A> 693f9704f0cSValentin Clement RT find(const std::shared_ptr<A> &x) { 694f9704f0cSValentin Clement return find(x.get()); 695f9704f0cSValentin Clement } 696f9704f0cSValentin Clement template <typename A> 697f9704f0cSValentin Clement RT find(const A *x) { 698f9704f0cSValentin Clement if (x) 699f9704f0cSValentin Clement return find(*x); 700f9704f0cSValentin Clement return {}; 701f9704f0cSValentin Clement } 702f9704f0cSValentin Clement template <typename A> 703f9704f0cSValentin Clement RT find(const std::optional<A> &x) { 704f9704f0cSValentin Clement if (x) 705f9704f0cSValentin Clement return find(*x); 706f9704f0cSValentin Clement return {}; 707f9704f0cSValentin Clement } 708f9704f0cSValentin Clement template <typename... A> 709f9704f0cSValentin Clement RT find(const std::variant<A...> &u) { 710f9704f0cSValentin Clement return std::visit([&](const auto &v) { return find(v); }, u); 711f9704f0cSValentin Clement } 712f9704f0cSValentin Clement template <typename A> 713f9704f0cSValentin Clement RT find(const std::vector<A> &x) { 714f9704f0cSValentin Clement for (auto &v : x) 715f9704f0cSValentin Clement (void)find(v); 716f9704f0cSValentin Clement return {}; 717f9704f0cSValentin Clement } 718f9704f0cSValentin Clement RT find(const Fortran::evaluate::BOZLiteralConstant &) { return {}; } 719f9704f0cSValentin Clement RT find(const Fortran::evaluate::NullPointer &) { return {}; } 720f9704f0cSValentin Clement template <typename T> 721f9704f0cSValentin Clement RT find(const Fortran::evaluate::Constant<T> &x) { 722f9704f0cSValentin Clement return {}; 723f9704f0cSValentin Clement } 724f9704f0cSValentin Clement RT find(const Fortran::evaluate::StaticDataObject &) { return {}; } 725f9704f0cSValentin Clement RT find(const Fortran::evaluate::ImpliedDoIndex &) { return {}; } 726f9704f0cSValentin Clement RT find(const Fortran::evaluate::BaseObject &x) { 727f9704f0cSValentin Clement (void)find(x.u); 728f9704f0cSValentin Clement return {}; 729f9704f0cSValentin Clement } 730f9704f0cSValentin Clement RT find(const Fortran::evaluate::TypeParamInquiry &) { return {}; } 731f9704f0cSValentin Clement RT find(const Fortran::evaluate::ComplexPart &x) { return {}; } 732f9704f0cSValentin Clement template <typename T> 733f9704f0cSValentin Clement RT find(const Fortran::evaluate::Designator<T> &x) { 734f9704f0cSValentin Clement return find(x.u); 735f9704f0cSValentin Clement } 736f9704f0cSValentin Clement template <typename T> 737f9704f0cSValentin Clement RT find(const Fortran::evaluate::Variable<T> &x) { 738f9704f0cSValentin Clement return find(x.u); 739f9704f0cSValentin Clement } 740f9704f0cSValentin Clement RT find(const Fortran::evaluate::DescriptorInquiry &) { return {}; } 741f9704f0cSValentin Clement RT find(const Fortran::evaluate::SpecificIntrinsic &) { return {}; } 742f9704f0cSValentin Clement RT find(const Fortran::evaluate::ProcedureDesignator &x) { return {}; } 743f9704f0cSValentin Clement RT find(const Fortran::evaluate::ProcedureRef &x) { 744f9704f0cSValentin Clement (void)find(x.proc()); 745f9704f0cSValentin Clement if (x.IsElemental()) 746f9704f0cSValentin Clement (void)find(x.arguments()); 747f9704f0cSValentin Clement return {}; 748f9704f0cSValentin Clement } 749f9704f0cSValentin Clement RT find(const Fortran::evaluate::ActualArgument &x) { 750f9704f0cSValentin Clement if (const auto *sym = x.GetAssumedTypeDummy()) 751f9704f0cSValentin Clement (void)find(*sym); 752f9704f0cSValentin Clement else 753f9704f0cSValentin Clement (void)find(x.UnwrapExpr()); 754f9704f0cSValentin Clement return {}; 755f9704f0cSValentin Clement } 756f9704f0cSValentin Clement template <typename T> 757f9704f0cSValentin Clement RT find(const Fortran::evaluate::FunctionRef<T> &x) { 758f9704f0cSValentin Clement (void)find(static_cast<const Fortran::evaluate::ProcedureRef &>(x)); 759f9704f0cSValentin Clement return {}; 760f9704f0cSValentin Clement } 761f9704f0cSValentin Clement template <typename T> 762f9704f0cSValentin Clement RT find(const Fortran::evaluate::ArrayConstructorValue<T> &) { 763f9704f0cSValentin Clement return {}; 764f9704f0cSValentin Clement } 765f9704f0cSValentin Clement template <typename T> 766f9704f0cSValentin Clement RT find(const Fortran::evaluate::ArrayConstructorValues<T> &) { 767f9704f0cSValentin Clement return {}; 768f9704f0cSValentin Clement } 769f9704f0cSValentin Clement template <typename T> 770f9704f0cSValentin Clement RT find(const Fortran::evaluate::ImpliedDo<T> &) { 771f9704f0cSValentin Clement return {}; 772f9704f0cSValentin Clement } 773f9704f0cSValentin Clement RT find(const Fortran::semantics::ParamValue &) { return {}; } 774f9704f0cSValentin Clement RT find(const Fortran::semantics::DerivedTypeSpec &) { return {}; } 775f9704f0cSValentin Clement RT find(const Fortran::evaluate::StructureConstructor &) { return {}; } 776f9704f0cSValentin Clement template <typename D, typename R, typename O> 777f9704f0cSValentin Clement RT find(const Fortran::evaluate::Operation<D, R, O> &op) { 778f9704f0cSValentin Clement (void)find(op.left()); 779f9704f0cSValentin Clement return false; 780f9704f0cSValentin Clement } 781f9704f0cSValentin Clement template <typename D, typename R, typename LO, typename RO> 782f9704f0cSValentin Clement RT find(const Fortran::evaluate::Operation<D, R, LO, RO> &op) { 783f9704f0cSValentin Clement (void)find(op.left()); 784f9704f0cSValentin Clement (void)find(op.right()); 785f9704f0cSValentin Clement return false; 786f9704f0cSValentin Clement } 787f9704f0cSValentin Clement RT find(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x) { 788f9704f0cSValentin Clement (void)find(x.u); 789f9704f0cSValentin Clement return {}; 790f9704f0cSValentin Clement } 791f9704f0cSValentin Clement template <typename T> 792f9704f0cSValentin Clement RT find(const Fortran::evaluate::Expr<T> &x) { 793f9704f0cSValentin Clement (void)find(x.u); 794f9704f0cSValentin Clement return {}; 795f9704f0cSValentin Clement } 796f9704f0cSValentin Clement 797f9704f0cSValentin Clement llvm::SmallVector<Fortran::lower::ExplicitIterSpace::ArrayBases> bases; 798f9704f0cSValentin Clement llvm::SmallVector<Fortran::lower::FrontEndSymbol> controlVars; 799f9704f0cSValentin Clement }; 800f9704f0cSValentin Clement 801f9704f0cSValentin Clement } // namespace 802f9704f0cSValentin Clement 803f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::leave() { 804f9704f0cSValentin Clement ccLoopNest.pop_back(); 805f9704f0cSValentin Clement --forallContextOpen; 806f9704f0cSValentin Clement conditionalCleanup(); 807f9704f0cSValentin Clement } 808f9704f0cSValentin Clement 809f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::addSymbol( 810f9704f0cSValentin Clement Fortran::lower::FrontEndSymbol sym) { 811f9704f0cSValentin Clement assert(!symbolStack.empty()); 812f9704f0cSValentin Clement symbolStack.back().push_back(sym); 813f9704f0cSValentin Clement } 814f9704f0cSValentin Clement 815f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::exprBase(Fortran::lower::FrontEndExpr x, 816f9704f0cSValentin Clement bool lhs) { 817f9704f0cSValentin Clement ArrayBaseFinder finder(collectAllSymbols()); 818f9704f0cSValentin Clement finder(*x); 819f9704f0cSValentin Clement llvm::ArrayRef<Fortran::lower::ExplicitIterSpace::ArrayBases> bases = 820f9704f0cSValentin Clement finder.getBases(); 821f9704f0cSValentin Clement if (rhsBases.empty()) 822f9704f0cSValentin Clement endAssign(); 823f9704f0cSValentin Clement if (lhs) { 824f9704f0cSValentin Clement if (bases.empty()) { 825f9704f0cSValentin Clement lhsBases.push_back(llvm::None); 826f9704f0cSValentin Clement return; 827f9704f0cSValentin Clement } 828f9704f0cSValentin Clement assert(bases.size() >= 1 && "must detect an array reference on lhs"); 829f9704f0cSValentin Clement if (bases.size() > 1) 830f9704f0cSValentin Clement rhsBases.back().append(bases.begin(), bases.end() - 1); 831f9704f0cSValentin Clement lhsBases.push_back(bases.back()); 832f9704f0cSValentin Clement return; 833f9704f0cSValentin Clement } 834f9704f0cSValentin Clement rhsBases.back().append(bases.begin(), bases.end()); 835f9704f0cSValentin Clement } 836f9704f0cSValentin Clement 837f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::endAssign() { rhsBases.emplace_back(); } 838f9704f0cSValentin Clement 839f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::pushLevel() { 840f9704f0cSValentin Clement symbolStack.push_back(llvm::SmallVector<Fortran::lower::FrontEndSymbol>{}); 841f9704f0cSValentin Clement } 842f9704f0cSValentin Clement 843f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::popLevel() { symbolStack.pop_back(); } 844f9704f0cSValentin Clement 845f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::conditionalCleanup() { 846f9704f0cSValentin Clement if (forallContextOpen == 0) { 847f9704f0cSValentin Clement // Exiting the outermost FORALL context. 848f9704f0cSValentin Clement // Cleanup any residual mask buffers. 849f9704f0cSValentin Clement outermostContext().finalize(); 850f9704f0cSValentin Clement // Clear and reset all the cached information. 851f9704f0cSValentin Clement symbolStack.clear(); 852f9704f0cSValentin Clement lhsBases.clear(); 853f9704f0cSValentin Clement rhsBases.clear(); 854f9704f0cSValentin Clement loadBindings.clear(); 855f9704f0cSValentin Clement ccLoopNest.clear(); 856f9704f0cSValentin Clement innerArgs.clear(); 857f9704f0cSValentin Clement outerLoop = llvm::None; 858f9704f0cSValentin Clement clearLoops(); 859f9704f0cSValentin Clement counter = 0; 860f9704f0cSValentin Clement } 861f9704f0cSValentin Clement } 862f9704f0cSValentin Clement 863f9704f0cSValentin Clement llvm::Optional<size_t> 864f9704f0cSValentin Clement Fortran::lower::ExplicitIterSpace::findArgPosition(fir::ArrayLoadOp load) { 865*86b8c1d9SKazu Hirata if (lhsBases[counter]) { 8663b7c3a65SKazu Hirata auto ld = loadBindings.find(lhsBases[counter].getValue()); 867f9704f0cSValentin Clement llvm::Optional<size_t> optPos; 868f9704f0cSValentin Clement if (ld != loadBindings.end() && ld->second == load) 869f9704f0cSValentin Clement optPos = static_cast<size_t>(0u); 8703b7c3a65SKazu Hirata assert(optPos.hasValue() && "load does not correspond to lhs"); 871f9704f0cSValentin Clement return optPos; 872f9704f0cSValentin Clement } 873f9704f0cSValentin Clement return llvm::None; 874f9704f0cSValentin Clement } 875f9704f0cSValentin Clement 876f9704f0cSValentin Clement llvm::SmallVector<Fortran::lower::FrontEndSymbol> 877f9704f0cSValentin Clement Fortran::lower::ExplicitIterSpace::collectAllSymbols() { 878f9704f0cSValentin Clement llvm::SmallVector<Fortran::lower::FrontEndSymbol> result; 879f9704f0cSValentin Clement for (llvm::SmallVector<FrontEndSymbol> vec : symbolStack) 880f9704f0cSValentin Clement result.append(vec.begin(), vec.end()); 881f9704f0cSValentin Clement return result; 882f9704f0cSValentin Clement } 883f9704f0cSValentin Clement 884f9704f0cSValentin Clement llvm::raw_ostream & 885f9704f0cSValentin Clement Fortran::lower::operator<<(llvm::raw_ostream &s, 886f9704f0cSValentin Clement const Fortran::lower::ImplicitIterSpace &e) { 887f9704f0cSValentin Clement for (const llvm::SmallVector< 888f9704f0cSValentin Clement Fortran::lower::ImplicitIterSpace::FrontEndMaskExpr> &xs : 889f9704f0cSValentin Clement e.getMasks()) { 890f9704f0cSValentin Clement s << "{ "; 891f9704f0cSValentin Clement for (const Fortran::lower::ImplicitIterSpace::FrontEndMaskExpr &x : xs) 892f9704f0cSValentin Clement x->AsFortran(s << '(') << "), "; 893f9704f0cSValentin Clement s << "}\n"; 894f9704f0cSValentin Clement } 895f9704f0cSValentin Clement return s; 896f9704f0cSValentin Clement } 897f9704f0cSValentin Clement 898f9704f0cSValentin Clement llvm::raw_ostream & 899f9704f0cSValentin Clement Fortran::lower::operator<<(llvm::raw_ostream &s, 900f9704f0cSValentin Clement const Fortran::lower::ExplicitIterSpace &e) { 901f9704f0cSValentin Clement auto dump = [&](const auto &u) { 902f9704f0cSValentin Clement std::visit(Fortran::common::visitors{ 903f9704f0cSValentin Clement [&](const Fortran::semantics::Symbol *y) { 904f9704f0cSValentin Clement s << " " << *y << '\n'; 905f9704f0cSValentin Clement }, 906f9704f0cSValentin Clement [&](const Fortran::evaluate::ArrayRef *y) { 907f9704f0cSValentin Clement s << " "; 908f9704f0cSValentin Clement if (y->base().IsSymbol()) 909f9704f0cSValentin Clement s << y->base().GetFirstSymbol(); 910f9704f0cSValentin Clement else 911f9704f0cSValentin Clement s << y->base().GetComponent().GetLastSymbol(); 912f9704f0cSValentin Clement s << '\n'; 913f9704f0cSValentin Clement }, 914f9704f0cSValentin Clement [&](const Fortran::evaluate::Component *y) { 915f9704f0cSValentin Clement s << " " << y->GetLastSymbol() << '\n'; 916f9704f0cSValentin Clement }}, 917f9704f0cSValentin Clement u); 918f9704f0cSValentin Clement }; 919f9704f0cSValentin Clement s << "LHS bases:\n"; 920f9704f0cSValentin Clement for (const llvm::Optional<Fortran::lower::ExplicitIterSpace::ArrayBases> &u : 921f9704f0cSValentin Clement e.lhsBases) 922*86b8c1d9SKazu Hirata if (u) 9233b7c3a65SKazu Hirata dump(u.getValue()); 924f9704f0cSValentin Clement s << "RHS bases:\n"; 925f9704f0cSValentin Clement for (const llvm::SmallVector<Fortran::lower::ExplicitIterSpace::ArrayBases> 926f9704f0cSValentin Clement &bases : e.rhsBases) { 927f9704f0cSValentin Clement for (const Fortran::lower::ExplicitIterSpace::ArrayBases &u : bases) 928f9704f0cSValentin Clement dump(u); 929f9704f0cSValentin Clement s << '\n'; 930f9704f0cSValentin Clement } 931f9704f0cSValentin Clement return s; 932f9704f0cSValentin Clement } 933f9704f0cSValentin Clement 934f9704f0cSValentin Clement void Fortran::lower::ImplicitIterSpace::dump() const { 935f9704f0cSValentin Clement llvm::errs() << *this << '\n'; 936f9704f0cSValentin Clement } 937f9704f0cSValentin Clement 938f9704f0cSValentin Clement void Fortran::lower::ExplicitIterSpace::dump() const { 939f9704f0cSValentin Clement llvm::errs() << *this << '\n'; 940f9704f0cSValentin Clement } 941