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