xref: /llvm-project/flang/lib/Lower/VectorSubscripts.cpp (revision 77d8cfb3c50e3341d65af1f9e442004bbd77af9b)
19aeb7f03SValentin Clement //===-- VectorSubscripts.cpp -- Vector subscripts tools -------------------===//
29aeb7f03SValentin Clement //
39aeb7f03SValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49aeb7f03SValentin Clement // See https://llvm.org/LICENSE.txt for license information.
59aeb7f03SValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69aeb7f03SValentin Clement //
79aeb7f03SValentin Clement //===----------------------------------------------------------------------===//
89aeb7f03SValentin Clement //
99aeb7f03SValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
109aeb7f03SValentin Clement //
119aeb7f03SValentin Clement //===----------------------------------------------------------------------===//
129aeb7f03SValentin Clement 
139aeb7f03SValentin Clement #include "flang/Lower/VectorSubscripts.h"
149aeb7f03SValentin Clement #include "flang/Lower/AbstractConverter.h"
159aeb7f03SValentin Clement #include "flang/Lower/Support/Utils.h"
169aeb7f03SValentin Clement #include "flang/Optimizer/Builder/Character.h"
179aeb7f03SValentin Clement #include "flang/Optimizer/Builder/Complex.h"
189aeb7f03SValentin Clement #include "flang/Optimizer/Builder/FIRBuilder.h"
195b66cc10SValentin Clement #include "flang/Optimizer/Builder/Todo.h"
209aeb7f03SValentin Clement #include "flang/Semantics/expression.h"
219aeb7f03SValentin Clement 
229aeb7f03SValentin Clement namespace {
239aeb7f03SValentin Clement /// Helper class to lower a designator containing vector subscripts into a
249aeb7f03SValentin Clement /// lowered representation that can be worked with.
259aeb7f03SValentin Clement class VectorSubscriptBoxBuilder {
269aeb7f03SValentin Clement public:
VectorSubscriptBoxBuilder(mlir::Location loc,Fortran::lower::AbstractConverter & converter,Fortran::lower::StatementContext & stmtCtx)279aeb7f03SValentin Clement   VectorSubscriptBoxBuilder(mlir::Location loc,
289aeb7f03SValentin Clement                             Fortran::lower::AbstractConverter &converter,
299aeb7f03SValentin Clement                             Fortran::lower::StatementContext &stmtCtx)
309aeb7f03SValentin Clement       : converter{converter}, stmtCtx{stmtCtx}, loc{loc} {}
319aeb7f03SValentin Clement 
gen(const Fortran::lower::SomeExpr & expr)329aeb7f03SValentin Clement   Fortran::lower::VectorSubscriptBox gen(const Fortran::lower::SomeExpr &expr) {
339aeb7f03SValentin Clement     elementType = genDesignator(expr);
349aeb7f03SValentin Clement     return Fortran::lower::VectorSubscriptBox(
359aeb7f03SValentin Clement         std::move(loweredBase), std::move(loweredSubscripts),
369aeb7f03SValentin Clement         std::move(componentPath), substringBounds, elementType);
379aeb7f03SValentin Clement   }
389aeb7f03SValentin Clement 
399aeb7f03SValentin Clement private:
409aeb7f03SValentin Clement   using LoweredVectorSubscript =
419aeb7f03SValentin Clement       Fortran::lower::VectorSubscriptBox::LoweredVectorSubscript;
429aeb7f03SValentin Clement   using LoweredTriplet = Fortran::lower::VectorSubscriptBox::LoweredTriplet;
439aeb7f03SValentin Clement   using LoweredSubscript = Fortran::lower::VectorSubscriptBox::LoweredSubscript;
449aeb7f03SValentin Clement   using MaybeSubstring = Fortran::lower::VectorSubscriptBox::MaybeSubstring;
459aeb7f03SValentin Clement 
469aeb7f03SValentin Clement   /// genDesignator unwraps a Designator<T> and calls `gen` on what the
479aeb7f03SValentin Clement   /// designator actually contains.
489aeb7f03SValentin Clement   template <typename A>
genDesignator(const A &)499aeb7f03SValentin Clement   mlir::Type genDesignator(const A &) {
509aeb7f03SValentin Clement     fir::emitFatalError(loc, "expr must contain a designator");
519aeb7f03SValentin Clement   }
529aeb7f03SValentin Clement   template <typename T>
genDesignator(const Fortran::evaluate::Expr<T> & expr)539aeb7f03SValentin Clement   mlir::Type genDesignator(const Fortran::evaluate::Expr<T> &expr) {
549aeb7f03SValentin Clement     using ExprVariant = decltype(Fortran::evaluate::Expr<T>::u);
559aeb7f03SValentin Clement     using Designator = Fortran::evaluate::Designator<T>;
569aeb7f03SValentin Clement     if constexpr (Fortran::common::HasMember<Designator, ExprVariant>) {
579aeb7f03SValentin Clement       const auto &designator = std::get<Designator>(expr.u);
58*77d8cfb3SAlexander Shaposhnikov       return Fortran::common::visit([&](const auto &x) { return gen(x); },
59*77d8cfb3SAlexander Shaposhnikov                                     designator.u);
609aeb7f03SValentin Clement     } else {
61*77d8cfb3SAlexander Shaposhnikov       return Fortran::common::visit(
62*77d8cfb3SAlexander Shaposhnikov           [&](const auto &x) { return genDesignator(x); }, expr.u);
639aeb7f03SValentin Clement     }
649aeb7f03SValentin Clement   }
659aeb7f03SValentin Clement 
669aeb7f03SValentin Clement   // The gen(X) methods visit X to lower its base and subscripts and return the
679aeb7f03SValentin Clement   // type of X elements.
689aeb7f03SValentin Clement 
gen(const Fortran::evaluate::DataRef & dataRef)699aeb7f03SValentin Clement   mlir::Type gen(const Fortran::evaluate::DataRef &dataRef) {
70*77d8cfb3SAlexander Shaposhnikov     return Fortran::common::visit(
71*77d8cfb3SAlexander Shaposhnikov         [&](const auto &ref) -> mlir::Type { return gen(ref); }, dataRef.u);
729aeb7f03SValentin Clement   }
739aeb7f03SValentin Clement 
gen(const Fortran::evaluate::SymbolRef & symRef)749aeb7f03SValentin Clement   mlir::Type gen(const Fortran::evaluate::SymbolRef &symRef) {
759aeb7f03SValentin Clement     // Never visited because expr lowering is used to lowered the ranked
769aeb7f03SValentin Clement     // ArrayRef.
779aeb7f03SValentin Clement     fir::emitFatalError(
789aeb7f03SValentin Clement         loc, "expected at least one ArrayRef with vector susbcripts");
799aeb7f03SValentin Clement   }
809aeb7f03SValentin Clement 
gen(const Fortran::evaluate::Substring & substring)819aeb7f03SValentin Clement   mlir::Type gen(const Fortran::evaluate::Substring &substring) {
829aeb7f03SValentin Clement     // StaticDataObject::Pointer bases are constants and cannot be
839aeb7f03SValentin Clement     // subscripted, so the base must be a DataRef here.
849aeb7f03SValentin Clement     mlir::Type baseElementType =
859aeb7f03SValentin Clement         gen(std::get<Fortran::evaluate::DataRef>(substring.parent()));
869aeb7f03SValentin Clement     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
879aeb7f03SValentin Clement     mlir::Type idxTy = builder.getIndexType();
889aeb7f03SValentin Clement     mlir::Value lb = genScalarValue(substring.lower());
899aeb7f03SValentin Clement     substringBounds.emplace_back(builder.createConvert(loc, idxTy, lb));
909aeb7f03SValentin Clement     if (const auto &ubExpr = substring.upper()) {
919aeb7f03SValentin Clement       mlir::Value ub = genScalarValue(*ubExpr);
929aeb7f03SValentin Clement       substringBounds.emplace_back(builder.createConvert(loc, idxTy, ub));
939aeb7f03SValentin Clement     }
949aeb7f03SValentin Clement     return baseElementType;
959aeb7f03SValentin Clement   }
969aeb7f03SValentin Clement 
gen(const Fortran::evaluate::ComplexPart & complexPart)979aeb7f03SValentin Clement   mlir::Type gen(const Fortran::evaluate::ComplexPart &complexPart) {
989aeb7f03SValentin Clement     auto complexType = gen(complexPart.complex());
999aeb7f03SValentin Clement     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1009aeb7f03SValentin Clement     mlir::Type i32Ty = builder.getI32Type(); // llvm's GEP requires i32
1019aeb7f03SValentin Clement     mlir::Value offset = builder.createIntegerConstant(
1029aeb7f03SValentin Clement         loc, i32Ty,
1039aeb7f03SValentin Clement         complexPart.part() == Fortran::evaluate::ComplexPart::Part::RE ? 0 : 1);
1049aeb7f03SValentin Clement     componentPath.emplace_back(offset);
1059aeb7f03SValentin Clement     return fir::factory::Complex{builder, loc}.getComplexPartType(complexType);
1069aeb7f03SValentin Clement   }
1079aeb7f03SValentin Clement 
gen(const Fortran::evaluate::Component & component)1089aeb7f03SValentin Clement   mlir::Type gen(const Fortran::evaluate::Component &component) {
109fac349a1SChristian Sigg     auto recTy = mlir::cast<fir::RecordType>(gen(component.base()));
1109aeb7f03SValentin Clement     const Fortran::semantics::Symbol &componentSymbol =
1119aeb7f03SValentin Clement         component.GetLastSymbol();
1129aeb7f03SValentin Clement     // Parent components will not be found here, they are not part
1139aeb7f03SValentin Clement     // of the FIR type and cannot be used in the path yet.
1149aeb7f03SValentin Clement     if (componentSymbol.test(Fortran::semantics::Symbol::Flag::ParentComp))
115331145e6SValentin Clement       TODO(loc, "reference to parent component");
1169aeb7f03SValentin Clement     mlir::Type fldTy = fir::FieldType::get(&converter.getMLIRContext());
1179aeb7f03SValentin Clement     llvm::StringRef componentName = toStringRef(componentSymbol.name());
1189aeb7f03SValentin Clement     // Parameters threading in field_index is not yet very clear. We only
1199aeb7f03SValentin Clement     // have the ones of the ranked array ref at hand, but it looks like
1209aeb7f03SValentin Clement     // the fir.field_index expects the one of the direct base.
1219aeb7f03SValentin Clement     if (recTy.getNumLenParams() != 0)
1229aeb7f03SValentin Clement       TODO(loc, "threading length parameters in field index op");
1239aeb7f03SValentin Clement     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1249aeb7f03SValentin Clement     componentPath.emplace_back(builder.create<fir::FieldIndexOp>(
1259a417395SKazu Hirata         loc, fldTy, componentName, recTy, /*typeParams*/ std::nullopt));
1269aeb7f03SValentin Clement     return fir::unwrapSequenceType(recTy.getType(componentName));
1279aeb7f03SValentin Clement   }
1289aeb7f03SValentin Clement 
gen(const Fortran::evaluate::ArrayRef & arrayRef)1299aeb7f03SValentin Clement   mlir::Type gen(const Fortran::evaluate::ArrayRef &arrayRef) {
1309aeb7f03SValentin Clement     auto isTripletOrVector =
1319aeb7f03SValentin Clement         [](const Fortran::evaluate::Subscript &subscript) -> bool {
132*77d8cfb3SAlexander Shaposhnikov       return Fortran::common::visit(
1339aeb7f03SValentin Clement           Fortran::common::visitors{
1349aeb7f03SValentin Clement               [](const Fortran::evaluate::IndirectSubscriptIntegerExpr &expr) {
1359aeb7f03SValentin Clement                 return expr.value().Rank() != 0;
1369aeb7f03SValentin Clement               },
1379aeb7f03SValentin Clement               [&](const Fortran::evaluate::Triplet &) { return true; }},
1389aeb7f03SValentin Clement           subscript.u);
1399aeb7f03SValentin Clement     };
1409aeb7f03SValentin Clement     if (llvm::any_of(arrayRef.subscript(), isTripletOrVector))
1419aeb7f03SValentin Clement       return genRankedArrayRefSubscriptAndBase(arrayRef);
1429aeb7f03SValentin Clement 
1439aeb7f03SValentin Clement     // This is a scalar ArrayRef (only scalar indexes), collect the indexes and
1449aeb7f03SValentin Clement     // visit the base that must contain another arrayRef with the vector
1459aeb7f03SValentin Clement     // subscript.
1469aeb7f03SValentin Clement     mlir::Type elementType = gen(namedEntityToDataRef(arrayRef.base()));
1479aeb7f03SValentin Clement     for (const Fortran::evaluate::Subscript &subscript : arrayRef.subscript()) {
1489aeb7f03SValentin Clement       const auto &expr =
1499aeb7f03SValentin Clement           std::get<Fortran::evaluate::IndirectSubscriptIntegerExpr>(
1509aeb7f03SValentin Clement               subscript.u);
1519aeb7f03SValentin Clement       componentPath.emplace_back(genScalarValue(expr.value()));
1529aeb7f03SValentin Clement     }
1539aeb7f03SValentin Clement     return elementType;
1549aeb7f03SValentin Clement   }
1559aeb7f03SValentin Clement 
1569aeb7f03SValentin Clement   /// Lower the subscripts and base of the ArrayRef that is an array (there must
1579aeb7f03SValentin Clement   /// be one since there is a vector subscript, and there can only be one
1589aeb7f03SValentin Clement   /// according to C925).
genRankedArrayRefSubscriptAndBase(const Fortran::evaluate::ArrayRef & arrayRef)1599aeb7f03SValentin Clement   mlir::Type genRankedArrayRefSubscriptAndBase(
1609aeb7f03SValentin Clement       const Fortran::evaluate::ArrayRef &arrayRef) {
1619aeb7f03SValentin Clement     // Lower the save the base
1629aeb7f03SValentin Clement     Fortran::lower::SomeExpr baseExpr = namedEntityToExpr(arrayRef.base());
1639aeb7f03SValentin Clement     loweredBase = converter.genExprAddr(baseExpr, stmtCtx);
1649aeb7f03SValentin Clement     // Lower and save the subscripts
1659aeb7f03SValentin Clement     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
1669aeb7f03SValentin Clement     mlir::Type idxTy = builder.getIndexType();
1679aeb7f03SValentin Clement     mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
1689aeb7f03SValentin Clement     for (const auto &subscript : llvm::enumerate(arrayRef.subscript())) {
169*77d8cfb3SAlexander Shaposhnikov       Fortran::common::visit(
1709aeb7f03SValentin Clement           Fortran::common::visitors{
1719aeb7f03SValentin Clement               [&](const Fortran::evaluate::IndirectSubscriptIntegerExpr &expr) {
1729aeb7f03SValentin Clement                 if (expr.value().Rank() == 0) {
1739aeb7f03SValentin Clement                   // Simple scalar subscript
1749aeb7f03SValentin Clement                   loweredSubscripts.emplace_back(genScalarValue(expr.value()));
1759aeb7f03SValentin Clement                 } else {
1769aeb7f03SValentin Clement                   // Vector subscript.
1779aeb7f03SValentin Clement                   // Remove conversion if any to avoid temp creation that may
1789aeb7f03SValentin Clement                   // have been added by the front-end to avoid the creation of a
1799aeb7f03SValentin Clement                   // temp array value.
1809aeb7f03SValentin Clement                   auto vector = converter.genExprAddr(
1819aeb7f03SValentin Clement                       ignoreEvConvert(expr.value()), stmtCtx);
1829aeb7f03SValentin Clement                   mlir::Value size =
1839aeb7f03SValentin Clement                       fir::factory::readExtent(builder, loc, vector, /*dim=*/0);
1849aeb7f03SValentin Clement                   size = builder.createConvert(loc, idxTy, size);
1859aeb7f03SValentin Clement                   loweredSubscripts.emplace_back(
1869aeb7f03SValentin Clement                       LoweredVectorSubscript{std::move(vector), size});
1879aeb7f03SValentin Clement                 }
1889aeb7f03SValentin Clement               },
1899aeb7f03SValentin Clement               [&](const Fortran::evaluate::Triplet &triplet) {
1909aeb7f03SValentin Clement                 mlir::Value lb, ub;
1919aeb7f03SValentin Clement                 if (const auto &lbExpr = triplet.lower())
1929aeb7f03SValentin Clement                   lb = genScalarValue(*lbExpr);
1939aeb7f03SValentin Clement                 else
1949aeb7f03SValentin Clement                   lb = fir::factory::readLowerBound(builder, loc, loweredBase,
1959aeb7f03SValentin Clement                                                     subscript.index(), one);
1969aeb7f03SValentin Clement                 if (const auto &ubExpr = triplet.upper())
1979aeb7f03SValentin Clement                   ub = genScalarValue(*ubExpr);
1989aeb7f03SValentin Clement                 else
1999aeb7f03SValentin Clement                   ub = fir::factory::readExtent(builder, loc, loweredBase,
2009aeb7f03SValentin Clement                                                 subscript.index());
2019aeb7f03SValentin Clement                 lb = builder.createConvert(loc, idxTy, lb);
2029aeb7f03SValentin Clement                 ub = builder.createConvert(loc, idxTy, ub);
2039aeb7f03SValentin Clement                 mlir::Value stride = genScalarValue(triplet.stride());
2049aeb7f03SValentin Clement                 stride = builder.createConvert(loc, idxTy, stride);
2059aeb7f03SValentin Clement                 loweredSubscripts.emplace_back(LoweredTriplet{lb, ub, stride});
2069aeb7f03SValentin Clement               },
2079aeb7f03SValentin Clement           },
2089aeb7f03SValentin Clement           subscript.value().u);
2099aeb7f03SValentin Clement     }
2109aeb7f03SValentin Clement     return fir::unwrapSequenceType(
2119aeb7f03SValentin Clement         fir::unwrapPassByRefType(fir::getBase(loweredBase).getType()));
2129aeb7f03SValentin Clement   }
2139aeb7f03SValentin Clement 
gen(const Fortran::evaluate::CoarrayRef &)2149aeb7f03SValentin Clement   mlir::Type gen(const Fortran::evaluate::CoarrayRef &) {
2159aeb7f03SValentin Clement     // Is this possible/legal ?
2165db4779cSPete Steinfeld     TODO(loc, "coarray: reference to coarray object with vector subscript in "
2175db4779cSPete Steinfeld               "IO input");
2189aeb7f03SValentin Clement   }
2199aeb7f03SValentin Clement 
2209aeb7f03SValentin Clement   template <typename A>
genScalarValue(const A & expr)2219aeb7f03SValentin Clement   mlir::Value genScalarValue(const A &expr) {
2229aeb7f03SValentin Clement     return fir::getBase(converter.genExprValue(toEvExpr(expr), stmtCtx));
2239aeb7f03SValentin Clement   }
2249aeb7f03SValentin Clement 
2259aeb7f03SValentin Clement   Fortran::evaluate::DataRef
namedEntityToDataRef(const Fortran::evaluate::NamedEntity & namedEntity)2269aeb7f03SValentin Clement   namedEntityToDataRef(const Fortran::evaluate::NamedEntity &namedEntity) {
2279aeb7f03SValentin Clement     if (namedEntity.IsSymbol())
2289aeb7f03SValentin Clement       return Fortran::evaluate::DataRef{namedEntity.GetFirstSymbol()};
2299aeb7f03SValentin Clement     return Fortran::evaluate::DataRef{namedEntity.GetComponent()};
2309aeb7f03SValentin Clement   }
2319aeb7f03SValentin Clement 
2329aeb7f03SValentin Clement   Fortran::lower::SomeExpr
namedEntityToExpr(const Fortran::evaluate::NamedEntity & namedEntity)2339aeb7f03SValentin Clement   namedEntityToExpr(const Fortran::evaluate::NamedEntity &namedEntity) {
2349aeb7f03SValentin Clement     return Fortran::evaluate::AsGenericExpr(namedEntityToDataRef(namedEntity))
2359aeb7f03SValentin Clement         .value();
2369aeb7f03SValentin Clement   }
2379aeb7f03SValentin Clement 
2389aeb7f03SValentin Clement   Fortran::lower::AbstractConverter &converter;
2399aeb7f03SValentin Clement   Fortran::lower::StatementContext &stmtCtx;
2409aeb7f03SValentin Clement   mlir::Location loc;
2419aeb7f03SValentin Clement   /// Elements of VectorSubscriptBox being built.
2429aeb7f03SValentin Clement   fir::ExtendedValue loweredBase;
2439aeb7f03SValentin Clement   llvm::SmallVector<LoweredSubscript, 16> loweredSubscripts;
2449aeb7f03SValentin Clement   llvm::SmallVector<mlir::Value> componentPath;
2459aeb7f03SValentin Clement   MaybeSubstring substringBounds;
2469aeb7f03SValentin Clement   mlir::Type elementType;
2479aeb7f03SValentin Clement };
2489aeb7f03SValentin Clement } // namespace
2499aeb7f03SValentin Clement 
genVectorSubscriptBox(mlir::Location loc,Fortran::lower::AbstractConverter & converter,Fortran::lower::StatementContext & stmtCtx,const Fortran::lower::SomeExpr & expr)2509aeb7f03SValentin Clement Fortran::lower::VectorSubscriptBox Fortran::lower::genVectorSubscriptBox(
2519aeb7f03SValentin Clement     mlir::Location loc, Fortran::lower::AbstractConverter &converter,
2529aeb7f03SValentin Clement     Fortran::lower::StatementContext &stmtCtx,
2539aeb7f03SValentin Clement     const Fortran::lower::SomeExpr &expr) {
2549aeb7f03SValentin Clement   return VectorSubscriptBoxBuilder(loc, converter, stmtCtx).gen(expr);
2559aeb7f03SValentin Clement }
2569aeb7f03SValentin Clement 
2579aeb7f03SValentin Clement template <typename LoopType, typename Generator>
loopOverElementsBase(fir::FirOpBuilder & builder,mlir::Location loc,const Generator & elementalGenerator,mlir::Value initialCondition)2589aeb7f03SValentin Clement mlir::Value Fortran::lower::VectorSubscriptBox::loopOverElementsBase(
2599aeb7f03SValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc,
2609aeb7f03SValentin Clement     const Generator &elementalGenerator,
2619aeb7f03SValentin Clement     [[maybe_unused]] mlir::Value initialCondition) {
2629aeb7f03SValentin Clement   mlir::Value shape = builder.createShape(loc, loweredBase);
2639aeb7f03SValentin Clement   mlir::Value slice = createSlice(builder, loc);
2649aeb7f03SValentin Clement 
2659aeb7f03SValentin Clement   // Create loop nest for triplets and vector subscripts in column
2669aeb7f03SValentin Clement   // major order.
2679aeb7f03SValentin Clement   llvm::SmallVector<mlir::Value> inductionVariables;
2689aeb7f03SValentin Clement   LoopType outerLoop;
2699aeb7f03SValentin Clement   for (auto [lb, ub, step] : genLoopBounds(builder, loc)) {
2709aeb7f03SValentin Clement     LoopType loop;
2719aeb7f03SValentin Clement     if constexpr (std::is_same_v<LoopType, fir::IterWhileOp>) {
2729aeb7f03SValentin Clement       loop =
2739aeb7f03SValentin Clement           builder.create<fir::IterWhileOp>(loc, lb, ub, step, initialCondition);
2749aeb7f03SValentin Clement       initialCondition = loop.getIterateVar();
2759aeb7f03SValentin Clement       if (!outerLoop)
2769aeb7f03SValentin Clement         outerLoop = loop;
2779aeb7f03SValentin Clement       else
2789aeb7f03SValentin Clement         builder.create<fir::ResultOp>(loc, loop.getResult(0));
2799aeb7f03SValentin Clement     } else {
2809aeb7f03SValentin Clement       loop =
2819aeb7f03SValentin Clement           builder.create<fir::DoLoopOp>(loc, lb, ub, step, /*unordered=*/false);
2829aeb7f03SValentin Clement       if (!outerLoop)
2839aeb7f03SValentin Clement         outerLoop = loop;
2849aeb7f03SValentin Clement     }
2859aeb7f03SValentin Clement     builder.setInsertionPointToStart(loop.getBody());
2869aeb7f03SValentin Clement     inductionVariables.push_back(loop.getInductionVar());
2879aeb7f03SValentin Clement   }
2889aeb7f03SValentin Clement   assert(outerLoop && !inductionVariables.empty() &&
2899aeb7f03SValentin Clement          "at least one loop should be created");
2909aeb7f03SValentin Clement 
2919aeb7f03SValentin Clement   fir::ExtendedValue elem =
2929aeb7f03SValentin Clement       getElementAt(builder, loc, shape, slice, inductionVariables);
2939aeb7f03SValentin Clement 
2949aeb7f03SValentin Clement   if constexpr (std::is_same_v<LoopType, fir::IterWhileOp>) {
2959aeb7f03SValentin Clement     auto res = elementalGenerator(elem);
2969aeb7f03SValentin Clement     builder.create<fir::ResultOp>(loc, res);
2979aeb7f03SValentin Clement     builder.setInsertionPointAfter(outerLoop);
2989aeb7f03SValentin Clement     return outerLoop.getResult(0);
2999aeb7f03SValentin Clement   } else {
3009aeb7f03SValentin Clement     elementalGenerator(elem);
3019aeb7f03SValentin Clement     builder.setInsertionPointAfter(outerLoop);
3029aeb7f03SValentin Clement     return {};
3039aeb7f03SValentin Clement   }
3049aeb7f03SValentin Clement }
3059aeb7f03SValentin Clement 
loopOverElements(fir::FirOpBuilder & builder,mlir::Location loc,const ElementalGenerator & elementalGenerator)3069aeb7f03SValentin Clement void Fortran::lower::VectorSubscriptBox::loopOverElements(
3079aeb7f03SValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc,
3089aeb7f03SValentin Clement     const ElementalGenerator &elementalGenerator) {
3099aeb7f03SValentin Clement   mlir::Value initialCondition;
3109aeb7f03SValentin Clement   loopOverElementsBase<fir::DoLoopOp, ElementalGenerator>(
3119aeb7f03SValentin Clement       builder, loc, elementalGenerator, initialCondition);
3129aeb7f03SValentin Clement }
3139aeb7f03SValentin Clement 
loopOverElementsWhile(fir::FirOpBuilder & builder,mlir::Location loc,const ElementalGeneratorWithBoolReturn & elementalGenerator,mlir::Value initialCondition)3149aeb7f03SValentin Clement mlir::Value Fortran::lower::VectorSubscriptBox::loopOverElementsWhile(
3159aeb7f03SValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc,
3169aeb7f03SValentin Clement     const ElementalGeneratorWithBoolReturn &elementalGenerator,
3179aeb7f03SValentin Clement     mlir::Value initialCondition) {
3189aeb7f03SValentin Clement   return loopOverElementsBase<fir::IterWhileOp,
3199aeb7f03SValentin Clement                               ElementalGeneratorWithBoolReturn>(
3209aeb7f03SValentin Clement       builder, loc, elementalGenerator, initialCondition);
3219aeb7f03SValentin Clement }
3229aeb7f03SValentin Clement 
3239aeb7f03SValentin Clement mlir::Value
createSlice(fir::FirOpBuilder & builder,mlir::Location loc)3249aeb7f03SValentin Clement Fortran::lower::VectorSubscriptBox::createSlice(fir::FirOpBuilder &builder,
3259aeb7f03SValentin Clement                                                 mlir::Location loc) {
3269aeb7f03SValentin Clement   mlir::Type idxTy = builder.getIndexType();
3279aeb7f03SValentin Clement   llvm::SmallVector<mlir::Value> triples;
3289aeb7f03SValentin Clement   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
3299aeb7f03SValentin Clement   auto undef = builder.create<fir::UndefOp>(loc, idxTy);
3309aeb7f03SValentin Clement   for (const LoweredSubscript &subscript : loweredSubscripts)
331*77d8cfb3SAlexander Shaposhnikov     Fortran::common::visit(Fortran::common::visitors{
3329aeb7f03SValentin Clement                                [&](const LoweredTriplet &triplet) {
3339aeb7f03SValentin Clement                                  triples.emplace_back(triplet.lb);
3349aeb7f03SValentin Clement                                  triples.emplace_back(triplet.ub);
3359aeb7f03SValentin Clement                                  triples.emplace_back(triplet.stride);
3369aeb7f03SValentin Clement                                },
3379aeb7f03SValentin Clement                                [&](const LoweredVectorSubscript &vector) {
3389aeb7f03SValentin Clement                                  triples.emplace_back(one);
3399aeb7f03SValentin Clement                                  triples.emplace_back(vector.size);
3409aeb7f03SValentin Clement                                  triples.emplace_back(one);
3419aeb7f03SValentin Clement                                },
3429aeb7f03SValentin Clement                                [&](const mlir::Value &i) {
3439aeb7f03SValentin Clement                                  triples.emplace_back(i);
3449aeb7f03SValentin Clement                                  triples.emplace_back(undef);
3459aeb7f03SValentin Clement                                  triples.emplace_back(undef);
3469aeb7f03SValentin Clement                                },
3479aeb7f03SValentin Clement                            },
3489aeb7f03SValentin Clement                            subscript);
3499aeb7f03SValentin Clement   return builder.create<fir::SliceOp>(loc, triples, componentPath);
3509aeb7f03SValentin Clement }
3519aeb7f03SValentin Clement 
3529aeb7f03SValentin Clement llvm::SmallVector<std::tuple<mlir::Value, mlir::Value, mlir::Value>>
genLoopBounds(fir::FirOpBuilder & builder,mlir::Location loc)3539aeb7f03SValentin Clement Fortran::lower::VectorSubscriptBox::genLoopBounds(fir::FirOpBuilder &builder,
3549aeb7f03SValentin Clement                                                   mlir::Location loc) {
3559aeb7f03SValentin Clement   mlir::Type idxTy = builder.getIndexType();
3569aeb7f03SValentin Clement   mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
3579aeb7f03SValentin Clement   mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
3589aeb7f03SValentin Clement   llvm::SmallVector<std::tuple<mlir::Value, mlir::Value, mlir::Value>> bounds;
3599aeb7f03SValentin Clement   size_t dimension = loweredSubscripts.size();
3609aeb7f03SValentin Clement   for (const LoweredSubscript &subscript : llvm::reverse(loweredSubscripts)) {
3619aeb7f03SValentin Clement     --dimension;
3629aeb7f03SValentin Clement     if (std::holds_alternative<mlir::Value>(subscript))
3639aeb7f03SValentin Clement       continue;
3649aeb7f03SValentin Clement     mlir::Value lb, ub, step;
3659aeb7f03SValentin Clement     if (const auto *triplet = std::get_if<LoweredTriplet>(&subscript)) {
3669aeb7f03SValentin Clement       mlir::Value extent = builder.genExtentFromTriplet(
3679aeb7f03SValentin Clement           loc, triplet->lb, triplet->ub, triplet->stride, idxTy);
3689aeb7f03SValentin Clement       mlir::Value baseLb = fir::factory::readLowerBound(
3699aeb7f03SValentin Clement           builder, loc, loweredBase, dimension, one);
3709aeb7f03SValentin Clement       baseLb = builder.createConvert(loc, idxTy, baseLb);
3719aeb7f03SValentin Clement       lb = baseLb;
3729aeb7f03SValentin Clement       ub = builder.create<mlir::arith::SubIOp>(loc, idxTy, extent, one);
3739aeb7f03SValentin Clement       ub = builder.create<mlir::arith::AddIOp>(loc, idxTy, ub, baseLb);
3749aeb7f03SValentin Clement       step = one;
3759aeb7f03SValentin Clement     } else {
3769aeb7f03SValentin Clement       const auto &vector = std::get<LoweredVectorSubscript>(subscript);
3779aeb7f03SValentin Clement       lb = zero;
3789aeb7f03SValentin Clement       ub = builder.create<mlir::arith::SubIOp>(loc, idxTy, vector.size, one);
3799aeb7f03SValentin Clement       step = one;
3809aeb7f03SValentin Clement     }
3819aeb7f03SValentin Clement     bounds.emplace_back(lb, ub, step);
3829aeb7f03SValentin Clement   }
3839aeb7f03SValentin Clement   return bounds;
3849aeb7f03SValentin Clement }
3859aeb7f03SValentin Clement 
getElementAt(fir::FirOpBuilder & builder,mlir::Location loc,mlir::Value shape,mlir::Value slice,mlir::ValueRange inductionVariables)3869aeb7f03SValentin Clement fir::ExtendedValue Fortran::lower::VectorSubscriptBox::getElementAt(
3879aeb7f03SValentin Clement     fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value shape,
3889aeb7f03SValentin Clement     mlir::Value slice, mlir::ValueRange inductionVariables) {
3899aeb7f03SValentin Clement   /// Generate the indexes for the array_coor inside the loops.
3909aeb7f03SValentin Clement   mlir::Type idxTy = builder.getIndexType();
3919aeb7f03SValentin Clement   llvm::SmallVector<mlir::Value> indexes;
3929aeb7f03SValentin Clement   size_t inductionIdx = inductionVariables.size() - 1;
3939aeb7f03SValentin Clement   for (const LoweredSubscript &subscript : loweredSubscripts)
394*77d8cfb3SAlexander Shaposhnikov     Fortran::common::visit(
395*77d8cfb3SAlexander Shaposhnikov         Fortran::common::visitors{
3969aeb7f03SValentin Clement             [&](const LoweredTriplet &triplet) {
3979aeb7f03SValentin Clement               indexes.emplace_back(inductionVariables[inductionIdx--]);
3989aeb7f03SValentin Clement             },
3999aeb7f03SValentin Clement             [&](const LoweredVectorSubscript &vector) {
4009aeb7f03SValentin Clement               mlir::Value vecIndex = inductionVariables[inductionIdx--];
4019aeb7f03SValentin Clement               mlir::Value vecBase = fir::getBase(vector.vector);
4029aeb7f03SValentin Clement               mlir::Type vecEleTy = fir::unwrapSequenceType(
4039aeb7f03SValentin Clement                   fir::unwrapPassByRefType(vecBase.getType()));
4049aeb7f03SValentin Clement               mlir::Type refTy = builder.getRefType(vecEleTy);
4059aeb7f03SValentin Clement               auto vecEltRef = builder.create<fir::CoordinateOp>(
4069aeb7f03SValentin Clement                   loc, refTy, vecBase, vecIndex);
4079aeb7f03SValentin Clement               auto vecElt =
4089aeb7f03SValentin Clement                   builder.create<fir::LoadOp>(loc, vecEleTy, vecEltRef);
409*77d8cfb3SAlexander Shaposhnikov               indexes.emplace_back(builder.createConvert(loc, idxTy, vecElt));
4109aeb7f03SValentin Clement             },
4119aeb7f03SValentin Clement             [&](const mlir::Value &i) {
4129aeb7f03SValentin Clement               indexes.emplace_back(builder.createConvert(loc, idxTy, i));
4139aeb7f03SValentin Clement             },
4149aeb7f03SValentin Clement         },
4159aeb7f03SValentin Clement         subscript);
4169aeb7f03SValentin Clement   mlir::Type refTy = builder.getRefType(getElementType());
4179aeb7f03SValentin Clement   auto elementAddr = builder.create<fir::ArrayCoorOp>(
4189aeb7f03SValentin Clement       loc, refTy, fir::getBase(loweredBase), shape, slice, indexes,
4199aeb7f03SValentin Clement       fir::getTypeParams(loweredBase));
4209aeb7f03SValentin Clement   fir::ExtendedValue element = fir::factory::arraySectionElementToExtendedValue(
4219aeb7f03SValentin Clement       builder, loc, loweredBase, elementAddr, slice);
4229aeb7f03SValentin Clement   if (!substringBounds.empty()) {
4239aeb7f03SValentin Clement     const fir::CharBoxValue *charBox = element.getCharBox();
4249aeb7f03SValentin Clement     assert(charBox && "substring requires CharBox base");
4259aeb7f03SValentin Clement     fir::factory::CharacterExprHelper helper{builder, loc};
4269aeb7f03SValentin Clement     return helper.createSubstring(*charBox, substringBounds);
4279aeb7f03SValentin Clement   }
4289aeb7f03SValentin Clement   return element;
4299aeb7f03SValentin Clement }
430