brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.8 KiB · 4d1d6fb Raw
431 lines · cpp
1//===-- VectorSubscripts.cpp -- Vector subscripts tools -------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12 13#include "flang/Lower/VectorSubscripts.h"14#include "flang/Lower/AbstractConverter.h"15#include "flang/Lower/Support/Utils.h"16#include "flang/Optimizer/Builder/Character.h"17#include "flang/Optimizer/Builder/Complex.h"18#include "flang/Optimizer/Builder/FIRBuilder.h"19#include "flang/Optimizer/Builder/Todo.h"20#include "flang/Semantics/expression.h"21 22namespace {23/// Helper class to lower a designator containing vector subscripts into a24/// lowered representation that can be worked with.25class VectorSubscriptBoxBuilder {26public:27  VectorSubscriptBoxBuilder(mlir::Location loc,28                            Fortran::lower::AbstractConverter &converter,29                            Fortran::lower::StatementContext &stmtCtx)30      : converter{converter}, stmtCtx{stmtCtx}, loc{loc} {}31 32  Fortran::lower::VectorSubscriptBox gen(const Fortran::lower::SomeExpr &expr) {33    elementType = genDesignator(expr);34    return Fortran::lower::VectorSubscriptBox(35        std::move(loweredBase), std::move(loweredSubscripts),36        std::move(componentPath), substringBounds, elementType);37  }38 39private:40  using LoweredVectorSubscript =41      Fortran::lower::VectorSubscriptBox::LoweredVectorSubscript;42  using LoweredTriplet = Fortran::lower::VectorSubscriptBox::LoweredTriplet;43  using LoweredSubscript = Fortran::lower::VectorSubscriptBox::LoweredSubscript;44  using MaybeSubstring = Fortran::lower::VectorSubscriptBox::MaybeSubstring;45 46  /// genDesignator unwraps a Designator<T> and calls `gen` on what the47  /// designator actually contains.48  template <typename A>49  mlir::Type genDesignator(const A &) {50    fir::emitFatalError(loc, "expr must contain a designator");51  }52  template <typename T>53  mlir::Type genDesignator(const Fortran::evaluate::Expr<T> &expr) {54    using ExprVariant = decltype(Fortran::evaluate::Expr<T>::u);55    using Designator = Fortran::evaluate::Designator<T>;56    if constexpr (Fortran::common::HasMember<Designator, ExprVariant>) {57      const auto &designator = std::get<Designator>(expr.u);58      return Fortran::common::visit([&](const auto &x) { return gen(x); },59                                    designator.u);60    } else {61      return Fortran::common::visit(62          [&](const auto &x) { return genDesignator(x); }, expr.u);63    }64  }65 66  // The gen(X) methods visit X to lower its base and subscripts and return the67  // type of X elements.68 69  mlir::Type gen(const Fortran::evaluate::DataRef &dataRef) {70    return Fortran::common::visit(71        [&](const auto &ref) -> mlir::Type { return gen(ref); }, dataRef.u);72  }73 74  mlir::Type gen(const Fortran::evaluate::SymbolRef &symRef) {75    // Never visited because expr lowering is used to lowered the ranked76    // ArrayRef.77    fir::emitFatalError(78        loc, "expected at least one ArrayRef with vector susbcripts");79  }80 81  mlir::Type gen(const Fortran::evaluate::Substring &substring) {82    // StaticDataObject::Pointer bases are constants and cannot be83    // subscripted, so the base must be a DataRef here.84    mlir::Type baseElementType =85        gen(std::get<Fortran::evaluate::DataRef>(substring.parent()));86    fir::FirOpBuilder &builder = converter.getFirOpBuilder();87    mlir::Type idxTy = builder.getIndexType();88    mlir::Value lb = genScalarValue(substring.lower());89    substringBounds.emplace_back(builder.createConvert(loc, idxTy, lb));90    if (const auto &ubExpr = substring.upper()) {91      mlir::Value ub = genScalarValue(*ubExpr);92      substringBounds.emplace_back(builder.createConvert(loc, idxTy, ub));93    }94    return baseElementType;95  }96 97  mlir::Type gen(const Fortran::evaluate::ComplexPart &complexPart) {98    auto complexType = gen(complexPart.complex());99    fir::FirOpBuilder &builder = converter.getFirOpBuilder();100    mlir::Type i32Ty = builder.getI32Type(); // llvm's GEP requires i32101    mlir::Value offset = builder.createIntegerConstant(102        loc, i32Ty,103        complexPart.part() == Fortran::evaluate::ComplexPart::Part::RE ? 0 : 1);104    componentPath.emplace_back(offset);105    return fir::factory::Complex{builder, loc}.getComplexPartType(complexType);106  }107 108  mlir::Type gen(const Fortran::evaluate::Component &component) {109    auto recTy = mlir::cast<fir::RecordType>(gen(component.base()));110    const Fortran::semantics::Symbol &componentSymbol =111        component.GetLastSymbol();112    // Parent components will not be found here, they are not part113    // of the FIR type and cannot be used in the path yet.114    if (componentSymbol.test(Fortran::semantics::Symbol::Flag::ParentComp))115      TODO(loc, "reference to parent component");116    mlir::Type fldTy = fir::FieldType::get(&converter.getMLIRContext());117    llvm::StringRef componentName = toStringRef(componentSymbol.name());118    // Parameters threading in field_index is not yet very clear. We only119    // have the ones of the ranked array ref at hand, but it looks like120    // the fir.field_index expects the one of the direct base.121    if (recTy.getNumLenParams() != 0)122      TODO(loc, "threading length parameters in field index op");123    fir::FirOpBuilder &builder = converter.getFirOpBuilder();124    componentPath.emplace_back(125        fir::FieldIndexOp::create(builder, loc, fldTy, componentName, recTy,126                                  /*typeParams=*/mlir::ValueRange{}));127    return fir::unwrapSequenceType(recTy.getType(componentName));128  }129 130  mlir::Type gen(const Fortran::evaluate::ArrayRef &arrayRef) {131    auto isTripletOrVector =132        [](const Fortran::evaluate::Subscript &subscript) -> bool {133      return Fortran::common::visit(134          Fortran::common::visitors{135              [](const Fortran::evaluate::IndirectSubscriptIntegerExpr &expr) {136                return expr.value().Rank() != 0;137              },138              [&](const Fortran::evaluate::Triplet &) { return true; }},139          subscript.u);140    };141    if (llvm::any_of(arrayRef.subscript(), isTripletOrVector))142      return genRankedArrayRefSubscriptAndBase(arrayRef);143 144    // This is a scalar ArrayRef (only scalar indexes), collect the indexes and145    // visit the base that must contain another arrayRef with the vector146    // subscript.147    mlir::Type elementType = gen(namedEntityToDataRef(arrayRef.base()));148    for (const Fortran::evaluate::Subscript &subscript : arrayRef.subscript()) {149      const auto &expr =150          std::get<Fortran::evaluate::IndirectSubscriptIntegerExpr>(151              subscript.u);152      componentPath.emplace_back(genScalarValue(expr.value()));153    }154    return elementType;155  }156 157  /// Lower the subscripts and base of the ArrayRef that is an array (there must158  /// be one since there is a vector subscript, and there can only be one159  /// according to C925).160  mlir::Type genRankedArrayRefSubscriptAndBase(161      const Fortran::evaluate::ArrayRef &arrayRef) {162    // Lower the save the base163    Fortran::lower::SomeExpr baseExpr = namedEntityToExpr(arrayRef.base());164    loweredBase = converter.genExprAddr(baseExpr, stmtCtx);165    // Lower and save the subscripts166    fir::FirOpBuilder &builder = converter.getFirOpBuilder();167    mlir::Type idxTy = builder.getIndexType();168    mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);169    for (const auto &subscript : llvm::enumerate(arrayRef.subscript())) {170      Fortran::common::visit(171          Fortran::common::visitors{172              [&](const Fortran::evaluate::IndirectSubscriptIntegerExpr &expr) {173                if (expr.value().Rank() == 0) {174                  // Simple scalar subscript175                  loweredSubscripts.emplace_back(genScalarValue(expr.value()));176                } else {177                  // Vector subscript.178                  // Remove conversion if any to avoid temp creation that may179                  // have been added by the front-end to avoid the creation of a180                  // temp array value.181                  auto vector = converter.genExprAddr(182                      ignoreEvConvert(expr.value()), stmtCtx);183                  mlir::Value size =184                      fir::factory::readExtent(builder, loc, vector, /*dim=*/0);185                  size = builder.createConvert(loc, idxTy, size);186                  loweredSubscripts.emplace_back(187                      LoweredVectorSubscript{std::move(vector), size});188                }189              },190              [&](const Fortran::evaluate::Triplet &triplet) {191                mlir::Value lb, ub;192                if (const auto &lbExpr = triplet.lower())193                  lb = genScalarValue(*lbExpr);194                else195                  lb = fir::factory::readLowerBound(builder, loc, loweredBase,196                                                    subscript.index(), one);197                if (const auto &ubExpr = triplet.upper())198                  ub = genScalarValue(*ubExpr);199                else200                  ub = fir::factory::readExtent(builder, loc, loweredBase,201                                                subscript.index());202                lb = builder.createConvert(loc, idxTy, lb);203                ub = builder.createConvert(loc, idxTy, ub);204                mlir::Value stride = genScalarValue(triplet.stride());205                stride = builder.createConvert(loc, idxTy, stride);206                loweredSubscripts.emplace_back(LoweredTriplet{lb, ub, stride});207              },208          },209          subscript.value().u);210    }211    return fir::unwrapSequenceType(212        fir::unwrapPassByRefType(fir::getBase(loweredBase).getType()));213  }214 215  mlir::Type gen(const Fortran::evaluate::CoarrayRef &) {216    // Is this possible/legal ?217    TODO(loc, "coarray: reference to coarray object with vector subscript in "218              "IO input");219  }220 221  template <typename A>222  mlir::Value genScalarValue(const A &expr) {223    return fir::getBase(converter.genExprValue(toEvExpr(expr), stmtCtx));224  }225 226  Fortran::evaluate::DataRef227  namedEntityToDataRef(const Fortran::evaluate::NamedEntity &namedEntity) {228    if (namedEntity.IsSymbol())229      return Fortran::evaluate::DataRef{namedEntity.GetFirstSymbol()};230    return Fortran::evaluate::DataRef{namedEntity.GetComponent()};231  }232 233  Fortran::lower::SomeExpr234  namedEntityToExpr(const Fortran::evaluate::NamedEntity &namedEntity) {235    return Fortran::evaluate::AsGenericExpr(namedEntityToDataRef(namedEntity))236        .value();237  }238 239  Fortran::lower::AbstractConverter &converter;240  Fortran::lower::StatementContext &stmtCtx;241  mlir::Location loc;242  /// Elements of VectorSubscriptBox being built.243  fir::ExtendedValue loweredBase;244  llvm::SmallVector<LoweredSubscript, 16> loweredSubscripts;245  llvm::SmallVector<mlir::Value> componentPath;246  MaybeSubstring substringBounds;247  mlir::Type elementType;248};249} // namespace250 251Fortran::lower::VectorSubscriptBox Fortran::lower::genVectorSubscriptBox(252    mlir::Location loc, Fortran::lower::AbstractConverter &converter,253    Fortran::lower::StatementContext &stmtCtx,254    const Fortran::lower::SomeExpr &expr) {255  return VectorSubscriptBoxBuilder(loc, converter, stmtCtx).gen(expr);256}257 258template <typename LoopType, typename Generator>259mlir::Value Fortran::lower::VectorSubscriptBox::loopOverElementsBase(260    fir::FirOpBuilder &builder, mlir::Location loc,261    const Generator &elementalGenerator,262    [[maybe_unused]] mlir::Value initialCondition) {263  mlir::Value shape = builder.createShape(loc, loweredBase);264  mlir::Value slice = createSlice(builder, loc);265 266  // Create loop nest for triplets and vector subscripts in column267  // major order.268  llvm::SmallVector<mlir::Value> inductionVariables;269  LoopType outerLoop;270  for (auto [lb, ub, step] : genLoopBounds(builder, loc)) {271    LoopType loop;272    if constexpr (std::is_same_v<LoopType, fir::IterWhileOp>) {273      loop = fir::IterWhileOp::create(builder, loc, lb, ub, step,274                                      initialCondition);275      initialCondition = loop.getIterateVar();276      if (!outerLoop)277        outerLoop = loop;278      else279        fir::ResultOp::create(builder, loc, loop.getResult(0));280    } else {281      loop = fir::DoLoopOp::create(builder, loc, lb, ub, step,282                                   /*unordered=*/false);283      if (!outerLoop)284        outerLoop = loop;285    }286    builder.setInsertionPointToStart(loop.getBody());287    inductionVariables.push_back(loop.getInductionVar());288  }289  assert(outerLoop && !inductionVariables.empty() &&290         "at least one loop should be created");291 292  fir::ExtendedValue elem =293      getElementAt(builder, loc, shape, slice, inductionVariables);294 295  if constexpr (std::is_same_v<LoopType, fir::IterWhileOp>) {296    auto res = elementalGenerator(elem);297    fir::ResultOp::create(builder, loc, res);298    builder.setInsertionPointAfter(outerLoop);299    return outerLoop.getResult(0);300  } else {301    elementalGenerator(elem);302    builder.setInsertionPointAfter(outerLoop);303    return {};304  }305}306 307void Fortran::lower::VectorSubscriptBox::loopOverElements(308    fir::FirOpBuilder &builder, mlir::Location loc,309    const ElementalGenerator &elementalGenerator) {310  mlir::Value initialCondition;311  loopOverElementsBase<fir::DoLoopOp, ElementalGenerator>(312      builder, loc, elementalGenerator, initialCondition);313}314 315mlir::Value Fortran::lower::VectorSubscriptBox::loopOverElementsWhile(316    fir::FirOpBuilder &builder, mlir::Location loc,317    const ElementalGeneratorWithBoolReturn &elementalGenerator,318    mlir::Value initialCondition) {319  return loopOverElementsBase<fir::IterWhileOp,320                              ElementalGeneratorWithBoolReturn>(321      builder, loc, elementalGenerator, initialCondition);322}323 324mlir::Value325Fortran::lower::VectorSubscriptBox::createSlice(fir::FirOpBuilder &builder,326                                                mlir::Location loc) {327  mlir::Type idxTy = builder.getIndexType();328  llvm::SmallVector<mlir::Value> triples;329  mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);330  auto undef = fir::UndefOp::create(builder, loc, idxTy);331  for (const LoweredSubscript &subscript : loweredSubscripts)332    Fortran::common::visit(Fortran::common::visitors{333                               [&](const LoweredTriplet &triplet) {334                                 triples.emplace_back(triplet.lb);335                                 triples.emplace_back(triplet.ub);336                                 triples.emplace_back(triplet.stride);337                               },338                               [&](const LoweredVectorSubscript &vector) {339                                 triples.emplace_back(one);340                                 triples.emplace_back(vector.size);341                                 triples.emplace_back(one);342                               },343                               [&](const mlir::Value &i) {344                                 triples.emplace_back(i);345                                 triples.emplace_back(undef);346                                 triples.emplace_back(undef);347                               },348                           },349                           subscript);350  return fir::SliceOp::create(builder, loc, triples, componentPath);351}352 353llvm::SmallVector<std::tuple<mlir::Value, mlir::Value, mlir::Value>>354Fortran::lower::VectorSubscriptBox::genLoopBounds(fir::FirOpBuilder &builder,355                                                  mlir::Location loc) {356  mlir::Type idxTy = builder.getIndexType();357  mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);358  mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);359  llvm::SmallVector<std::tuple<mlir::Value, mlir::Value, mlir::Value>> bounds;360  size_t dimension = loweredSubscripts.size();361  for (const LoweredSubscript &subscript : llvm::reverse(loweredSubscripts)) {362    --dimension;363    if (std::holds_alternative<mlir::Value>(subscript))364      continue;365    mlir::Value lb, ub, step;366    if (const auto *triplet = std::get_if<LoweredTriplet>(&subscript)) {367      mlir::Value extent = builder.genExtentFromTriplet(368          loc, triplet->lb, triplet->ub, triplet->stride, idxTy);369      mlir::Value baseLb = fir::factory::readLowerBound(370          builder, loc, loweredBase, dimension, one);371      baseLb = builder.createConvert(loc, idxTy, baseLb);372      lb = baseLb;373      ub = mlir::arith::SubIOp::create(builder, loc, idxTy, extent, one);374      ub = mlir::arith::AddIOp::create(builder, loc, idxTy, ub, baseLb);375      step = one;376    } else {377      const auto &vector = std::get<LoweredVectorSubscript>(subscript);378      lb = zero;379      ub = mlir::arith::SubIOp::create(builder, loc, idxTy, vector.size, one);380      step = one;381    }382    bounds.emplace_back(lb, ub, step);383  }384  return bounds;385}386 387fir::ExtendedValue Fortran::lower::VectorSubscriptBox::getElementAt(388    fir::FirOpBuilder &builder, mlir::Location loc, mlir::Value shape,389    mlir::Value slice, mlir::ValueRange inductionVariables) {390  /// Generate the indexes for the array_coor inside the loops.391  mlir::Type idxTy = builder.getIndexType();392  llvm::SmallVector<mlir::Value> indexes;393  size_t inductionIdx = inductionVariables.size() - 1;394  for (const LoweredSubscript &subscript : loweredSubscripts)395    Fortran::common::visit(396        Fortran::common::visitors{397            [&](const LoweredTriplet &triplet) {398              indexes.emplace_back(inductionVariables[inductionIdx--]);399            },400            [&](const LoweredVectorSubscript &vector) {401              mlir::Value vecIndex = inductionVariables[inductionIdx--];402              mlir::Value vecBase = fir::getBase(vector.vector);403              mlir::Type vecEleTy = fir::unwrapSequenceType(404                  fir::unwrapPassByRefType(vecBase.getType()));405              mlir::Type refTy = builder.getRefType(vecEleTy);406              auto vecEltRef = fir::CoordinateOp::create(builder, loc, refTy,407                                                         vecBase, vecIndex);408              auto vecElt =409                  fir::LoadOp::create(builder, loc, vecEleTy, vecEltRef);410              indexes.emplace_back(builder.createConvert(loc, idxTy, vecElt));411            },412            [&](const mlir::Value &i) {413              indexes.emplace_back(builder.createConvert(loc, idxTy, i));414            },415        },416        subscript);417  mlir::Type refTy = builder.getRefType(getElementType());418  auto elementAddr = fir::ArrayCoorOp::create(419      builder, loc, refTy, fir::getBase(loweredBase), shape, slice, indexes,420      fir::getTypeParams(loweredBase));421  fir::ExtendedValue element = fir::factory::arraySectionElementToExtendedValue(422      builder, loc, loweredBase, elementAddr, slice);423  if (!substringBounds.empty()) {424    const fir::CharBoxValue *charBox = element.getCharBox();425    assert(charBox && "substring requires CharBox base");426    fir::factory::CharacterExprHelper helper{builder, loc};427    return helper.createSubstring(*charBox, substringBounds);428  }429  return element;430}431