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