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