brintos

brintos / llvm-project-archived public Read only

0
0
Text · 222.9 KiB · 97e544f Raw
5683 lines · cpp
1//===-- FIROps.cpp --------------------------------------------------------===//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/Optimizer/Dialect/FIROps.h"14#include "flang/Optimizer/Dialect/FIRAttr.h"15#include "flang/Optimizer/Dialect/FIRDialect.h"16#include "flang/Optimizer/Dialect/FIROpsSupport.h"17#include "flang/Optimizer/Dialect/FIRType.h"18#include "flang/Optimizer/Dialect/Support/FIRContext.h"19#include "flang/Optimizer/Dialect/Support/KindMapping.h"20#include "flang/Optimizer/Support/Utils.h"21#include "mlir/Dialect/CommonFolders.h"22#include "mlir/Dialect/Func/IR/FuncOps.h"23#include "mlir/Dialect/OpenACC/OpenACC.h"24#include "mlir/Dialect/OpenMP/OpenMPDialect.h"25#include "mlir/IR/Attributes.h"26#include "mlir/IR/BuiltinAttributes.h"27#include "mlir/IR/BuiltinOps.h"28#include "mlir/IR/Diagnostics.h"29#include "mlir/IR/Matchers.h"30#include "mlir/IR/OpDefinition.h"31#include "mlir/IR/PatternMatch.h"32#include "mlir/IR/TypeRange.h"33#include "llvm/ADT/STLExtras.h"34#include "llvm/ADT/SmallVector.h"35#include "llvm/ADT/TypeSwitch.h"36#include "llvm/Support/CommandLine.h"37 38namespace {39#include "flang/Optimizer/Dialect/CanonicalizationPatterns.inc"40} // namespace41 42static llvm::cl::opt<bool> clUseStrictVolatileVerification(43    "strict-fir-volatile-verifier", llvm::cl::init(false),44    llvm::cl::desc(45        "use stricter verifier for FIR operations with volatile types"));46 47bool fir::useStrictVolatileVerification() {48  return clUseStrictVolatileVerification;49}50 51static void propagateAttributes(mlir::Operation *fromOp,52                                mlir::Operation *toOp) {53  if (!fromOp || !toOp)54    return;55 56  for (mlir::NamedAttribute attr : fromOp->getAttrs()) {57    if (attr.getName().getValue().starts_with(58            mlir::acc::OpenACCDialect::getDialectNamespace()))59      toOp->setAttr(attr.getName(), attr.getValue());60  }61}62 63/// Return true if a sequence type is of some incomplete size or a record type64/// is malformed or contains an incomplete sequence type. An incomplete sequence65/// type is one with more unknown extents in the type than have been provided66/// via `dynamicExtents`. Sequence types with an unknown rank are incomplete by67/// definition.68static bool verifyInType(mlir::Type inType,69                         llvm::SmallVectorImpl<llvm::StringRef> &visited,70                         unsigned dynamicExtents = 0) {71  if (auto st = mlir::dyn_cast<fir::SequenceType>(inType)) {72    auto shape = st.getShape();73    if (shape.size() == 0)74      return true;75    for (std::size_t i = 0, end = shape.size(); i < end; ++i) {76      if (shape[i] != fir::SequenceType::getUnknownExtent())77        continue;78      if (dynamicExtents-- == 0)79        return true;80    }81  } else if (auto rt = mlir::dyn_cast<fir::RecordType>(inType)) {82    // don't recurse if we're already visiting this one83    if (llvm::is_contained(visited, rt.getName()))84      return false;85    // keep track of record types currently being visited86    visited.push_back(rt.getName());87    for (auto &field : rt.getTypeList())88      if (verifyInType(field.second, visited))89        return true;90    visited.pop_back();91  }92  return false;93}94 95static bool verifyTypeParamCount(mlir::Type inType, unsigned numParams) {96  auto ty = fir::unwrapSequenceType(inType);97  if (numParams > 0) {98    if (auto recTy = mlir::dyn_cast<fir::RecordType>(ty))99      return numParams != recTy.getNumLenParams();100    if (auto chrTy = mlir::dyn_cast<fir::CharacterType>(ty))101      return !(numParams == 1 && chrTy.hasDynamicLen());102    return true;103  }104  if (auto chrTy = mlir::dyn_cast<fir::CharacterType>(ty))105    return !chrTy.hasConstantLen();106  return false;107}108 109/// Parser shared by Alloca and Allocmem110/// operation ::= %res = (`fir.alloca` | `fir.allocmem`) $in_type111///                      ( `(` $typeparams `)` )? ( `,` $shape )?112///                      attr-dict-without-keyword113template <typename FN>114static mlir::ParseResult parseAllocatableOp(FN wrapResultType,115                                            mlir::OpAsmParser &parser,116                                            mlir::OperationState &result) {117  mlir::Type intype;118  if (parser.parseType(intype))119    return mlir::failure();120  auto &builder = parser.getBuilder();121  result.addAttribute("in_type", mlir::TypeAttr::get(intype));122  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;123  llvm::SmallVector<mlir::Type> typeVec;124  bool hasOperands = false;125  std::int32_t typeparamsSize = 0;126  if (!parser.parseOptionalLParen()) {127    // parse the LEN params of the derived type. (<params> : <types>)128    if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None) ||129        parser.parseColonTypeList(typeVec) || parser.parseRParen())130      return mlir::failure();131    typeparamsSize = operands.size();132    hasOperands = true;133  }134  std::int32_t shapeSize = 0;135  if (!parser.parseOptionalComma()) {136    // parse size to scale by, vector of n dimensions of type index137    if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None))138      return mlir::failure();139    shapeSize = operands.size() - typeparamsSize;140    auto idxTy = builder.getIndexType();141    for (std::int32_t i = typeparamsSize, end = operands.size(); i != end; ++i)142      typeVec.push_back(idxTy);143    hasOperands = true;144  }145  if (hasOperands &&146      parser.resolveOperands(operands, typeVec, parser.getNameLoc(),147                             result.operands))148    return mlir::failure();149  mlir::Type restype = wrapResultType(intype);150  if (!restype) {151    parser.emitError(parser.getNameLoc(), "invalid allocate type: ") << intype;152    return mlir::failure();153  }154  result.addAttribute("operandSegmentSizes", builder.getDenseI32ArrayAttr(155                                                 {typeparamsSize, shapeSize}));156  if (parser.parseOptionalAttrDict(result.attributes) ||157      parser.addTypeToList(restype, result.types))158    return mlir::failure();159  return mlir::success();160}161 162template <typename OP>163static void printAllocatableOp(mlir::OpAsmPrinter &p, OP &op) {164  p << ' ' << op.getInType();165  if (!op.getTypeparams().empty()) {166    p << '(' << op.getTypeparams() << " : " << op.getTypeparams().getTypes()167      << ')';168  }169  // print the shape of the allocation (if any); all must be index type170  for (auto sh : op.getShape()) {171    p << ", ";172    p.printOperand(sh);173  }174  p.printOptionalAttrDict(op->getAttrs(), {"in_type", "operandSegmentSizes"});175}176 177//===----------------------------------------------------------------------===//178// AllocaOp179//===----------------------------------------------------------------------===//180 181/// Create a legal memory reference as return type182static mlir::Type wrapAllocaResultType(mlir::Type intype) {183  // FIR semantics: memory references to memory references are disallowed184  if (mlir::isa<fir::ReferenceType>(intype))185    return {};186  return fir::ReferenceType::get(intype);187}188 189mlir::Type fir::AllocaOp::getAllocatedType() {190  return mlir::cast<fir::ReferenceType>(getType()).getEleTy();191}192 193mlir::Type fir::AllocaOp::getRefTy(mlir::Type ty) {194  return fir::ReferenceType::get(ty);195}196 197void fir::AllocaOp::build(mlir::OpBuilder &builder,198                          mlir::OperationState &result, mlir::Type inType,199                          llvm::StringRef uniqName, mlir::ValueRange typeparams,200                          mlir::ValueRange shape,201                          llvm::ArrayRef<mlir::NamedAttribute> attributes) {202  auto nameAttr = builder.getStringAttr(uniqName);203  build(builder, result, wrapAllocaResultType(inType), inType, nameAttr, {},204        /*pinned=*/false, typeparams, shape);205  result.addAttributes(attributes);206}207 208void fir::AllocaOp::build(mlir::OpBuilder &builder,209                          mlir::OperationState &result, mlir::Type inType,210                          llvm::StringRef uniqName, bool pinned,211                          mlir::ValueRange typeparams, mlir::ValueRange shape,212                          llvm::ArrayRef<mlir::NamedAttribute> attributes) {213  auto nameAttr = builder.getStringAttr(uniqName);214  build(builder, result, wrapAllocaResultType(inType), inType, nameAttr, {},215        pinned, typeparams, shape);216  result.addAttributes(attributes);217}218 219void fir::AllocaOp::build(mlir::OpBuilder &builder,220                          mlir::OperationState &result, mlir::Type inType,221                          llvm::StringRef uniqName, llvm::StringRef bindcName,222                          mlir::ValueRange typeparams, mlir::ValueRange shape,223                          llvm::ArrayRef<mlir::NamedAttribute> attributes) {224  auto nameAttr =225      uniqName.empty() ? mlir::StringAttr{} : builder.getStringAttr(uniqName);226  auto bindcAttr =227      bindcName.empty() ? mlir::StringAttr{} : builder.getStringAttr(bindcName);228  build(builder, result, wrapAllocaResultType(inType), inType, nameAttr,229        bindcAttr, /*pinned=*/false, typeparams, shape);230  result.addAttributes(attributes);231}232 233void fir::AllocaOp::build(mlir::OpBuilder &builder,234                          mlir::OperationState &result, mlir::Type inType,235                          llvm::StringRef uniqName, llvm::StringRef bindcName,236                          bool pinned, mlir::ValueRange typeparams,237                          mlir::ValueRange shape,238                          llvm::ArrayRef<mlir::NamedAttribute> attributes) {239  auto nameAttr =240      uniqName.empty() ? mlir::StringAttr{} : builder.getStringAttr(uniqName);241  auto bindcAttr =242      bindcName.empty() ? mlir::StringAttr{} : builder.getStringAttr(bindcName);243  build(builder, result, wrapAllocaResultType(inType), inType, nameAttr,244        bindcAttr, pinned, typeparams, shape);245  result.addAttributes(attributes);246}247 248void fir::AllocaOp::build(mlir::OpBuilder &builder,249                          mlir::OperationState &result, mlir::Type inType,250                          mlir::ValueRange typeparams, mlir::ValueRange shape,251                          llvm::ArrayRef<mlir::NamedAttribute> attributes) {252  build(builder, result, wrapAllocaResultType(inType), inType, {}, {},253        /*pinned=*/false, typeparams, shape);254  result.addAttributes(attributes);255}256 257void fir::AllocaOp::build(mlir::OpBuilder &builder,258                          mlir::OperationState &result, mlir::Type inType,259                          bool pinned, mlir::ValueRange typeparams,260                          mlir::ValueRange shape,261                          llvm::ArrayRef<mlir::NamedAttribute> attributes) {262  build(builder, result, wrapAllocaResultType(inType), inType, {}, {}, pinned,263        typeparams, shape);264  result.addAttributes(attributes);265}266 267mlir::ParseResult fir::AllocaOp::parse(mlir::OpAsmParser &parser,268                                       mlir::OperationState &result) {269  return parseAllocatableOp(wrapAllocaResultType, parser, result);270}271 272void fir::AllocaOp::print(mlir::OpAsmPrinter &p) {273  printAllocatableOp(p, *this);274}275 276llvm::LogicalResult fir::AllocaOp::verify() {277  llvm::SmallVector<llvm::StringRef> visited;278  if (verifyInType(getInType(), visited, numShapeOperands()))279    return emitOpError("invalid type for allocation");280  if (verifyTypeParamCount(getInType(), numLenParams()))281    return emitOpError("LEN params do not correspond to type");282  mlir::Type outType = getType();283  if (!mlir::isa<fir::ReferenceType>(outType))284    return emitOpError("must be a !fir.ref type");285  return mlir::success();286}287 288bool fir::AllocaOp::ownsNestedAlloca(mlir::Operation *op) {289  return op->hasTrait<mlir::OpTrait::IsIsolatedFromAbove>() ||290         op->hasTrait<mlir::OpTrait::AutomaticAllocationScope>() ||291         mlir::isa<mlir::LoopLikeOpInterface>(*op);292}293 294mlir::Region *fir::AllocaOp::getOwnerRegion() {295  mlir::Operation *currentOp = getOperation();296  while (mlir::Operation *parentOp = currentOp->getParentOp()) {297    // If the operation was not registered, inquiries about its traits will be298    // incorrect and it is not possible to reason about the operation. This299    // should not happen in a normal Fortran compilation flow, but be foolproof.300    if (!parentOp->isRegistered())301      return nullptr;302    if (fir::AllocaOp::ownsNestedAlloca(parentOp))303      return currentOp->getParentRegion();304    currentOp = parentOp;305  }306  return nullptr;307}308 309//===----------------------------------------------------------------------===//310// AllocMemOp311//===----------------------------------------------------------------------===//312 313/// Create a legal heap reference as return type314static mlir::Type wrapAllocMemResultType(mlir::Type intype) {315  // Fortran semantics: C852 an entity cannot be both ALLOCATABLE and POINTER316  // 8.5.3 note 1 prohibits ALLOCATABLE procedures as well317  // FIR semantics: one may not allocate a memory reference value318  if (mlir::isa<fir::ReferenceType, fir::HeapType, fir::PointerType,319                mlir::FunctionType>(intype))320    return {};321  return fir::HeapType::get(intype);322}323 324mlir::Type fir::AllocMemOp::getAllocatedType() {325  return mlir::cast<fir::HeapType>(getType()).getEleTy();326}327 328mlir::Type fir::AllocMemOp::getRefTy(mlir::Type ty) {329  return fir::HeapType::get(ty);330}331 332void fir::AllocMemOp::build(mlir::OpBuilder &builder,333                            mlir::OperationState &result, mlir::Type inType,334                            llvm::StringRef uniqName,335                            mlir::ValueRange typeparams, mlir::ValueRange shape,336                            llvm::ArrayRef<mlir::NamedAttribute> attributes) {337  auto nameAttr = builder.getStringAttr(uniqName);338  build(builder, result, wrapAllocMemResultType(inType), inType, nameAttr, {},339        typeparams, shape);340  result.addAttributes(attributes);341}342 343void fir::AllocMemOp::build(mlir::OpBuilder &builder,344                            mlir::OperationState &result, mlir::Type inType,345                            llvm::StringRef uniqName, llvm::StringRef bindcName,346                            mlir::ValueRange typeparams, mlir::ValueRange shape,347                            llvm::ArrayRef<mlir::NamedAttribute> attributes) {348  auto nameAttr = builder.getStringAttr(uniqName);349  auto bindcAttr = builder.getStringAttr(bindcName);350  build(builder, result, wrapAllocMemResultType(inType), inType, nameAttr,351        bindcAttr, typeparams, shape);352  result.addAttributes(attributes);353}354 355void fir::AllocMemOp::build(mlir::OpBuilder &builder,356                            mlir::OperationState &result, mlir::Type inType,357                            mlir::ValueRange typeparams, mlir::ValueRange shape,358                            llvm::ArrayRef<mlir::NamedAttribute> attributes) {359  build(builder, result, wrapAllocMemResultType(inType), inType, {}, {},360        typeparams, shape);361  result.addAttributes(attributes);362}363 364mlir::ParseResult fir::AllocMemOp::parse(mlir::OpAsmParser &parser,365                                         mlir::OperationState &result) {366  return parseAllocatableOp(wrapAllocMemResultType, parser, result);367}368 369void fir::AllocMemOp::print(mlir::OpAsmPrinter &p) {370  printAllocatableOp(p, *this);371}372 373llvm::LogicalResult fir::AllocMemOp::verify() {374  llvm::SmallVector<llvm::StringRef> visited;375  if (verifyInType(getInType(), visited, numShapeOperands()))376    return emitOpError("invalid type for allocation");377  if (verifyTypeParamCount(getInType(), numLenParams()))378    return emitOpError("LEN params do not correspond to type");379  mlir::Type outType = getType();380  if (!mlir::dyn_cast<fir::HeapType>(outType))381    return emitOpError("must be a !fir.heap type");382  if (fir::isa_unknown_size_box(fir::dyn_cast_ptrEleTy(outType)))383    return emitOpError("cannot allocate !fir.box of unknown rank or type");384  return mlir::success();385}386 387//===----------------------------------------------------------------------===//388// ArrayCoorOp389//===----------------------------------------------------------------------===//390 391// CHARACTERs and derived types with LEN PARAMETERs are dependent types that392// require runtime values to fully define the type of an object.393static bool validTypeParams(mlir::Type dynTy, mlir::ValueRange typeParams,394                            bool allowParamsForBox = false) {395  dynTy = fir::unwrapAllRefAndSeqType(dynTy);396  if (mlir::isa<fir::BaseBoxType>(dynTy)) {397    // A box value will contain type parameter values itself.398    if (!allowParamsForBox)399      return typeParams.size() == 0;400 401    // A boxed value may have no length parameters, when the lengths402    // are assumed. If dynamic lengths are used, then proceed403    // to the verification below.404    if (typeParams.size() == 0)405      return true;406 407    dynTy = fir::getFortranElementType(dynTy);408  }409  // Derived type must have all type parameters satisfied.410  if (auto recTy = mlir::dyn_cast<fir::RecordType>(dynTy))411    return typeParams.size() == recTy.getNumLenParams();412  // Characters with non-constant LEN must have a type parameter value.413  if (auto charTy = mlir::dyn_cast<fir::CharacterType>(dynTy))414    if (charTy.hasDynamicLen())415      return typeParams.size() == 1;416  // Otherwise, any type parameters are invalid.417  return typeParams.size() == 0;418}419 420llvm::LogicalResult fir::ArrayCoorOp::verify() {421  auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());422  auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy);423  if (!arrTy)424    return emitOpError("must be a reference to an array");425  auto arrDim = arrTy.getDimension();426 427  if (auto shapeOp = getShape()) {428    auto shapeTy = shapeOp.getType();429    unsigned shapeTyRank = 0;430    if (auto s = mlir::dyn_cast<fir::ShapeType>(shapeTy)) {431      shapeTyRank = s.getRank();432    } else if (auto ss = mlir::dyn_cast<fir::ShapeShiftType>(shapeTy)) {433      shapeTyRank = ss.getRank();434    } else {435      auto s = mlir::cast<fir::ShiftType>(shapeTy);436      shapeTyRank = s.getRank();437      // TODO: it looks like PreCGRewrite and CodeGen can support438      // fir.shift with plain array reference, so we may consider439      // removing this check.440      if (!mlir::isa<fir::BaseBoxType>(getMemref().getType()))441        return emitOpError("shift can only be provided with fir.box memref");442    }443    if (arrDim && arrDim != shapeTyRank)444      return emitOpError("rank of dimension mismatched");445    // TODO: support slicing with changing the number of dimensions,446    // e.g. when array_coor represents an element access to array(:,1,:)447    // slice: the shape is 3D and the number of indices is 2 in this case.448    if (shapeTyRank != getIndices().size())449      return emitOpError("number of indices do not match dim rank");450  }451 452  if (auto sliceOp = getSlice()) {453    if (auto sl = mlir::dyn_cast_or_null<fir::SliceOp>(sliceOp.getDefiningOp()))454      if (!sl.getSubstr().empty())455        return emitOpError("array_coor cannot take a slice with substring");456    if (auto sliceTy = mlir::dyn_cast<fir::SliceType>(sliceOp.getType()))457      if (sliceTy.getRank() != arrDim)458        return emitOpError("rank of dimension in slice mismatched");459  }460  if (!validTypeParams(getMemref().getType(), getTypeparams()))461    return emitOpError("invalid type parameters");462 463  return mlir::success();464}465 466// Pull in fir.embox and fir.rebox into fir.array_coor when possible.467struct SimplifyArrayCoorOp : public mlir::OpRewritePattern<fir::ArrayCoorOp> {468  using mlir::OpRewritePattern<fir::ArrayCoorOp>::OpRewritePattern;469  llvm::LogicalResult470  matchAndRewrite(fir::ArrayCoorOp op,471                  mlir::PatternRewriter &rewriter) const override {472    mlir::Value memref = op.getMemref();473    if (!mlir::isa<fir::BaseBoxType>(memref.getType()))474      return mlir::failure();475 476    mlir::Value boxedMemref, boxedShape, boxedSlice;477    if (auto emboxOp =478            mlir::dyn_cast_or_null<fir::EmboxOp>(memref.getDefiningOp())) {479      boxedMemref = emboxOp.getMemref();480      boxedShape = emboxOp.getShape();481      boxedSlice = emboxOp.getSlice();482      // If any of operands, that are not currently supported for migration483      // to ArrayCoorOp, is present, don't rewrite.484      if (!emboxOp.getTypeparams().empty() || emboxOp.getSourceBox() ||485          emboxOp.getAccessMap())486        return mlir::failure();487    } else if (auto reboxOp = mlir::dyn_cast_or_null<fir::ReboxOp>(488                   memref.getDefiningOp())) {489      boxedMemref = reboxOp.getBox();490      boxedShape = reboxOp.getShape();491      // Avoid pulling in rebox that performs reshaping.492      // There is no way to represent box reshaping with array_coor.493      if (boxedShape && !mlir::isa<fir::ShiftType>(boxedShape.getType()))494        return mlir::failure();495      boxedSlice = reboxOp.getSlice();496    } else {497      return mlir::failure();498    }499 500    bool boxedShapeIsShift =501        boxedShape && mlir::isa<fir::ShiftType>(boxedShape.getType());502    bool boxedShapeIsShape =503        boxedShape && mlir::isa<fir::ShapeType>(boxedShape.getType());504    bool boxedShapeIsShapeShift =505        boxedShape && mlir::isa<fir::ShapeShiftType>(boxedShape.getType());506 507    // Slices changing the number of dimensions are not supported508    // for array_coor yet.509    unsigned origBoxRank;510    if (mlir::isa<fir::BaseBoxType>(boxedMemref.getType()))511      origBoxRank = fir::getBoxRank(boxedMemref.getType());512    else if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(513                 fir::unwrapRefType(boxedMemref.getType())))514      origBoxRank = arrTy.getDimension();515    else516      return mlir::failure();517 518    if (fir::getBoxRank(memref.getType()) != origBoxRank)519      return mlir::failure();520 521    // Slices with substring are not supported by array_coor.522    if (boxedSlice)523      if (auto sliceOp =524              mlir::dyn_cast_or_null<fir::SliceOp>(boxedSlice.getDefiningOp()))525        if (!sliceOp.getSubstr().empty())526          return mlir::failure();527 528    // If embox/rebox and array_coor have conflicting shapes or slices,529    // do nothing.530    if (op.getShape() && boxedShape && boxedShape != op.getShape())531      return mlir::failure();532    if (op.getSlice() && boxedSlice && boxedSlice != op.getSlice())533      return mlir::failure();534 535    std::optional<IndicesVectorTy> shiftedIndices;536    // The embox/rebox and array_coor either have compatible537    // shape/slice at this point or shape/slice is null538    // in one of them but not in the other.539    // The compatibility means they are equal or both null.540    if (!op.getShape()) {541      if (boxedShape) {542        if (op.getSlice()) {543          if (!boxedSlice) {544            if (boxedShapeIsShift) {545              // %0 = fir.rebox %arg(%shift)546              // %1 = fir.array_coor %0 [%slice] %idx547              // Both the slice indices and %idx are 1-based, so the rebox548              // may be pulled in as:549              // %1 = fir.array_coor %arg [%slice] %idx550              boxedShape = nullptr;551            } else if (boxedShapeIsShape) {552              // %0 = fir.embox %arg(%shape)553              // %1 = fir.array_coor %0 [%slice] %idx554              // Pull in as:555              // %1 = fir.array_coor %arg(%shape) [%slice] %idx556            } else if (boxedShapeIsShapeShift) {557              // %0 = fir.embox %arg(%shapeshift)558              // %1 = fir.array_coor %0 [%slice] %idx559              // Pull in as:560              // %shape = fir.shape <extents from the %shapeshift>561              // %1 = fir.array_coor %arg(%shape) [%slice] %idx562              boxedShape = getShapeFromShapeShift(boxedShape, rewriter);563              if (!boxedShape)564                return mlir::failure();565            } else {566              return mlir::failure();567            }568          } else {569            if (boxedShapeIsShift) {570              // %0 = fir.rebox %arg(%shift) [%slice]571              // %1 = fir.array_coor %0 [%slice] %idx572              // This FIR may only be valid if the shape specifies573              // that all lower bounds are 1s and the slice's start indices574              // and strides are all 1s.575              // We could pull in the rebox as:576              // %1 = fir.array_coor %arg [%slice] %idx577              // Do not do anything for the time being.578              return mlir::failure();579            } else if (boxedShapeIsShape) {580              // %0 = fir.embox %arg(%shape) [%slice]581              // %1 = fir.array_coor %0 [%slice] %idx582              // This FIR may only be valid if the slice's start indices583              // and strides are all 1s.584              // We could pull in the embox as:585              // %1 = fir.array_coor %arg(%shape) [%slice] %idx586              return mlir::failure();587            } else if (boxedShapeIsShapeShift) {588              // %0 = fir.embox %arg(%shapeshift) [%slice]589              // %1 = fir.array_coor %0 [%slice] %idx590              // This FIR may only be valid if the shape specifies591              // that all lower bounds are 1s and the slice's start indices592              // and strides are all 1s.593              // We could pull in the embox as:594              // %shape = fir.shape <extents from the %shapeshift>595              // %1 = fir.array_coor %arg(%shape) [%slice] %idx596              return mlir::failure();597            } else {598              return mlir::failure();599            }600          }601        } else { // !op.getSlice()602          if (!boxedSlice) {603            if (boxedShapeIsShift) {604              // %0 = fir.rebox %arg(%shift)605              // %1 = fir.array_coor %0 %idx606              // Pull in as:607              // %1 = fir.array_coor %arg %idx608              boxedShape = nullptr;609            } else if (boxedShapeIsShape) {610              // %0 = fir.embox %arg(%shape)611              // %1 = fir.array_coor %0 %idx612              // Pull in as:613              // %1 = fir.array_coor %arg(%shape) %idx614            } else if (boxedShapeIsShapeShift) {615              // %0 = fir.embox %arg(%shapeshift)616              // %1 = fir.array_coor %0 %idx617              // Pull in as:618              // %shape = fir.shape <extents from the %shapeshift>619              // %1 = fir.array_coor %arg(%shape) %idx620              boxedShape = getShapeFromShapeShift(boxedShape, rewriter);621              if (!boxedShape)622                return mlir::failure();623            } else {624              return mlir::failure();625            }626          } else {627            if (boxedShapeIsShift) {628              // %0 = fir.embox %arg(%shift) [%slice]629              // %1 = fir.array_coor %0 %idx630              // Pull in as:631              // %tmp = arith.addi %idx, %shift.origin632              // %idx_shifted = arith.subi %tmp, 1633              // %1 = fir.array_coor %arg(%shift) %[slice] %idx_shifted634              shiftedIndices =635                  getShiftedIndices(boxedShape, op.getIndices(), rewriter);636              if (!shiftedIndices)637                return mlir::failure();638            } else if (boxedShapeIsShape) {639              // %0 = fir.embox %arg(%shape) [%slice]640              // %1 = fir.array_coor %0 %idx641              // Pull in as:642              // %1 = fir.array_coor %arg(%shape) %[slice] %idx643            } else if (boxedShapeIsShapeShift) {644              // %0 = fir.embox %arg(%shapeshift) [%slice]645              // %1 = fir.array_coor %0 %idx646              // Pull in as:647              // %tmp = arith.addi %idx, %shapeshift.lb648              // %idx_shifted = arith.subi %tmp, 1649              // %1 = fir.array_coor %arg(%shapeshift) %[slice] %idx_shifted650              shiftedIndices =651                  getShiftedIndices(boxedShape, op.getIndices(), rewriter);652              if (!shiftedIndices)653                return mlir::failure();654            } else {655              return mlir::failure();656            }657          }658        }659      } else { // !boxedShape660        if (op.getSlice()) {661          if (!boxedSlice) {662            // %0 = fir.rebox %arg663            // %1 = fir.array_coor %0 [%slice] %idx664            // Pull in as:665            // %1 = fir.array_coor %arg [%slice] %idx666          } else {667            // %0 = fir.rebox %arg [%slice]668            // %1 = fir.array_coor %0 [%slice] %idx669            // This is a valid FIR iff the slice's lower bounds670            // and strides are all 1s.671            // Pull in as:672            // %1 = fir.array_coor %arg [%slice] %idx673          }674        } else { // !op.getSlice()675          if (!boxedSlice) {676            // %0 = fir.rebox %arg677            // %1 = fir.array_coor %0 %idx678            // Pull in as:679            // %1 = fir.array_coor %arg %idx680          } else {681            // %0 = fir.rebox %arg [%slice]682            // %1 = fir.array_coor %0 %idx683            // Pull in as:684            // %1 = fir.array_coor %arg [%slice] %idx685          }686        }687      }688    } else { // op.getShape()689      if (boxedShape) {690        // Check if pulling in non-default shape is correct.691        if (op.getSlice()) {692          if (!boxedSlice) {693            // %0 = fir.embox %arg(%shape)694            // %1 = fir.array_coor %0(%shape) [%slice] %idx695            // Pull in as:696            // %1 = fir.array_coor %arg(%shape) [%slice] %idx697          } else {698            // %0 = fir.embox %arg(%shape) [%slice]699            // %1 = fir.array_coor %0(%shape) [%slice] %idx700            // Pull in as:701            // %1 = fir.array_coor %arg(%shape) [%slice] %idx702          }703        } else { // !op.getSlice()704          if (!boxedSlice) {705            // %0 = fir.embox %arg(%shape)706            // %1 = fir.array_coor %0(%shape) %idx707            // Pull in as:708            // %1 = fir.array_coor %arg(%shape) %idx709          } else {710            // %0 = fir.embox %arg(%shape) [%slice]711            // %1 = fir.array_coor %0(%shape) %idx712            // Pull in as:713            // %1 = fir.array_coor %arg(%shape) [%slice] %idx714          }715        }716      } else { // !boxedShape717        if (op.getSlice()) {718          if (!boxedSlice) {719            // %0 = fir.rebox %arg720            // %1 = fir.array_coor %0(%shape) [%slice] %idx721            // Pull in as:722            // %1 = fir.array_coor %arg(%shape) [%slice] %idx723          } else {724            // %0 = fir.rebox %arg [%slice]725            // %1 = fir.array_coor %0(%shape) [%slice] %idx726            return mlir::failure();727          }728        } else { // !op.getSlice()729          if (!boxedSlice) {730            // %0 = fir.rebox %arg731            // %1 = fir.array_coor %0(%shape) %idx732            // Pull in as:733            // %1 = fir.array_coor %arg(%shape) %idx734          } else {735            // %0 = fir.rebox %arg [%slice]736            // %1 = fir.array_coor %0(%shape) %idx737            // Cannot pull in without adjusting the slice indices.738            return mlir::failure();739          }740        }741      }742    }743 744    // TODO: temporarily avoid producing array_coor with the shape shift745    // and plain array reference (it seems to be a limitation of746    // ArrayCoorOp verifier).747    if (!mlir::isa<fir::BaseBoxType>(boxedMemref.getType())) {748      if (boxedShape) {749        if (mlir::isa<fir::ShiftType>(boxedShape.getType()))750          return mlir::failure();751      } else if (op.getShape() &&752                 mlir::isa<fir::ShiftType>(op.getShape().getType())) {753        return mlir::failure();754      }755    }756 757    rewriter.modifyOpInPlace(op, [&]() {758      op.getMemrefMutable().assign(boxedMemref);759      if (boxedShape)760        op.getShapeMutable().assign(boxedShape);761      if (boxedSlice)762        op.getSliceMutable().assign(boxedSlice);763      if (shiftedIndices)764        op.getIndicesMutable().assign(*shiftedIndices);765    });766    return mlir::success();767  }768 769private:770  using IndicesVectorTy = std::vector<mlir::Value>;771 772  // If v is a shape_shift operation:773  //   fir.shape_shift %l1, %e1, %l2, %e2, ...774  // create:775  //   fir.shape %e1, %e2, ...776  static mlir::Value getShapeFromShapeShift(mlir::Value v,777                                            mlir::PatternRewriter &rewriter) {778    auto shapeShiftOp =779        mlir::dyn_cast_or_null<fir::ShapeShiftOp>(v.getDefiningOp());780    if (!shapeShiftOp)781      return nullptr;782    mlir::OpBuilder::InsertionGuard guard(rewriter);783    rewriter.setInsertionPoint(shapeShiftOp);784    return fir::ShapeOp::create(rewriter, shapeShiftOp.getLoc(),785                                shapeShiftOp.getExtents());786  }787 788  static std::optional<IndicesVectorTy>789  getShiftedIndices(mlir::Value v, mlir::ValueRange indices,790                    mlir::PatternRewriter &rewriter) {791    auto insertAdjustments = [&](mlir::Operation *op, mlir::ValueRange lbs) {792      // Compute the shifted indices using the extended type.793      // Note that this can probably result in less efficient794      // MLIR and further LLVM IR due to the extra conversions.795      mlir::OpBuilder::InsertPoint savedIP = rewriter.saveInsertionPoint();796      rewriter.setInsertionPoint(op);797      mlir::Location loc = op->getLoc();798      mlir::Type idxTy = rewriter.getIndexType();799      mlir::Value one = mlir::arith::ConstantOp::create(800          rewriter, loc, idxTy, rewriter.getIndexAttr(1));801      rewriter.restoreInsertionPoint(savedIP);802      auto nsw = mlir::arith::IntegerOverflowFlags::nsw;803 804      IndicesVectorTy shiftedIndices;805      for (auto [lb, idx] : llvm::zip(lbs, indices)) {806        mlir::Value extLb = fir::ConvertOp::create(rewriter, loc, idxTy, lb);807        mlir::Value extIdx = fir::ConvertOp::create(rewriter, loc, idxTy, idx);808        mlir::Value add =809            mlir::arith::AddIOp::create(rewriter, loc, extIdx, extLb, nsw);810        mlir::Value sub =811            mlir::arith::SubIOp::create(rewriter, loc, add, one, nsw);812        shiftedIndices.push_back(sub);813      }814 815      return shiftedIndices;816    };817 818    if (auto shiftOp =819            mlir::dyn_cast_or_null<fir::ShiftOp>(v.getDefiningOp())) {820      return insertAdjustments(shiftOp.getOperation(), shiftOp.getOrigins());821    } else if (auto shapeShiftOp = mlir::dyn_cast_or_null<fir::ShapeShiftOp>(822                   v.getDefiningOp())) {823      return insertAdjustments(shapeShiftOp.getOperation(),824                               shapeShiftOp.getOrigins());825    }826 827    return std::nullopt;828  }829};830 831void fir::ArrayCoorOp::getCanonicalizationPatterns(832    mlir::RewritePatternSet &patterns, mlir::MLIRContext *context) {833  // TODO: !fir.shape<1> operand may be removed from array_coor always.834  patterns.add<SimplifyArrayCoorOp>(context);835}836 837std::optional<std::int64_t> fir::ArrayCoorOp::getViewOffset(mlir::OpResult) {838  // TODO: we can try to compute the constant offset.839  return std::nullopt;840}841 842//===----------------------------------------------------------------------===//843// ArrayLoadOp844//===----------------------------------------------------------------------===//845 846static mlir::Type adjustedElementType(mlir::Type t) {847  if (auto ty = mlir::dyn_cast<fir::ReferenceType>(t)) {848    auto eleTy = ty.getEleTy();849    if (fir::isa_char(eleTy))850      return eleTy;851    if (fir::isa_derived(eleTy))852      return eleTy;853    if (mlir::isa<fir::SequenceType>(eleTy))854      return eleTy;855  }856  return t;857}858 859std::vector<mlir::Value> fir::ArrayLoadOp::getExtents() {860  if (auto sh = getShape())861    if (auto *op = sh.getDefiningOp()) {862      if (auto shOp = mlir::dyn_cast<fir::ShapeOp>(op)) {863        auto extents = shOp.getExtents();864        return {extents.begin(), extents.end()};865      }866      return mlir::cast<fir::ShapeShiftOp>(op).getExtents();867    }868  return {};869}870 871void fir::ArrayLoadOp::getEffects(872    llvm::SmallVectorImpl<873        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>874        &effects) {875  effects.emplace_back(mlir::MemoryEffects::Read::get(), &getMemrefMutable(),876                       mlir::SideEffects::DefaultResource::get());877  addVolatileMemoryEffects({getMemref().getType()}, effects);878}879 880llvm::LogicalResult fir::ArrayLoadOp::verify() {881  auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());882  auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy);883  if (!arrTy)884    return emitOpError("must be a reference to an array");885  auto arrDim = arrTy.getDimension();886 887  if (auto shapeOp = getShape()) {888    auto shapeTy = shapeOp.getType();889    unsigned shapeTyRank = 0u;890    if (auto s = mlir::dyn_cast<fir::ShapeType>(shapeTy)) {891      shapeTyRank = s.getRank();892    } else if (auto ss = mlir::dyn_cast<fir::ShapeShiftType>(shapeTy)) {893      shapeTyRank = ss.getRank();894    } else {895      auto s = mlir::cast<fir::ShiftType>(shapeTy);896      shapeTyRank = s.getRank();897      if (!mlir::isa<fir::BaseBoxType>(getMemref().getType()))898        return emitOpError("shift can only be provided with fir.box memref");899    }900    if (arrDim && arrDim != shapeTyRank)901      return emitOpError("rank of dimension mismatched");902  }903 904  if (auto sliceOp = getSlice()) {905    if (auto sl = mlir::dyn_cast_or_null<fir::SliceOp>(sliceOp.getDefiningOp()))906      if (!sl.getSubstr().empty())907        return emitOpError("array_load cannot take a slice with substring");908    if (auto sliceTy = mlir::dyn_cast<fir::SliceType>(sliceOp.getType()))909      if (sliceTy.getRank() != arrDim)910        return emitOpError("rank of dimension in slice mismatched");911  }912 913  if (!validTypeParams(getMemref().getType(), getTypeparams()))914    return emitOpError("invalid type parameters");915 916  return mlir::success();917}918 919//===----------------------------------------------------------------------===//920// ArrayMergeStoreOp921//===----------------------------------------------------------------------===//922 923llvm::LogicalResult fir::ArrayMergeStoreOp::verify() {924  if (!mlir::isa<fir::ArrayLoadOp>(getOriginal().getDefiningOp()))925    return emitOpError("operand #0 must be result of a fir.array_load op");926  if (auto sl = getSlice()) {927    if (auto sliceOp =928            mlir::dyn_cast_or_null<fir::SliceOp>(sl.getDefiningOp())) {929      if (!sliceOp.getSubstr().empty())930        return emitOpError(931            "array_merge_store cannot take a slice with substring");932      if (!sliceOp.getFields().empty()) {933        // This is an intra-object merge, where the slice is projecting the934        // subfields that are to be overwritten by the merge operation.935        auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());936        if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) {937          auto projTy =938              fir::applyPathToType(seqTy.getEleTy(), sliceOp.getFields());939          if (fir::unwrapSequenceType(getOriginal().getType()) != projTy)940            return emitOpError(941                "type of origin does not match sliced memref type");942          if (fir::unwrapSequenceType(getSequence().getType()) != projTy)943            return emitOpError(944                "type of sequence does not match sliced memref type");945          return mlir::success();946        }947        return emitOpError("referenced type is not an array");948      }949    }950    return mlir::success();951  }952  auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(getMemref().getType());953  if (getOriginal().getType() != eleTy)954    return emitOpError("type of origin does not match memref element type");955  if (getSequence().getType() != eleTy)956    return emitOpError("type of sequence does not match memref element type");957  if (!validTypeParams(getMemref().getType(), getTypeparams()))958    return emitOpError("invalid type parameters");959  return mlir::success();960}961 962void fir::ArrayMergeStoreOp::getEffects(963    llvm::SmallVectorImpl<964        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>965        &effects) {966  effects.emplace_back(mlir::MemoryEffects::Write::get(), &getMemrefMutable(),967                       mlir::SideEffects::DefaultResource::get());968  addVolatileMemoryEffects({getMemref().getType()}, effects);969}970 971//===----------------------------------------------------------------------===//972// ArrayFetchOp973//===----------------------------------------------------------------------===//974 975// Template function used for both array_fetch and array_update verification.976template <typename A>977mlir::Type validArraySubobject(A op) {978  auto ty = op.getSequence().getType();979  return fir::applyPathToType(ty, op.getIndices());980}981 982llvm::LogicalResult fir::ArrayFetchOp::verify() {983  auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());984  auto indSize = getIndices().size();985  if (indSize < arrTy.getDimension())986    return emitOpError("number of indices != dimension of array");987  if (indSize == arrTy.getDimension() &&988      ::adjustedElementType(getElement().getType()) != arrTy.getEleTy())989    return emitOpError("return type does not match array");990  auto ty = validArraySubobject(*this);991  if (!ty || ty != ::adjustedElementType(getType()))992    return emitOpError("return type and/or indices do not type check");993  if (!mlir::isa<fir::ArrayLoadOp>(getSequence().getDefiningOp()))994    return emitOpError("argument #0 must be result of fir.array_load");995  if (!validTypeParams(arrTy, getTypeparams()))996    return emitOpError("invalid type parameters");997  return mlir::success();998}999 1000//===----------------------------------------------------------------------===//1001// ArrayAccessOp1002//===----------------------------------------------------------------------===//1003 1004llvm::LogicalResult fir::ArrayAccessOp::verify() {1005  auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());1006  std::size_t indSize = getIndices().size();1007  if (indSize < arrTy.getDimension())1008    return emitOpError("number of indices != dimension of array");1009  if (indSize == arrTy.getDimension() &&1010      getElement().getType() != fir::ReferenceType::get(arrTy.getEleTy()))1011    return emitOpError("return type does not match array");1012  mlir::Type ty = validArraySubobject(*this);1013  if (!ty || fir::ReferenceType::get(ty) != getType())1014    return emitOpError("return type and/or indices do not type check");1015  if (!validTypeParams(arrTy, getTypeparams()))1016    return emitOpError("invalid type parameters");1017  return mlir::success();1018}1019 1020//===----------------------------------------------------------------------===//1021// ArrayUpdateOp1022//===----------------------------------------------------------------------===//1023 1024llvm::LogicalResult fir::ArrayUpdateOp::verify() {1025  if (fir::isa_ref_type(getMerge().getType()))1026    return emitOpError("does not support reference type for merge");1027  auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());1028  auto indSize = getIndices().size();1029  if (indSize < arrTy.getDimension())1030    return emitOpError("number of indices != dimension of array");1031  if (indSize == arrTy.getDimension() &&1032      ::adjustedElementType(getMerge().getType()) != arrTy.getEleTy())1033    return emitOpError("merged value does not have element type");1034  auto ty = validArraySubobject(*this);1035  if (!ty || ty != ::adjustedElementType(getMerge().getType()))1036    return emitOpError("merged value and/or indices do not type check");1037  if (!validTypeParams(arrTy, getTypeparams()))1038    return emitOpError("invalid type parameters");1039  return mlir::success();1040}1041 1042//===----------------------------------------------------------------------===//1043// ArrayModifyOp1044//===----------------------------------------------------------------------===//1045 1046llvm::LogicalResult fir::ArrayModifyOp::verify() {1047  auto arrTy = mlir::cast<fir::SequenceType>(getSequence().getType());1048  auto indSize = getIndices().size();1049  if (indSize < arrTy.getDimension())1050    return emitOpError("number of indices must match array dimension");1051  return mlir::success();1052}1053 1054//===----------------------------------------------------------------------===//1055// BoxAddrOp1056//===----------------------------------------------------------------------===//1057 1058void fir::BoxAddrOp::build(mlir::OpBuilder &builder,1059                           mlir::OperationState &result, mlir::Value val) {1060  mlir::Type type =1061      llvm::TypeSwitch<mlir::Type, mlir::Type>(val.getType())1062          .Case<fir::BaseBoxType>([&](fir::BaseBoxType ty) -> mlir::Type {1063            mlir::Type eleTy = ty.getEleTy();1064            if (fir::isa_ref_type(eleTy))1065              return eleTy;1066            return fir::ReferenceType::get(eleTy);1067          })1068          .Case<fir::BoxCharType>([&](fir::BoxCharType ty) -> mlir::Type {1069            return fir::ReferenceType::get(ty.getEleTy());1070          })1071          .Case<fir::BoxProcType>(1072              [&](fir::BoxProcType ty) { return ty.getEleTy(); })1073          .Default([&](const auto &) { return mlir::Type{}; });1074  assert(type && "bad val type");1075  build(builder, result, type, val);1076}1077 1078mlir::OpFoldResult fir::BoxAddrOp::fold(FoldAdaptor adaptor) {1079  if (auto *v = getVal().getDefiningOp()) {1080    if (auto box = mlir::dyn_cast<fir::EmboxOp>(v)) {1081      // Fold only if not sliced1082      if (!box.getSlice() && box.getMemref().getType() == getType()) {1083        propagateAttributes(getOperation(), box.getMemref().getDefiningOp());1084        return box.getMemref();1085      }1086    }1087    if (auto box = mlir::dyn_cast<fir::EmboxCharOp>(v))1088      if (box.getMemref().getType() == getType())1089        return box.getMemref();1090  }1091  return {};1092}1093 1094std::optional<std::int64_t> fir::BoxAddrOp::getViewOffset(mlir::OpResult) {1095  // fir.box_addr just returns the base address stored inside a box,1096  // so the direct accesses through the base address and through the box1097  // are not offsetted.1098  return 0;1099}1100 1101//===----------------------------------------------------------------------===//1102// BoxCharLenOp1103//===----------------------------------------------------------------------===//1104 1105mlir::OpFoldResult fir::BoxCharLenOp::fold(FoldAdaptor adaptor) {1106  if (auto v = getVal().getDefiningOp()) {1107    if (auto box = mlir::dyn_cast<fir::EmboxCharOp>(v))1108      return box.getLen();1109  }1110  return {};1111}1112 1113//===----------------------------------------------------------------------===//1114// BoxDimsOp1115//===----------------------------------------------------------------------===//1116 1117/// Get the result types packed in a tuple tuple1118mlir::Type fir::BoxDimsOp::getTupleType() {1119  // note: triple, but 4 is nearest power of 21120  llvm::SmallVector<mlir::Type> triple{1121      getResult(0).getType(), getResult(1).getType(), getResult(2).getType()};1122  return mlir::TupleType::get(getContext(), triple);1123}1124 1125//===----------------------------------------------------------------------===//1126// BoxRankOp1127//===----------------------------------------------------------------------===//1128 1129void fir::BoxRankOp::getEffects(1130    llvm::SmallVectorImpl<1131        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>1132        &effects) {1133  mlir::OpOperand &inputBox = getBoxMutable();1134  if (fir::isBoxAddress(inputBox.get().getType()))1135    effects.emplace_back(mlir::MemoryEffects::Read::get(), &inputBox,1136                         mlir::SideEffects::DefaultResource::get());1137}1138 1139//===----------------------------------------------------------------------===//1140// CallOp1141//===----------------------------------------------------------------------===//1142 1143mlir::FunctionType fir::CallOp::getFunctionType() {1144  return mlir::FunctionType::get(getContext(), getOperandTypes(),1145                                 getResultTypes());1146}1147 1148void fir::CallOp::print(mlir::OpAsmPrinter &p) {1149  bool isDirect = getCallee().has_value();1150  p << ' ';1151  if (isDirect)1152    p << *getCallee();1153  else1154    p << getOperand(0);1155  p << '(' << (*this)->getOperands().drop_front(isDirect ? 0 : 1) << ')';1156 1157  // Print `proc_attrs<...>`, if present.1158  fir::FortranProcedureFlagsEnumAttr procAttrs = getProcedureAttrsAttr();1159  if (procAttrs &&1160      procAttrs.getValue() != fir::FortranProcedureFlagsEnum::none) {1161    p << ' ' << fir::FortranProcedureFlagsEnumAttr::getMnemonic();1162    p.printStrippedAttrOrType(procAttrs);1163  }1164 1165  // Print 'fastmath<...>' (if it has non-default value) before1166  // any other attributes.1167  mlir::arith::FastMathFlagsAttr fmfAttr = getFastmathAttr();1168  if (fmfAttr.getValue() != mlir::arith::FastMathFlags::none) {1169    p << ' ' << mlir::arith::FastMathFlagsAttr::getMnemonic();1170    p.printStrippedAttrOrType(fmfAttr);1171  }1172 1173  p.printOptionalAttrDict((*this)->getAttrs(),1174                          {fir::CallOp::getCalleeAttrNameStr(),1175                           getFastmathAttrName(), getProcedureAttrsAttrName(),1176                           getArgAttrsAttrName(), getResAttrsAttrName()});1177  p << " : ";1178  mlir::call_interface_impl::printFunctionSignature(1179      p, getArgs().drop_front(isDirect ? 0 : 1).getTypes(), getArgAttrsAttr(),1180      /*isVariadic=*/false, getResultTypes(), getResAttrsAttr());1181}1182 1183mlir::ParseResult fir::CallOp::parse(mlir::OpAsmParser &parser,1184                                     mlir::OperationState &result) {1185  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;1186  if (parser.parseOperandList(operands))1187    return mlir::failure();1188 1189  mlir::NamedAttrList attrs;1190  mlir::SymbolRefAttr funcAttr;1191  bool isDirect = operands.empty();1192  if (isDirect)1193    if (parser.parseAttribute(funcAttr, fir::CallOp::getCalleeAttrNameStr(),1194                              attrs))1195      return mlir::failure();1196 1197  if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::Paren))1198    return mlir::failure();1199 1200  // Parse `proc_attrs<...>`, if present.1201  fir::FortranProcedureFlagsEnumAttr procAttr;1202  if (mlir::succeeded(parser.parseOptionalKeyword(1203          fir::FortranProcedureFlagsEnumAttr::getMnemonic())))1204    if (parser.parseCustomAttributeWithFallback(1205            procAttr, mlir::Type{}, getProcedureAttrsAttrName(result.name),1206            attrs))1207      return mlir::failure();1208 1209  // Parse 'fastmath<...>', if present.1210  mlir::arith::FastMathFlagsAttr fmfAttr;1211  llvm::StringRef fmfAttrName = getFastmathAttrName(result.name);1212  if (mlir::succeeded(parser.parseOptionalKeyword(fmfAttrName)))1213    if (parser.parseCustomAttributeWithFallback(fmfAttr, mlir::Type{},1214                                                fmfAttrName, attrs))1215      return mlir::failure();1216 1217  if (parser.parseOptionalAttrDict(attrs) || parser.parseColon())1218    return mlir::failure();1219  llvm::SmallVector<mlir::Type> argTypes;1220  llvm::SmallVector<mlir::Type> resTypes;1221  llvm::SmallVector<mlir::DictionaryAttr> argAttrs;1222  llvm::SmallVector<mlir::DictionaryAttr> resultAttrs;1223  if (mlir::call_interface_impl::parseFunctionSignature(1224          parser, argTypes, argAttrs, resTypes, resultAttrs))1225    return parser.emitError(parser.getNameLoc(), "expected function type");1226  mlir::FunctionType funcType =1227      mlir::FunctionType::get(parser.getContext(), argTypes, resTypes);1228  if (isDirect) {1229    if (parser.resolveOperands(operands, funcType.getInputs(),1230                               parser.getNameLoc(), result.operands))1231      return mlir::failure();1232  } else {1233    auto funcArgs =1234        llvm::ArrayRef<mlir::OpAsmParser::UnresolvedOperand>(operands)1235            .drop_front();1236    if (parser.resolveOperand(operands[0], funcType, result.operands) ||1237        parser.resolveOperands(funcArgs, funcType.getInputs(),1238                               parser.getNameLoc(), result.operands))1239      return mlir::failure();1240  }1241  result.attributes = attrs;1242  mlir::call_interface_impl::addArgAndResultAttrs(1243      parser.getBuilder(), result, argAttrs, resultAttrs,1244      getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));1245  result.addTypes(funcType.getResults());1246  return mlir::success();1247}1248 1249void fir::CallOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,1250                        mlir::func::FuncOp callee, mlir::ValueRange operands) {1251  result.addOperands(operands);1252  result.addAttribute(getCalleeAttrNameStr(), mlir::SymbolRefAttr::get(callee));1253  result.addTypes(callee.getFunctionType().getResults());1254}1255 1256void fir::CallOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,1257                        mlir::SymbolRefAttr callee,1258                        llvm::ArrayRef<mlir::Type> results,1259                        mlir::ValueRange operands) {1260  result.addOperands(operands);1261  if (callee)1262    result.addAttribute(getCalleeAttrNameStr(), callee);1263  result.addTypes(results);1264}1265 1266//===----------------------------------------------------------------------===//1267// CharConvertOp1268//===----------------------------------------------------------------------===//1269 1270llvm::LogicalResult fir::CharConvertOp::verify() {1271  auto unwrap = [&](mlir::Type t) {1272    t = fir::unwrapSequenceType(fir::dyn_cast_ptrEleTy(t));1273    return mlir::dyn_cast<fir::CharacterType>(t);1274  };1275  auto inTy = unwrap(getFrom().getType());1276  auto outTy = unwrap(getTo().getType());1277  if (!(inTy && outTy))1278    return emitOpError("not a reference to a character");1279  if (inTy.getFKind() == outTy.getFKind())1280    return emitOpError("buffers must have different KIND values");1281  return mlir::success();1282}1283 1284//===----------------------------------------------------------------------===//1285// CmpOp1286//===----------------------------------------------------------------------===//1287 1288template <typename OPTY>1289static void printCmpOp(mlir::OpAsmPrinter &p, OPTY op) {1290  p << ' ';1291  auto predSym = mlir::arith::symbolizeCmpFPredicate(1292      op->template getAttrOfType<mlir::IntegerAttr>(1293            OPTY::getPredicateAttrName())1294          .getInt());1295  assert(predSym.has_value() && "invalid symbol value for predicate");1296  p << '"' << mlir::arith::stringifyCmpFPredicate(predSym.value()) << '"'1297    << ", ";1298  p.printOperand(op.getLhs());1299  p << ", ";1300  p.printOperand(op.getRhs());1301  p.printOptionalAttrDict(op->getAttrs(),1302                          /*elidedAttrs=*/{OPTY::getPredicateAttrName()});1303  p << " : " << op.getLhs().getType();1304}1305 1306template <typename OPTY>1307static mlir::ParseResult parseCmpOp(mlir::OpAsmParser &parser,1308                                    mlir::OperationState &result) {1309  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> ops;1310  mlir::NamedAttrList attrs;1311  mlir::Attribute predicateNameAttr;1312  mlir::Type type;1313  if (parser.parseAttribute(predicateNameAttr, OPTY::getPredicateAttrName(),1314                            attrs) ||1315      parser.parseComma() || parser.parseOperandList(ops, 2) ||1316      parser.parseOptionalAttrDict(attrs) || parser.parseColonType(type) ||1317      parser.resolveOperands(ops, type, result.operands))1318    return mlir::failure();1319 1320  if (!mlir::isa<mlir::StringAttr>(predicateNameAttr))1321    return parser.emitError(parser.getNameLoc(),1322                            "expected string comparison predicate attribute");1323 1324  // Rewrite string attribute to an enum value.1325  llvm::StringRef predicateName =1326      mlir::cast<mlir::StringAttr>(predicateNameAttr).getValue();1327  auto predicate = fir::CmpcOp::getPredicateByName(predicateName);1328  auto builder = parser.getBuilder();1329  mlir::Type i1Type = builder.getI1Type();1330  attrs.set(OPTY::getPredicateAttrName(),1331            builder.getI64IntegerAttr(static_cast<std::int64_t>(predicate)));1332  result.attributes = attrs;1333  result.addTypes({i1Type});1334  return mlir::success();1335}1336 1337//===----------------------------------------------------------------------===//1338// CmpcOp1339//===----------------------------------------------------------------------===//1340 1341void fir::buildCmpCOp(mlir::OpBuilder &builder, mlir::OperationState &result,1342                      mlir::arith::CmpFPredicate predicate, mlir::Value lhs,1343                      mlir::Value rhs) {1344  result.addOperands({lhs, rhs});1345  result.types.push_back(builder.getI1Type());1346  result.addAttribute(1347      fir::CmpcOp::getPredicateAttrName(),1348      builder.getI64IntegerAttr(static_cast<std::int64_t>(predicate)));1349}1350 1351mlir::arith::CmpFPredicate1352fir::CmpcOp::getPredicateByName(llvm::StringRef name) {1353  auto pred = mlir::arith::symbolizeCmpFPredicate(name);1354  assert(pred.has_value() && "invalid predicate name");1355  return pred.value();1356}1357 1358void fir::CmpcOp::print(mlir::OpAsmPrinter &p) { printCmpOp(p, *this); }1359 1360mlir::ParseResult fir::CmpcOp::parse(mlir::OpAsmParser &parser,1361                                     mlir::OperationState &result) {1362  return parseCmpOp<fir::CmpcOp>(parser, result);1363}1364 1365//===----------------------------------------------------------------------===//1366// VolatileCastOp1367//===----------------------------------------------------------------------===//1368 1369static bool typesMatchExceptForVolatility(mlir::Type fromType,1370                                          mlir::Type toType) {1371  // If we can change only the volatility and get identical types, then we1372  // match.1373  if (fir::updateTypeWithVolatility(fromType, fir::isa_volatile_type(toType)) ==1374      toType)1375    return true;1376 1377  // Otherwise, recurse on the element types if the base classes are the same.1378  const bool match =1379      llvm::TypeSwitch<mlir::Type, bool>(fromType)1380          .Case<fir::BoxType, fir::ReferenceType, fir::ClassType>(1381              [&](auto type) {1382                using TYPE = decltype(type);1383                // If we are not the same base class, then we don't match.1384                auto castedToType = mlir::dyn_cast<TYPE>(toType);1385                if (!castedToType)1386                  return false;1387                // If we are the same base class, we match if the element types1388                // match.1389                return typesMatchExceptForVolatility(type.getEleTy(),1390                                                     castedToType.getEleTy());1391              })1392          .Default([](mlir::Type) { return false; });1393 1394  return match;1395}1396 1397llvm::LogicalResult fir::VolatileCastOp::verify() {1398  mlir::Type fromType = getValue().getType();1399  mlir::Type toType = getType();1400  if (!typesMatchExceptForVolatility(fromType, toType))1401    return emitOpError("types must be identical except for volatility ")1402           << fromType << " / " << toType;1403  return mlir::success();1404}1405 1406mlir::OpFoldResult fir::VolatileCastOp::fold(FoldAdaptor adaptor) {1407  if (getValue().getType() == getType())1408    return getValue();1409  return {};1410}1411 1412//===----------------------------------------------------------------------===//1413// ConvertOp1414//===----------------------------------------------------------------------===//1415 1416void fir::ConvertOp::getCanonicalizationPatterns(1417    mlir::RewritePatternSet &results, mlir::MLIRContext *context) {1418  results.insert<ConvertConvertOptPattern, ConvertAscendingIndexOptPattern,1419                 ConvertDescendingIndexOptPattern, RedundantConvertOptPattern,1420                 CombineConvertOptPattern, CombineConvertTruncOptPattern,1421                 ForwardConstantConvertPattern, ChainedPointerConvertsPattern>(1422      context);1423}1424 1425mlir::OpFoldResult fir::ConvertOp::fold(FoldAdaptor adaptor) {1426  if (getValue().getType() == getType())1427    return getValue();1428  if (matchPattern(getValue(), mlir::m_Op<fir::ConvertOp>())) {1429    auto inner = mlir::cast<fir::ConvertOp>(getValue().getDefiningOp());1430    // (convert (convert 'a : logical -> i1) : i1 -> logical) ==> forward 'a1431    if (auto toTy = mlir::dyn_cast<fir::LogicalType>(getType()))1432      if (auto fromTy =1433              mlir::dyn_cast<fir::LogicalType>(inner.getValue().getType()))1434        if (mlir::isa<mlir::IntegerType>(inner.getType()) && (toTy == fromTy))1435          return inner.getValue();1436    // (convert (convert 'a : i1 -> logical) : logical -> i1) ==> forward 'a1437    if (auto toTy = mlir::dyn_cast<mlir::IntegerType>(getType()))1438      if (auto fromTy =1439              mlir::dyn_cast<mlir::IntegerType>(inner.getValue().getType()))1440        if (mlir::isa<fir::LogicalType>(inner.getType()) && (toTy == fromTy) &&1441            (fromTy.getWidth() == 1))1442          return inner.getValue();1443  }1444  return {};1445}1446 1447bool fir::ConvertOp::isInteger(mlir::Type ty) {1448  return mlir::isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType>(ty);1449}1450 1451bool fir::ConvertOp::isIntegerCompatible(mlir::Type ty) {1452  return isInteger(ty) || mlir::isa<fir::LogicalType>(ty);1453}1454 1455bool fir::ConvertOp::isFloatCompatible(mlir::Type ty) {1456  return mlir::isa<mlir::FloatType>(ty);1457}1458 1459bool fir::ConvertOp::isPointerCompatible(mlir::Type ty) {1460  return mlir::isa<fir::ReferenceType, fir::PointerType, fir::HeapType,1461                   fir::LLVMPointerType, mlir::MemRefType, mlir::FunctionType,1462                   fir::TypeDescType, mlir::LLVM::LLVMPointerType>(ty);1463}1464 1465static std::optional<mlir::Type> getVectorElementType(mlir::Type ty) {1466  mlir::Type elemTy;1467  if (mlir::isa<fir::VectorType>(ty))1468    elemTy = mlir::dyn_cast<fir::VectorType>(ty).getElementType();1469  else if (mlir::isa<mlir::VectorType>(ty))1470    elemTy = mlir::dyn_cast<mlir::VectorType>(ty).getElementType();1471  else1472    return std::nullopt;1473 1474  // e.g. fir.vector<4:ui32> => mlir.vector<4xi32>1475  // e.g. mlir.vector<4xui32> => mlir.vector<4xi32>1476  if (elemTy.isUnsignedInteger()) {1477    elemTy = mlir::IntegerType::get(1478        ty.getContext(), mlir::dyn_cast<mlir::IntegerType>(elemTy).getWidth());1479  }1480  return elemTy;1481}1482 1483static std::optional<uint64_t> getVectorLen(mlir::Type ty) {1484  if (mlir::isa<fir::VectorType>(ty))1485    return mlir::dyn_cast<fir::VectorType>(ty).getLen();1486  else if (mlir::isa<mlir::VectorType>(ty)) {1487    // fir.vector only supports 1-D vector1488    if (!(mlir::dyn_cast<mlir::VectorType>(ty).isScalable()))1489      return mlir::dyn_cast<mlir::VectorType>(ty).getShape()[0];1490  }1491 1492  return std::nullopt;1493}1494 1495bool fir::ConvertOp::areVectorsCompatible(mlir::Type inTy, mlir::Type outTy) {1496  if (!(mlir::isa<fir::VectorType>(inTy) &&1497        mlir::isa<mlir::VectorType>(outTy)) &&1498      !(mlir::isa<mlir::VectorType>(inTy) && mlir::isa<fir::VectorType>(outTy)))1499    return false;1500 1501  // Only support integer, unsigned and real vector1502  // Both vectors must have the same element type1503  std::optional<mlir::Type> inElemTy = getVectorElementType(inTy);1504  std::optional<mlir::Type> outElemTy = getVectorElementType(outTy);1505  if (!inElemTy.has_value() || !outElemTy.has_value() ||1506      inElemTy.value() != outElemTy.value())1507    return false;1508 1509  // Both vectors must have the same number of elements1510  std::optional<uint64_t> inLen = getVectorLen(inTy);1511  std::optional<uint64_t> outLen = getVectorLen(outTy);1512  if (!inLen.has_value() || !outLen.has_value() ||1513      inLen.value() != outLen.value())1514    return false;1515 1516  return true;1517}1518 1519static bool areRecordsCompatible(mlir::Type inTy, mlir::Type outTy) {1520  // Both records must have the same field types.1521  // Trust frontend semantics for in-depth checks, such as if both records1522  // have the BIND(C) attribute.1523  auto inRecTy = mlir::dyn_cast<fir::RecordType>(inTy);1524  auto outRecTy = mlir::dyn_cast<fir::RecordType>(outTy);1525  return inRecTy && outRecTy && inRecTy.getTypeList() == outRecTy.getTypeList();1526}1527 1528bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {1529  if (inType == outType)1530    return true;1531  return (isPointerCompatible(inType) && isPointerCompatible(outType)) ||1532         (isIntegerCompatible(inType) && isIntegerCompatible(outType)) ||1533         (isInteger(inType) && isFloatCompatible(outType)) ||1534         (isFloatCompatible(inType) && isInteger(outType)) ||1535         (isFloatCompatible(inType) && isFloatCompatible(outType)) ||1536         (isInteger(inType) && isPointerCompatible(outType)) ||1537         (isPointerCompatible(inType) && isInteger(outType)) ||1538         (mlir::isa<fir::BoxType>(inType) &&1539          mlir::isa<fir::BoxType>(outType)) ||1540         (mlir::isa<fir::BoxProcType>(inType) &&1541          mlir::isa<fir::BoxProcType>(outType)) ||1542         (fir::isa_complex(inType) && fir::isa_complex(outType)) ||1543         (fir::isBoxedRecordType(inType) && fir::isPolymorphicType(outType)) ||1544         (fir::isPolymorphicType(inType) && fir::isPolymorphicType(outType)) ||1545         (fir::isPolymorphicType(inType) && mlir::isa<BoxType>(outType)) ||1546         areVectorsCompatible(inType, outType) ||1547         areRecordsCompatible(inType, outType);1548}1549 1550// In general, ptrtoint-like conversions are allowed to lose volatility1551// information because they are either:1552//1553// 1. passing an entity to an external function and there's nothing we can do1554//    about volatility after that happens, or1555// 2. for code generation, at which point we represent volatility with1556//    attributes on the LLVM instructions and intrinsics.1557//1558// For all other cases, volatility ought to match exactly.1559static mlir::LogicalResult verifyVolatility(mlir::Type inType,1560                                            mlir::Type outType) {1561  const bool toLLVMPointer = mlir::isa<mlir::LLVM::LLVMPointerType>(outType);1562  const bool toInteger = fir::isa_integer(outType);1563 1564  // When converting references to classes or allocatables into boxes for1565  // runtime arguments, we cast away all the volatility information and pass a1566  // box<none>. This is allowed.1567  const bool isBoxNoneLike = [&]() {1568    if (fir::isBoxNone(outType))1569      return true;1570    if (auto referenceType = mlir::dyn_cast<fir::ReferenceType>(outType)) {1571      if (fir::isBoxNone(referenceType.getElementType())) {1572        return true;1573      }1574    }1575    return false;1576  }();1577 1578  const bool isPtrToIntLike = toLLVMPointer || toInteger || isBoxNoneLike;1579  if (isPtrToIntLike) {1580    return mlir::success();1581  }1582 1583  // In all other cases, we need to check for an exact volatility match.1584  return mlir::success(fir::isa_volatile_type(inType) ==1585                       fir::isa_volatile_type(outType));1586}1587 1588llvm::LogicalResult fir::ConvertOp::verify() {1589  mlir::Type inType = getValue().getType();1590  mlir::Type outType = getType();1591  if (fir::useStrictVolatileVerification()) {1592    if (failed(verifyVolatility(inType, outType))) {1593      return emitOpError("this conversion does not preserve volatility: ")1594             << inType << " / " << outType;1595    }1596  }1597  if (canBeConverted(inType, outType))1598    return mlir::success();1599  return emitOpError("invalid type conversion")1600         << getValue().getType() << " / " << getType();1601}1602 1603//===----------------------------------------------------------------------===//1604// CoordinateOp1605//===----------------------------------------------------------------------===//1606 1607void fir::CoordinateOp::build(mlir::OpBuilder &builder,1608                              mlir::OperationState &result,1609                              mlir::Type resultType, mlir::Value ref,1610                              mlir::ValueRange coor) {1611  llvm::SmallVector<int32_t> fieldIndices;1612  llvm::SmallVector<mlir::Value> dynamicIndices;1613  bool anyField = false;1614  for (mlir::Value index : coor) {1615    if (auto field = index.getDefiningOp<fir::FieldIndexOp>()) {1616      auto recTy = mlir::cast<fir::RecordType>(field.getOnType());1617      fieldIndices.push_back(recTy.getFieldIndex(field.getFieldId()));1618      anyField = true;1619    } else {1620      fieldIndices.push_back(fir::CoordinateOp::kDynamicIndex);1621      dynamicIndices.push_back(index);1622    }1623  }1624  auto typeAttr = mlir::TypeAttr::get(ref.getType());1625  if (anyField) {1626    build(builder, result, resultType, ref, dynamicIndices, typeAttr,1627          builder.getDenseI32ArrayAttr(fieldIndices));1628  } else {1629    build(builder, result, resultType, ref, dynamicIndices, typeAttr, nullptr);1630  }1631}1632 1633void fir::CoordinateOp::build(mlir::OpBuilder &builder,1634                              mlir::OperationState &result,1635                              mlir::Type resultType, mlir::Value ref,1636                              llvm::ArrayRef<fir::IntOrValue> coor) {1637  llvm::SmallVector<int32_t> fieldIndices;1638  llvm::SmallVector<mlir::Value> dynamicIndices;1639  bool anyField = false;1640  for (fir::IntOrValue index : coor) {1641    llvm::TypeSwitch<fir::IntOrValue>(index)1642        .Case<mlir::IntegerAttr>([&](mlir::IntegerAttr intAttr) {1643          fieldIndices.push_back(intAttr.getInt());1644          anyField = true;1645        })1646        .Case<mlir::Value>([&](mlir::Value value) {1647          dynamicIndices.push_back(value);1648          fieldIndices.push_back(fir::CoordinateOp::kDynamicIndex);1649        });1650  }1651  auto typeAttr = mlir::TypeAttr::get(ref.getType());1652  if (anyField) {1653    build(builder, result, resultType, ref, dynamicIndices, typeAttr,1654          builder.getDenseI32ArrayAttr(fieldIndices));1655  } else {1656    build(builder, result, resultType, ref, dynamicIndices, typeAttr, nullptr);1657  }1658}1659 1660void fir::CoordinateOp::print(mlir::OpAsmPrinter &p) {1661  p << ' ' << getRef();1662  if (!getFieldIndicesAttr()) {1663    p << ", " << getCoor();1664  } else {1665    mlir::Type eleTy = fir::getFortranElementType(getRef().getType());1666    for (auto index : getIndices()) {1667      p << ", ";1668      llvm::TypeSwitch<fir::IntOrValue>(index)1669          .Case<mlir::IntegerAttr>([&](mlir::IntegerAttr intAttr) {1670            if (auto recordType = llvm::dyn_cast<fir::RecordType>(eleTy)) {1671              int fieldId = intAttr.getInt();1672              if (fieldId < static_cast<int>(recordType.getNumFields())) {1673                auto nameAndType = recordType.getTypeList()[fieldId];1674                p << std::get<std::string>(nameAndType);1675                eleTy = fir::getFortranElementType(1676                    std::get<mlir::Type>(nameAndType));1677                return;1678              }1679            }1680            // Invalid index, still print it so that invalid IR can be1681            // investigated.1682            p << intAttr;1683          })1684          .Case<mlir::Value>([&](mlir::Value value) { p << value; });1685    }1686  }1687  p.printOptionalAttrDict(1688      (*this)->getAttrs(),1689      /*elideAttrs=*/{getBaseTypeAttrName(), getFieldIndicesAttrName()});1690  p << " : ";1691  p.printFunctionalType(getOperandTypes(), (*this)->getResultTypes());1692}1693 1694mlir::ParseResult fir::CoordinateOp::parse(mlir::OpAsmParser &parser,1695                                           mlir::OperationState &result) {1696  mlir::OpAsmParser::UnresolvedOperand memref;1697  if (parser.parseOperand(memref) || parser.parseComma())1698    return mlir::failure();1699  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> coorOperands;1700  llvm::SmallVector<std::pair<llvm::StringRef, int>> fieldNames;1701  llvm::SmallVector<int32_t> fieldIndices;1702  while (true) {1703    llvm::StringRef fieldName;1704    if (mlir::succeeded(parser.parseOptionalKeyword(&fieldName))) {1705      fieldNames.push_back({fieldName, static_cast<int>(fieldIndices.size())});1706      // Actual value will be computed later when base type has been parsed.1707      fieldIndices.push_back(0);1708    } else {1709      mlir::OpAsmParser::UnresolvedOperand index;1710      if (parser.parseOperand(index))1711        return mlir::failure();1712      fieldIndices.push_back(fir::CoordinateOp::kDynamicIndex);1713      coorOperands.push_back(index);1714    }1715    if (mlir::failed(parser.parseOptionalComma()))1716      break;1717  }1718  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> allOperands;1719  allOperands.push_back(memref);1720  allOperands.append(coorOperands.begin(), coorOperands.end());1721  mlir::FunctionType funcTy;1722  auto loc = parser.getCurrentLocation();1723  if (parser.parseOptionalAttrDict(result.attributes) ||1724      parser.parseColonType(funcTy) ||1725      parser.resolveOperands(allOperands, funcTy.getInputs(), loc,1726                             result.operands) ||1727      parser.addTypesToList(funcTy.getResults(), result.types))1728    return mlir::failure();1729  result.addAttribute(getBaseTypeAttrName(result.name),1730                      mlir::TypeAttr::get(funcTy.getInput(0)));1731  if (!fieldNames.empty()) {1732    mlir::Type eleTy = fir::getFortranElementType(funcTy.getInput(0));1733    for (auto [fieldName, operandPosition] : fieldNames) {1734      auto recTy = llvm::dyn_cast<fir::RecordType>(eleTy);1735      if (!recTy)1736        return parser.emitError(1737            loc, "base must be a derived type when field name appears");1738      unsigned fieldNum = recTy.getFieldIndex(fieldName);1739      if (fieldNum > recTy.getNumFields())1740        return parser.emitError(loc)1741               << "field '" << fieldName1742               << "' is not a component or subcomponent of the base type";1743      fieldIndices[operandPosition] = fieldNum;1744      eleTy = fir::getFortranElementType(1745          std::get<mlir::Type>(recTy.getTypeList()[fieldNum]));1746    }1747    result.addAttribute(getFieldIndicesAttrName(result.name),1748                        parser.getBuilder().getDenseI32ArrayAttr(fieldIndices));1749  }1750  return mlir::success();1751}1752 1753llvm::LogicalResult fir::CoordinateOp::verify() {1754  const mlir::Type refTy = getRef().getType();1755  if (fir::isa_ref_type(refTy)) {1756    auto eleTy = fir::dyn_cast_ptrEleTy(refTy);1757    if (auto arrTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) {1758      if (arrTy.hasUnknownShape())1759        return emitOpError("cannot find coordinate in unknown shape");1760      if (arrTy.getConstantRows() < arrTy.getDimension() - 1)1761        return emitOpError("cannot find coordinate with unknown extents");1762    }1763    if (!(fir::isa_aggregate(eleTy) || fir::isa_complex(eleTy) ||1764          fir::isa_char_string(eleTy)))1765      return emitOpError("cannot apply to this element type");1766  }1767  auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(refTy);1768  unsigned dimension = 0;1769  const unsigned numCoors = getCoor().size();1770  for (auto coorOperand : llvm::enumerate(getCoor())) {1771    auto co = coorOperand.value();1772    if (dimension == 0 && mlir::isa<fir::SequenceType>(eleTy)) {1773      dimension = mlir::cast<fir::SequenceType>(eleTy).getDimension();1774      if (dimension == 0)1775        return emitOpError("cannot apply to array of unknown rank");1776    }1777    if (auto *defOp = co.getDefiningOp()) {1778      if (auto index = mlir::dyn_cast<fir::LenParamIndexOp>(defOp)) {1779        // Recovering a LEN type parameter only makes sense from a boxed1780        // value. For a bare reference, the LEN type parameters must be1781        // passed as additional arguments to `index`.1782        if (mlir::isa<fir::BoxType>(refTy)) {1783          if (coorOperand.index() != numCoors - 1)1784            return emitOpError("len_param_index must be last argument");1785          if (getNumOperands() != 2)1786            return emitOpError("too many operands for len_param_index case");1787        }1788        if (eleTy != index.getOnType())1789          return emitOpError(1790              "len_param_index type not compatible with reference type");1791        return mlir::success();1792      } else if (auto index = mlir::dyn_cast<fir::FieldIndexOp>(defOp)) {1793        if (eleTy != index.getOnType())1794          return emitOpError(1795              "field_index type not compatible with reference type");1796        if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy)) {1797          eleTy = recTy.getType(index.getFieldName());1798          continue;1799        }1800        return emitOpError("field_index not applied to !fir.type");1801      }1802    }1803    if (dimension) {1804      if (--dimension == 0)1805        eleTy = mlir::cast<fir::SequenceType>(eleTy).getElementType();1806    } else {1807      if (auto t = mlir::dyn_cast<mlir::TupleType>(eleTy)) {1808        // FIXME: Generally, we don't know which field of the tuple is being1809        // referred to unless the operand is a constant. Just assume everything1810        // is good in the tuple case for now.1811        return mlir::success();1812      } else if (auto t = mlir::dyn_cast<fir::RecordType>(eleTy)) {1813        // FIXME: This is the same as the tuple case.1814        return mlir::success();1815      } else if (auto t = mlir::dyn_cast<mlir::ComplexType>(eleTy)) {1816        eleTy = t.getElementType();1817      } else if (auto t = mlir::dyn_cast<fir::CharacterType>(eleTy)) {1818        if (t.getLen() == fir::CharacterType::singleton())1819          return emitOpError("cannot apply to character singleton");1820        eleTy = fir::CharacterType::getSingleton(t.getContext(), t.getFKind());1821        if (fir::unwrapRefType(getType()) != eleTy)1822          return emitOpError("character type mismatch");1823      } else {1824        return emitOpError("invalid parameters (too many)");1825      }1826    }1827  }1828  return mlir::success();1829}1830 1831fir::CoordinateIndicesAdaptor fir::CoordinateOp::getIndices() {1832  return CoordinateIndicesAdaptor(getFieldIndicesAttr(), getCoor());1833}1834 1835std::optional<std::int64_t> fir::CoordinateOp::getViewOffset(mlir::OpResult) {1836  // TODO: we can try to compute the constant offset.1837  return std::nullopt;1838}1839 1840//===----------------------------------------------------------------------===//1841// DispatchOp1842//===----------------------------------------------------------------------===//1843 1844llvm::LogicalResult fir::DispatchOp::verify() {1845  // Check that pass_arg_pos is in range of actual operands. pass_arg_pos is1846  // unsigned so check for less than zero is not needed.1847  if (getPassArgPos() && *getPassArgPos() > (getArgOperands().size() - 1))1848    return emitOpError(1849        "pass_arg_pos must be smaller than the number of operands");1850 1851  // Operand pointed by pass_arg_pos must have polymorphic type.1852  if (getPassArgPos() &&1853      !fir::isPolymorphicType(getArgOperands()[*getPassArgPos()].getType()))1854    return emitOpError("pass_arg_pos must be a polymorphic operand");1855  return mlir::success();1856}1857 1858mlir::FunctionType fir::DispatchOp::getFunctionType() {1859  return mlir::FunctionType::get(getContext(), getOperandTypes(),1860                                 getResultTypes());1861}1862 1863//===----------------------------------------------------------------------===//1864// TypeInfoOp1865//===----------------------------------------------------------------------===//1866 1867void fir::TypeInfoOp::build(mlir::OpBuilder &builder,1868                            mlir::OperationState &result, fir::RecordType type,1869                            fir::RecordType parentType,1870                            llvm::ArrayRef<mlir::NamedAttribute> attrs) {1871  result.addRegion();1872  result.addRegion();1873  result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),1874                      builder.getStringAttr(type.getName()));1875  result.addAttribute(getTypeAttrName(result.name), mlir::TypeAttr::get(type));1876  if (parentType)1877    result.addAttribute(getParentTypeAttrName(result.name),1878                        mlir::TypeAttr::get(parentType));1879  result.addAttributes(attrs);1880}1881 1882llvm::LogicalResult fir::TypeInfoOp::verify() {1883  if (!getDispatchTable().empty())1884    for (auto &op : getDispatchTable().front().without_terminator())1885      if (!mlir::isa<fir::DTEntryOp>(op))1886        return op.emitOpError("dispatch table must contain dt_entry");1887 1888  if (!mlir::isa<fir::RecordType>(getType()))1889    return emitOpError("type must be a fir.type");1890 1891  if (getParentType() && !mlir::isa<fir::RecordType>(*getParentType()))1892    return emitOpError("parent_type must be a fir.type");1893  return mlir::success();1894}1895 1896//===----------------------------------------------------------------------===//1897// EmboxOp1898//===----------------------------------------------------------------------===//1899 1900// Conversions from reference types to box types must preserve volatility.1901static llvm::LogicalResult1902verifyEmboxOpVolatilityInvariants(mlir::Type memrefType,1903                                  mlir::Type resultType) {1904 1905  if (!fir::useStrictVolatileVerification())1906    return mlir::success();1907 1908  mlir::Type boxElementType =1909      llvm::TypeSwitch<mlir::Type, mlir::Type>(resultType)1910          .Case<fir::BoxType, fir::ClassType>(1911              [&](auto type) { return type.getEleTy(); })1912          .Default([&](mlir::Type type) { return type; });1913 1914  // If the embox is simply wrapping a non-volatile type into a volatile box,1915  // we're not losing any volatility information.1916  if (boxElementType == memrefType) {1917    return mlir::success();1918  }1919 1920  // Otherwise, the volatility of the input and result must match.1921  const bool volatilityMatches =1922      fir::isa_volatile_type(memrefType) == fir::isa_volatile_type(resultType);1923 1924  return mlir::success(volatilityMatches);1925}1926 1927llvm::LogicalResult fir::EmboxOp::verify() {1928  auto eleTy = fir::dyn_cast_ptrEleTy(getMemref().getType());1929  bool isArray = false;1930  if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy)) {1931    eleTy = seqTy.getEleTy();1932    isArray = true;1933  }1934  if (hasLenParams()) {1935    auto lenPs = numLenParams();1936    if (auto rt = mlir::dyn_cast<fir::RecordType>(eleTy)) {1937      if (lenPs != rt.getNumLenParams())1938        return emitOpError("number of LEN params does not correspond"1939                           " to the !fir.type type");1940    } else if (auto strTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) {1941      if (strTy.getLen() != fir::CharacterType::unknownLen())1942        return emitOpError("CHARACTER already has static LEN");1943    } else {1944      return emitOpError("LEN parameters require CHARACTER or derived type");1945    }1946    for (auto lp : getTypeparams())1947      if (!fir::isa_integer(lp.getType()))1948        return emitOpError("LEN parameters must be integral type");1949  }1950  if (getShape() && !isArray)1951    return emitOpError("shape must not be provided for a scalar");1952  if (getSlice() && !isArray)1953    return emitOpError("slice must not be provided for a scalar");1954  if (getSourceBox() && !mlir::isa<fir::ClassType>(getResult().getType()))1955    return emitOpError("source_box must be used with fir.class result type");1956  if (failed(verifyEmboxOpVolatilityInvariants(getMemref().getType(),1957                                               getResult().getType())))1958    return emitOpError(1959               "cannot convert between volatile and non-volatile types:")1960           << " " << getMemref().getType() << " " << getResult().getType();1961  return mlir::success();1962}1963 1964/// Returns true if \p extent matches the extent of the \p box's1965/// dimension \p dim.1966static bool isBoxExtent(mlir::Value box, std::int64_t dim, mlir::Value extent) {1967  if (auto op = extent.getDefiningOp<fir::BoxDimsOp>())1968    if (op.getVal() == box && op.getExtent() == extent)1969      if (auto dimOperand = fir::getIntIfConstant(op.getDim()))1970        return *dimOperand == dim;1971  return false;1972}1973 1974/// Returns true if \p lb matches the lower bound of the \p box's1975/// dimension \p dim. If \p mayHaveNonDefaultLowerBounds is false,1976/// then \p lb may be an integer constant 1.1977static bool isBoxLb(mlir::Value box, std::int64_t dim, mlir::Value lb,1978                    bool mayHaveNonDefaultLowerBounds = true) {1979  if (auto op = lb.getDefiningOp<fir::BoxDimsOp>()) {1980    if (op.getVal() == box && op.getLowerBound() == lb)1981      if (auto dimOperand = fir::getIntIfConstant(op.getDim()))1982        return *dimOperand == dim;1983  } else if (!mayHaveNonDefaultLowerBounds) {1984    if (auto constantLb = fir::getIntIfConstant(lb))1985      return *constantLb == 1;1986  }1987  return false;1988}1989 1990/// Returns true if \p ub matches the upper bound of the \p box's1991/// dimension \p dim. If \p mayHaveNonDefaultLowerBounds is false,1992/// then the dimension's lower bound may be an integer constant 1.1993/// Note that the upper bound is usually a result of computation1994/// involving the lower bound and the extent, and the function1995/// tries its best to recognize the computation pattern.1996/// The conservative result 'false' does not necessarily mean1997/// that \p ub is not an actual upper bound value.1998static bool isBoxUb(mlir::Value box, std::int64_t dim, mlir::Value ub,1999                    bool mayHaveNonDefaultLowerBounds = true) {2000  if (auto sub1 = ub.getDefiningOp<mlir::arith::SubIOp>()) {2001    auto one = fir::getIntIfConstant(sub1.getOperand(1));2002    if (!one || *one != 1)2003      return false;2004    if (auto add = sub1.getOperand(0).getDefiningOp<mlir::arith::AddIOp>())2005      if ((isBoxLb(box, dim, add.getOperand(0)) &&2006           isBoxExtent(box, dim, add.getOperand(1))) ||2007          (isBoxLb(box, dim, add.getOperand(1)) &&2008           isBoxExtent(box, dim, add.getOperand(0))))2009        return true;2010  } else if (!mayHaveNonDefaultLowerBounds) {2011    return isBoxExtent(box, dim, ub);2012  }2013  return false;2014}2015 2016/// Checks if the given \p sliceOp specifies a contiguous2017/// array slice. If \p checkWhole is true, then the check2018/// is done for all dimensions, otherwise, only for the innermost2019/// dimension.2020/// The simplest way to prove that this is an contiguous slice2021/// is to check whether the slice stride(s) is 1.2022/// For more complex cases, extra information must be provided2023/// by the caller:2024///   * \p origBox - if not null, then the source array is represented2025///     with this !fir.box value. The box is used to recognize2026///     the full dimension slices, which are specified by the triplets2027///     computed from the dimensions' lower bounds and extents.2028///   * \p mayHaveNonDefaultLowerBounds may be set to false to indicate2029///     that the source entity has default lower bounds, so the full2030///     dimension slices computations may use 1 for the lower bound.2031static bool isContiguousArraySlice(fir::SliceOp sliceOp, bool checkWhole = true,2032                                   mlir::Value origBox = nullptr,2033                                   bool mayHaveNonDefaultLowerBounds = true) {2034  if (sliceOp.getFields().empty() && sliceOp.getSubstr().empty()) {2035    // TODO: generalize code for the triples analysis with2036    // hlfir::designatePreservesContinuity, especially when2037    // recognition of the whole dimension slices is added.2038    auto triples = sliceOp.getTriples();2039    assert((triples.size() % 3) == 0 && "invalid triples size");2040 2041    // A slice with step=1 in the innermost dimension preserves2042    // the continuity of the array in the innermost dimension.2043    // If checkWhole is false, then check only the innermost slice triples.2044    std::size_t checkUpTo = checkWhole ? triples.size() : 3;2045    checkUpTo = std::min(checkUpTo, triples.size());2046    for (std::size_t i = 0; i < checkUpTo; i += 3) {2047      if (triples[i] != triples[i + 1]) {2048        // This is a section of the dimension. Only allow it2049        // to be the first triple, if the source of the slice2050        // is a boxed array. If it is a raw pointer, then2051        // the result will still be contiguous, as long as2052        // the strides are all ones.2053        // When origBox is not null, we must prove that the triple2054        // covers the whole dimension and the stride is one,2055        // before claiming contiguity for this dimension.2056        if (i != 0 && origBox) {2057          std::int64_t dim = i / 3;2058          if (!isBoxLb(origBox, dim, triples[i],2059                       mayHaveNonDefaultLowerBounds) ||2060              !isBoxUb(origBox, dim, triples[i + 1],2061                       mayHaveNonDefaultLowerBounds))2062            return false;2063        }2064        auto constantStep = fir::getIntIfConstant(triples[i + 2]);2065        if (!constantStep || *constantStep != 1)2066          return false;2067      }2068    }2069    return true;2070  }2071  return false;2072}2073 2074bool fir::isContiguousEmbox(fir::EmboxOp embox, bool checkWhole) {2075  auto sliceArg = embox.getSlice();2076  if (!sliceArg)2077    return true;2078 2079  if (auto sliceOp =2080          mlir::dyn_cast_or_null<fir::SliceOp>(sliceArg.getDefiningOp()))2081    return isContiguousArraySlice(sliceOp, checkWhole);2082 2083  return false;2084}2085 2086std::optional<std::int64_t> fir::EmboxOp::getViewOffset(mlir::OpResult) {2087  // The address offset is zero, unless there is a slice.2088  // TODO: we can handle slices that leave the base address untouched.2089  if (!getSlice())2090    return 0;2091  return std::nullopt;2092}2093 2094//===----------------------------------------------------------------------===//2095// EmboxCharOp2096//===----------------------------------------------------------------------===//2097 2098llvm::LogicalResult fir::EmboxCharOp::verify() {2099  auto eleTy = fir::dyn_cast_ptrEleTy(getMemref().getType());2100  if (!mlir::dyn_cast_or_null<fir::CharacterType>(eleTy))2101    return mlir::failure();2102  return mlir::success();2103}2104 2105//===----------------------------------------------------------------------===//2106// EmboxProcOp2107//===----------------------------------------------------------------------===//2108 2109llvm::LogicalResult fir::EmboxProcOp::verify() {2110  // host bindings (optional) must be a reference to a tuple2111  if (auto h = getHost()) {2112    if (auto r = mlir::dyn_cast<fir::ReferenceType>(h.getType()))2113      if (mlir::isa<mlir::TupleType>(r.getEleTy()))2114        return mlir::success();2115    return mlir::failure();2116  }2117  return mlir::success();2118}2119 2120//===----------------------------------------------------------------------===//2121// TypeDescOp2122//===----------------------------------------------------------------------===//2123 2124void fir::TypeDescOp::build(mlir::OpBuilder &, mlir::OperationState &result,2125                            mlir::TypeAttr inty) {2126  result.addAttribute("in_type", inty);2127  result.addTypes(TypeDescType::get(inty.getValue()));2128}2129 2130mlir::ParseResult fir::TypeDescOp::parse(mlir::OpAsmParser &parser,2131                                         mlir::OperationState &result) {2132  mlir::Type intype;2133  if (parser.parseType(intype))2134    return mlir::failure();2135  result.addAttribute("in_type", mlir::TypeAttr::get(intype));2136  mlir::Type restype = fir::TypeDescType::get(intype);2137  if (parser.addTypeToList(restype, result.types))2138    return mlir::failure();2139  return mlir::success();2140}2141 2142void fir::TypeDescOp::print(mlir::OpAsmPrinter &p) {2143  p << ' ' << getOperation()->getAttr("in_type");2144  p.printOptionalAttrDict(getOperation()->getAttrs(), {"in_type"});2145}2146 2147llvm::LogicalResult fir::TypeDescOp::verify() {2148  mlir::Type resultTy = getType();2149  if (auto tdesc = mlir::dyn_cast<fir::TypeDescType>(resultTy)) {2150    if (tdesc.getOfTy() != getInType())2151      return emitOpError("wrapped type mismatched");2152    return mlir::success();2153  }2154  return emitOpError("must be !fir.tdesc type");2155}2156 2157//===----------------------------------------------------------------------===//2158// GlobalOp2159//===----------------------------------------------------------------------===//2160 2161mlir::Type fir::GlobalOp::resultType() {2162  return wrapAllocaResultType(getType());2163}2164 2165mlir::ParseResult fir::GlobalOp::parse(mlir::OpAsmParser &parser,2166                                       mlir::OperationState &result) {2167  // Parse the optional linkage2168  llvm::StringRef linkage;2169  auto &builder = parser.getBuilder();2170  if (mlir::succeeded(parser.parseOptionalKeyword(&linkage))) {2171    if (fir::GlobalOp::verifyValidLinkage(linkage))2172      return mlir::failure();2173    mlir::StringAttr linkAttr = builder.getStringAttr(linkage);2174    result.addAttribute(fir::GlobalOp::getLinkNameAttrName(result.name),2175                        linkAttr);2176  }2177 2178  // Parse the name as a symbol reference attribute.2179  mlir::SymbolRefAttr nameAttr;2180  if (parser.parseAttribute(nameAttr,2181                            fir::GlobalOp::getSymrefAttrName(result.name),2182                            result.attributes))2183    return mlir::failure();2184  result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),2185                      nameAttr.getRootReference());2186 2187  bool simpleInitializer = false;2188  if (mlir::succeeded(parser.parseOptionalLParen())) {2189    mlir::Attribute attr;2190    if (parser.parseAttribute(attr, getInitValAttrName(result.name),2191                              result.attributes) ||2192        parser.parseRParen())2193      return mlir::failure();2194    simpleInitializer = true;2195  }2196 2197  if (parser.parseOptionalAttrDict(result.attributes))2198    return mlir::failure();2199 2200  if (succeeded(2201          parser.parseOptionalKeyword(getConstantAttrName(result.name)))) {2202    // if "constant" keyword then mark this as a constant, not a variable2203    result.addAttribute(getConstantAttrName(result.name),2204                        builder.getUnitAttr());2205  }2206 2207  if (succeeded(parser.parseOptionalKeyword(getTargetAttrName(result.name))))2208    result.addAttribute(getTargetAttrName(result.name), builder.getUnitAttr());2209 2210  mlir::Type globalType;2211  if (parser.parseColonType(globalType))2212    return mlir::failure();2213 2214  result.addAttribute(fir::GlobalOp::getTypeAttrName(result.name),2215                      mlir::TypeAttr::get(globalType));2216 2217  if (simpleInitializer) {2218    result.addRegion();2219  } else {2220    // Parse the optional initializer body.2221    auto parseResult =2222        parser.parseOptionalRegion(*result.addRegion(), /*arguments=*/{});2223    if (parseResult.has_value() && mlir::failed(*parseResult))2224      return mlir::failure();2225  }2226  return mlir::success();2227}2228 2229void fir::GlobalOp::print(mlir::OpAsmPrinter &p) {2230  if (getLinkName())2231    p << ' ' << *getLinkName();2232  p << ' ';2233  p.printAttributeWithoutType(getSymrefAttr());2234  if (auto val = getValueOrNull())2235    p << '(' << val << ')';2236  // Print all other attributes that are not pretty printed here.2237  p.printOptionalAttrDict((*this)->getAttrs(), /*elideAttrs=*/{2238                              getSymNameAttrName(), getSymrefAttrName(),2239                              getTypeAttrName(), getConstantAttrName(),2240                              getTargetAttrName(), getLinkNameAttrName(),2241                              getInitValAttrName()});2242  if (getOperation()->getAttr(getConstantAttrName()))2243    p << " " << getConstantAttrName().strref();2244  if (getOperation()->getAttr(getTargetAttrName()))2245    p << " " << getTargetAttrName().strref();2246  p << " : ";2247  p.printType(getType());2248  if (hasInitializationBody()) {2249    p << ' ';2250    p.printRegion(getOperation()->getRegion(0),2251                  /*printEntryBlockArgs=*/false,2252                  /*printBlockTerminators=*/true);2253  }2254}2255 2256void fir::GlobalOp::appendInitialValue(mlir::Operation *op) {2257  getBlock().getOperations().push_back(op);2258}2259 2260void fir::GlobalOp::build(mlir::OpBuilder &builder,2261                          mlir::OperationState &result, llvm::StringRef name,2262                          bool isConstant, bool isTarget, mlir::Type type,2263                          mlir::Attribute initialVal, mlir::StringAttr linkage,2264                          llvm::ArrayRef<mlir::NamedAttribute> attrs) {2265  result.addRegion();2266  result.addAttribute(getTypeAttrName(result.name), mlir::TypeAttr::get(type));2267  result.addAttribute(mlir::SymbolTable::getSymbolAttrName(),2268                      builder.getStringAttr(name));2269  result.addAttribute(getSymrefAttrName(result.name),2270                      mlir::SymbolRefAttr::get(builder.getContext(), name));2271  if (isConstant)2272    result.addAttribute(getConstantAttrName(result.name),2273                        builder.getUnitAttr());2274  if (isTarget)2275    result.addAttribute(getTargetAttrName(result.name), builder.getUnitAttr());2276  if (initialVal)2277    result.addAttribute(getInitValAttrName(result.name), initialVal);2278  if (linkage)2279    result.addAttribute(getLinkNameAttrName(result.name), linkage);2280  result.attributes.append(attrs.begin(), attrs.end());2281}2282 2283void fir::GlobalOp::build(mlir::OpBuilder &builder,2284                          mlir::OperationState &result, llvm::StringRef name,2285                          mlir::Type type, mlir::Attribute initialVal,2286                          mlir::StringAttr linkage,2287                          llvm::ArrayRef<mlir::NamedAttribute> attrs) {2288  build(builder, result, name, /*isConstant=*/false, /*isTarget=*/false, type,2289        {}, linkage, attrs);2290}2291 2292void fir::GlobalOp::build(mlir::OpBuilder &builder,2293                          mlir::OperationState &result, llvm::StringRef name,2294                          bool isConstant, bool isTarget, mlir::Type type,2295                          mlir::StringAttr linkage,2296                          llvm::ArrayRef<mlir::NamedAttribute> attrs) {2297  build(builder, result, name, isConstant, isTarget, type, {}, linkage, attrs);2298}2299 2300void fir::GlobalOp::build(mlir::OpBuilder &builder,2301                          mlir::OperationState &result, llvm::StringRef name,2302                          mlir::Type type, mlir::StringAttr linkage,2303                          llvm::ArrayRef<mlir::NamedAttribute> attrs) {2304  build(builder, result, name, /*isConstant=*/false, /*isTarget=*/false, type,2305        {}, linkage, attrs);2306}2307 2308void fir::GlobalOp::build(mlir::OpBuilder &builder,2309                          mlir::OperationState &result, llvm::StringRef name,2310                          bool isConstant, bool isTarget, mlir::Type type,2311                          llvm::ArrayRef<mlir::NamedAttribute> attrs) {2312  build(builder, result, name, isConstant, isTarget, type, mlir::StringAttr{},2313        attrs);2314}2315 2316void fir::GlobalOp::build(mlir::OpBuilder &builder,2317                          mlir::OperationState &result, llvm::StringRef name,2318                          mlir::Type type,2319                          llvm::ArrayRef<mlir::NamedAttribute> attrs) {2320  build(builder, result, name, /*isConstant=*/false, /*isTarget=*/false, type,2321        attrs);2322}2323 2324mlir::ParseResult fir::GlobalOp::verifyValidLinkage(llvm::StringRef linkage) {2325  // Supporting only a subset of the LLVM linkage types for now2326  static const char *validNames[] = {"common", "internal", "linkonce",2327                                     "linkonce_odr", "weak"};2328  return mlir::success(llvm::is_contained(validNames, linkage));2329}2330 2331//===----------------------------------------------------------------------===//2332// GlobalLenOp2333//===----------------------------------------------------------------------===//2334 2335mlir::ParseResult fir::GlobalLenOp::parse(mlir::OpAsmParser &parser,2336                                          mlir::OperationState &result) {2337  llvm::StringRef fieldName;2338  if (failed(parser.parseOptionalKeyword(&fieldName))) {2339    mlir::StringAttr fieldAttr;2340    if (parser.parseAttribute(fieldAttr,2341                              fir::GlobalLenOp::getLenParamAttrName(),2342                              result.attributes))2343      return mlir::failure();2344  } else {2345    result.addAttribute(fir::GlobalLenOp::getLenParamAttrName(),2346                        parser.getBuilder().getStringAttr(fieldName));2347  }2348  mlir::IntegerAttr constant;2349  if (parser.parseComma() ||2350      parser.parseAttribute(constant, fir::GlobalLenOp::getIntAttrName(),2351                            result.attributes))2352    return mlir::failure();2353  return mlir::success();2354}2355 2356void fir::GlobalLenOp::print(mlir::OpAsmPrinter &p) {2357  p << ' ' << getOperation()->getAttr(fir::GlobalLenOp::getLenParamAttrName())2358    << ", " << getOperation()->getAttr(fir::GlobalLenOp::getIntAttrName());2359}2360 2361//===----------------------------------------------------------------------===//2362// FieldIndexOp2363//===----------------------------------------------------------------------===//2364 2365template <typename TY>2366mlir::ParseResult parseFieldLikeOp(mlir::OpAsmParser &parser,2367                                   mlir::OperationState &result) {2368  llvm::StringRef fieldName;2369  auto &builder = parser.getBuilder();2370  mlir::Type recty;2371  if (parser.parseOptionalKeyword(&fieldName) || parser.parseComma() ||2372      parser.parseType(recty))2373    return mlir::failure();2374  result.addAttribute(fir::FieldIndexOp::getFieldAttrName(),2375                      builder.getStringAttr(fieldName));2376  if (!mlir::dyn_cast<fir::RecordType>(recty))2377    return mlir::failure();2378  result.addAttribute(fir::FieldIndexOp::getTypeAttrName(),2379                      mlir::TypeAttr::get(recty));2380  if (!parser.parseOptionalLParen()) {2381    llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;2382    llvm::SmallVector<mlir::Type> types;2383    auto loc = parser.getNameLoc();2384    if (parser.parseOperandList(operands, mlir::OpAsmParser::Delimiter::None) ||2385        parser.parseColonTypeList(types) || parser.parseRParen() ||2386        parser.resolveOperands(operands, types, loc, result.operands))2387      return mlir::failure();2388  }2389  mlir::Type fieldType = TY::get(builder.getContext());2390  if (parser.addTypeToList(fieldType, result.types))2391    return mlir::failure();2392  return mlir::success();2393}2394 2395mlir::ParseResult fir::FieldIndexOp::parse(mlir::OpAsmParser &parser,2396                                           mlir::OperationState &result) {2397  return parseFieldLikeOp<fir::FieldType>(parser, result);2398}2399 2400template <typename OP>2401void printFieldLikeOp(mlir::OpAsmPrinter &p, OP &op) {2402  p << ' '2403    << op.getOperation()2404           ->template getAttrOfType<mlir::StringAttr>(2405               fir::FieldIndexOp::getFieldAttrName())2406           .getValue()2407    << ", " << op.getOperation()->getAttr(fir::FieldIndexOp::getTypeAttrName());2408  if (op.getNumOperands()) {2409    p << '(';2410    p.printOperands(op.getTypeparams());2411    auto sep = ") : ";2412    for (auto op : op.getTypeparams()) {2413      p << sep;2414      if (op)2415        p.printType(op.getType());2416      else2417        p << "()";2418      sep = ", ";2419    }2420  }2421}2422 2423void fir::FieldIndexOp::print(mlir::OpAsmPrinter &p) {2424  printFieldLikeOp(p, *this);2425}2426 2427void fir::FieldIndexOp::build(mlir::OpBuilder &builder,2428                              mlir::OperationState &result,2429                              llvm::StringRef fieldName, mlir::Type recTy,2430                              mlir::ValueRange operands) {2431  result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));2432  result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));2433  result.addOperands(operands);2434}2435 2436llvm::SmallVector<mlir::Attribute> fir::FieldIndexOp::getAttributes() {2437  llvm::SmallVector<mlir::Attribute> attrs;2438  attrs.push_back(getFieldIdAttr());2439  attrs.push_back(getOnTypeAttr());2440  return attrs;2441}2442 2443//===----------------------------------------------------------------------===//2444// InsertOnRangeOp2445//===----------------------------------------------------------------------===//2446 2447static mlir::ParseResult2448parseCustomRangeSubscript(mlir::OpAsmParser &parser,2449                          mlir::DenseIntElementsAttr &coord) {2450  llvm::SmallVector<std::int64_t> lbounds;2451  llvm::SmallVector<std::int64_t> ubounds;2452  if (parser.parseKeyword("from") ||2453      parser.parseCommaSeparatedList(2454          mlir::AsmParser::Delimiter::Paren,2455          [&] { return parser.parseInteger(lbounds.emplace_back(0)); }) ||2456      parser.parseKeyword("to") ||2457      parser.parseCommaSeparatedList(mlir::AsmParser::Delimiter::Paren, [&] {2458        return parser.parseInteger(ubounds.emplace_back(0));2459      }))2460    return mlir::failure();2461  llvm::SmallVector<std::int64_t> zippedBounds;2462  for (auto zip : llvm::zip(lbounds, ubounds)) {2463    zippedBounds.push_back(std::get<0>(zip));2464    zippedBounds.push_back(std::get<1>(zip));2465  }2466  coord = mlir::Builder(parser.getContext()).getIndexTensorAttr(zippedBounds);2467  return mlir::success();2468}2469 2470static void printCustomRangeSubscript(mlir::OpAsmPrinter &printer,2471                                      fir::InsertOnRangeOp op,2472                                      mlir::DenseIntElementsAttr coord) {2473  printer << "from (";2474  auto enumerate = llvm::enumerate(coord.getValues<std::int64_t>());2475  // Even entries are the lower bounds.2476  llvm::interleaveComma(2477      make_filter_range(2478          enumerate,2479          [](auto indexed_value) { return indexed_value.index() % 2 == 0; }),2480      printer, [&](auto indexed_value) { printer << indexed_value.value(); });2481  printer << ") to (";2482  // Odd entries are the upper bounds.2483  llvm::interleaveComma(2484      make_filter_range(2485          enumerate,2486          [](auto indexed_value) { return indexed_value.index() % 2 != 0; }),2487      printer, [&](auto indexed_value) { printer << indexed_value.value(); });2488  printer << ")";2489}2490 2491/// Range bounds must be nonnegative, and the range must not be empty.2492llvm::LogicalResult fir::InsertOnRangeOp::verify() {2493  if (fir::hasDynamicSize(getSeq().getType()))2494    return emitOpError("must have constant shape and size");2495  mlir::DenseIntElementsAttr coorAttr = getCoor();2496  if (coorAttr.size() < 2 || coorAttr.size() % 2 != 0)2497    return emitOpError("has uneven number of values in ranges");2498  bool rangeIsKnownToBeNonempty = false;2499  for (auto i = coorAttr.getValues<std::int64_t>().end(),2500            b = coorAttr.getValues<std::int64_t>().begin();2501       i != b;) {2502    int64_t ub = (*--i);2503    int64_t lb = (*--i);2504    if (lb < 0 || ub < 0)2505      return emitOpError("negative range bound");2506    if (rangeIsKnownToBeNonempty)2507      continue;2508    if (lb > ub)2509      return emitOpError("empty range");2510    rangeIsKnownToBeNonempty = lb < ub;2511  }2512  return mlir::success();2513}2514 2515bool fir::InsertOnRangeOp::isFullRange() {2516  auto extents = getType().getShape();2517  mlir::DenseIntElementsAttr indexes = getCoor();2518  if (indexes.size() / 2 != static_cast<int64_t>(extents.size()))2519    return false;2520  auto cur_index = indexes.value_begin<int64_t>();2521  for (unsigned i = 0; i < indexes.size(); i += 2) {2522    if (*(cur_index++) != 0)2523      return false;2524    if (*(cur_index++) != extents[i / 2] - 1)2525      return false;2526  }2527  return true;2528}2529 2530//===----------------------------------------------------------------------===//2531// InsertValueOp2532//===----------------------------------------------------------------------===//2533 2534static bool checkIsIntegerConstant(mlir::Attribute attr, std::int64_t conVal) {2535  if (auto iattr = mlir::dyn_cast<mlir::IntegerAttr>(attr))2536    return iattr.getInt() == conVal;2537  return false;2538}2539 2540static bool isZero(mlir::Attribute a) { return checkIsIntegerConstant(a, 0); }2541static bool isOne(mlir::Attribute a) { return checkIsIntegerConstant(a, 1); }2542 2543// Undo some complex patterns created in the front-end and turn them back into2544// complex ops.2545template <typename FltOp, typename CpxOp>2546struct UndoComplexPattern : public mlir::RewritePattern {2547  UndoComplexPattern(mlir::MLIRContext *ctx)2548      : mlir::RewritePattern("fir.insert_value", 2, ctx) {}2549 2550  llvm::LogicalResult2551  matchAndRewrite(mlir::Operation *op,2552                  mlir::PatternRewriter &rewriter) const override {2553    auto insval = mlir::dyn_cast_or_null<fir::InsertValueOp>(op);2554    if (!insval || !mlir::isa<mlir::ComplexType>(insval.getType()))2555      return mlir::failure();2556    auto insval2 = mlir::dyn_cast_or_null<fir::InsertValueOp>(2557        insval.getAdt().getDefiningOp());2558    if (!insval2)2559      return mlir::failure();2560    auto binf = mlir::dyn_cast_or_null<FltOp>(insval.getVal().getDefiningOp());2561    auto binf2 =2562        mlir::dyn_cast_or_null<FltOp>(insval2.getVal().getDefiningOp());2563    if (!binf || !binf2 || insval.getCoor().size() != 1 ||2564        !isOne(insval.getCoor()[0]) || insval2.getCoor().size() != 1 ||2565        !isZero(insval2.getCoor()[0]))2566      return mlir::failure();2567    auto eai = mlir::dyn_cast_or_null<fir::ExtractValueOp>(2568        binf.getLhs().getDefiningOp());2569    auto ebi = mlir::dyn_cast_or_null<fir::ExtractValueOp>(2570        binf.getRhs().getDefiningOp());2571    auto ear = mlir::dyn_cast_or_null<fir::ExtractValueOp>(2572        binf2.getLhs().getDefiningOp());2573    auto ebr = mlir::dyn_cast_or_null<fir::ExtractValueOp>(2574        binf2.getRhs().getDefiningOp());2575    if (!eai || !ebi || !ear || !ebr || ear.getAdt() != eai.getAdt() ||2576        ebr.getAdt() != ebi.getAdt() || eai.getCoor().size() != 1 ||2577        !isOne(eai.getCoor()[0]) || ebi.getCoor().size() != 1 ||2578        !isOne(ebi.getCoor()[0]) || ear.getCoor().size() != 1 ||2579        !isZero(ear.getCoor()[0]) || ebr.getCoor().size() != 1 ||2580        !isZero(ebr.getCoor()[0]))2581      return mlir::failure();2582    rewriter.replaceOpWithNewOp<CpxOp>(op, ear.getAdt(), ebr.getAdt());2583    return mlir::success();2584  }2585};2586 2587void fir::InsertValueOp::getCanonicalizationPatterns(2588    mlir::RewritePatternSet &results, mlir::MLIRContext *context) {2589  results.insert<UndoComplexPattern<mlir::arith::AddFOp, fir::AddcOp>,2590                 UndoComplexPattern<mlir::arith::SubFOp, fir::SubcOp>>(context);2591}2592 2593//===----------------------------------------------------------------------===//2594// IterWhileOp2595//===----------------------------------------------------------------------===//2596 2597void fir::IterWhileOp::build(mlir::OpBuilder &builder,2598                             mlir::OperationState &result, mlir::Value lb,2599                             mlir::Value ub, mlir::Value step,2600                             mlir::Value iterate, bool finalCountValue,2601                             mlir::ValueRange iterArgs,2602                             llvm::ArrayRef<mlir::NamedAttribute> attributes) {2603  result.addOperands({lb, ub, step, iterate});2604  if (finalCountValue) {2605    result.addTypes(builder.getIndexType());2606    result.addAttribute(getFinalValueAttrNameStr(), builder.getUnitAttr());2607  }2608  result.addTypes(iterate.getType());2609  result.addOperands(iterArgs);2610  for (auto v : iterArgs)2611    result.addTypes(v.getType());2612  mlir::Region *bodyRegion = result.addRegion();2613  bodyRegion->push_back(new mlir::Block{});2614  bodyRegion->front().addArgument(builder.getIndexType(), result.location);2615  bodyRegion->front().addArgument(iterate.getType(), result.location);2616  bodyRegion->front().addArguments(2617      iterArgs.getTypes(),2618      llvm::SmallVector<mlir::Location>(iterArgs.size(), result.location));2619  result.addAttributes(attributes);2620}2621 2622mlir::ParseResult fir::IterWhileOp::parse(mlir::OpAsmParser &parser,2623                                          mlir::OperationState &result) {2624  auto &builder = parser.getBuilder();2625  mlir::OpAsmParser::Argument inductionVariable, iterateVar;2626  mlir::OpAsmParser::UnresolvedOperand lb, ub, step, iterateInput;2627  if (parser.parseLParen() || parser.parseArgument(inductionVariable) ||2628      parser.parseEqual())2629    return mlir::failure();2630 2631  // Parse loop bounds.2632  auto indexType = builder.getIndexType();2633  auto i1Type = builder.getIntegerType(1);2634  if (parser.parseOperand(lb) ||2635      parser.resolveOperand(lb, indexType, result.operands) ||2636      parser.parseKeyword("to") || parser.parseOperand(ub) ||2637      parser.resolveOperand(ub, indexType, result.operands) ||2638      parser.parseKeyword("step") || parser.parseOperand(step) ||2639      parser.parseRParen() ||2640      parser.resolveOperand(step, indexType, result.operands) ||2641      parser.parseKeyword("and") || parser.parseLParen() ||2642      parser.parseArgument(iterateVar) || parser.parseEqual() ||2643      parser.parseOperand(iterateInput) || parser.parseRParen() ||2644      parser.resolveOperand(iterateInput, i1Type, result.operands))2645    return mlir::failure();2646 2647  // Parse the initial iteration arguments.2648  auto prependCount = false;2649 2650  // Induction variable.2651  llvm::SmallVector<mlir::OpAsmParser::Argument> regionArgs;2652  regionArgs.push_back(inductionVariable);2653  regionArgs.push_back(iterateVar);2654 2655  if (succeeded(parser.parseOptionalKeyword("iter_args"))) {2656    llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> operands;2657    llvm::SmallVector<mlir::Type> regionTypes;2658    // Parse assignment list and results type list.2659    if (parser.parseAssignmentList(regionArgs, operands) ||2660        parser.parseArrowTypeList(regionTypes))2661      return mlir::failure();2662    if (regionTypes.size() == operands.size() + 2)2663      prependCount = true;2664    llvm::ArrayRef<mlir::Type> resTypes = regionTypes;2665    resTypes = prependCount ? resTypes.drop_front(2) : resTypes;2666    // Resolve input operands.2667    for (auto operandType : llvm::zip(operands, resTypes))2668      if (parser.resolveOperand(std::get<0>(operandType),2669                                std::get<1>(operandType), result.operands))2670        return mlir::failure();2671    if (prependCount) {2672      result.addTypes(regionTypes);2673    } else {2674      result.addTypes(i1Type);2675      result.addTypes(resTypes);2676    }2677  } else if (succeeded(parser.parseOptionalArrow())) {2678    llvm::SmallVector<mlir::Type> typeList;2679    if (parser.parseLParen() || parser.parseTypeList(typeList) ||2680        parser.parseRParen())2681      return mlir::failure();2682    // Type list must be "(index, i1)".2683    if (typeList.size() != 2 || !mlir::isa<mlir::IndexType>(typeList[0]) ||2684        !typeList[1].isSignlessInteger(1))2685      return mlir::failure();2686    result.addTypes(typeList);2687    prependCount = true;2688  } else {2689    result.addTypes(i1Type);2690  }2691 2692  if (parser.parseOptionalAttrDictWithKeyword(result.attributes))2693    return mlir::failure();2694 2695  llvm::SmallVector<mlir::Type> argTypes;2696  // Induction variable (hidden)2697  if (prependCount)2698    result.addAttribute(IterWhileOp::getFinalValueAttrNameStr(),2699                        builder.getUnitAttr());2700  else2701    argTypes.push_back(indexType);2702  // Loop carried variables (including iterate)2703  argTypes.append(result.types.begin(), result.types.end());2704  // Parse the body region.2705  auto *body = result.addRegion();2706  if (regionArgs.size() != argTypes.size())2707    return parser.emitError(2708        parser.getNameLoc(),2709        "mismatch in number of loop-carried values and defined values");2710 2711  for (size_t i = 0, e = regionArgs.size(); i != e; ++i)2712    regionArgs[i].type = argTypes[i];2713 2714  if (parser.parseRegion(*body, regionArgs))2715    return mlir::failure();2716 2717  fir::IterWhileOp::ensureTerminator(*body, builder, result.location);2718  return mlir::success();2719}2720 2721llvm::LogicalResult fir::IterWhileOp::verify() {2722  // Check that the body defines as single block argument for the induction2723  // variable.2724  auto *body = getBody();2725  if (!body->getArgument(1).getType().isInteger(1))2726    return emitOpError(2727        "expected body second argument to be an index argument for "2728        "the induction variable");2729  if (!body->getArgument(0).getType().isIndex())2730    return emitOpError(2731        "expected body first argument to be an index argument for "2732        "the induction variable");2733 2734  auto opNumResults = getNumResults();2735  if (getFinalValue()) {2736    // Result type must be "(index, i1, ...)".2737    if (!mlir::isa<mlir::IndexType>(getResult(0).getType()))2738      return emitOpError("result #0 expected to be index");2739    if (!getResult(1).getType().isSignlessInteger(1))2740      return emitOpError("result #1 expected to be i1");2741    opNumResults--;2742  } else {2743    // iterate_while always returns the early exit induction value.2744    // Result type must be "(i1, ...)"2745    if (!getResult(0).getType().isSignlessInteger(1))2746      return emitOpError("result #0 expected to be i1");2747  }2748  if (opNumResults == 0)2749    return mlir::failure();2750  if (getNumIterOperands() != opNumResults)2751    return emitOpError(2752        "mismatch in number of loop-carried values and defined values");2753  if (getNumRegionIterArgs() != opNumResults)2754    return emitOpError(2755        "mismatch in number of basic block args and defined values");2756  auto iterOperands = getIterOperands();2757  auto iterArgs = getRegionIterArgs();2758  auto opResults = getFinalValue() ? getResults().drop_front() : getResults();2759  unsigned i = 0u;2760  for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {2761    if (std::get<0>(e).getType() != std::get<2>(e).getType())2762      return emitOpError() << "types mismatch between " << i2763                           << "th iter operand and defined value";2764    if (std::get<1>(e).getType() != std::get<2>(e).getType())2765      return emitOpError() << "types mismatch between " << i2766                           << "th iter region arg and defined value";2767 2768    i++;2769  }2770  return mlir::success();2771}2772 2773void fir::IterWhileOp::print(mlir::OpAsmPrinter &p) {2774  p << " (" << getInductionVar() << " = " << getLowerBound() << " to "2775    << getUpperBound() << " step " << getStep() << ") and (";2776  assert(hasIterOperands());2777  auto regionArgs = getRegionIterArgs();2778  auto operands = getIterOperands();2779  p << regionArgs.front() << " = " << *operands.begin() << ")";2780  if (regionArgs.size() > 1) {2781    p << " iter_args(";2782    llvm::interleaveComma(2783        llvm::zip(regionArgs.drop_front(), operands.drop_front()), p,2784        [&](auto it) { p << std::get<0>(it) << " = " << std::get<1>(it); });2785    p << ") -> (";2786    llvm::interleaveComma(2787        llvm::drop_begin(getResultTypes(), getFinalValue() ? 0 : 1), p);2788    p << ")";2789  } else if (getFinalValue()) {2790    p << " -> (" << getResultTypes() << ')';2791  }2792  p.printOptionalAttrDictWithKeyword((*this)->getAttrs(),2793                                     {getFinalValueAttrNameStr()});2794  p << ' ';2795  p.printRegion(getRegion(), /*printEntryBlockArgs=*/false,2796                /*printBlockTerminators=*/true);2797}2798 2799llvm::SmallVector<mlir::Region *> fir::IterWhileOp::getLoopRegions() {2800  return {&getRegion()};2801}2802 2803mlir::BlockArgument fir::IterWhileOp::iterArgToBlockArg(mlir::Value iterArg) {2804  for (auto i : llvm::enumerate(getInitArgs()))2805    if (iterArg == i.value())2806      return getRegion().front().getArgument(i.index() + 1);2807  return {};2808}2809 2810void fir::IterWhileOp::resultToSourceOps(2811    llvm::SmallVectorImpl<mlir::Value> &results, unsigned resultNum) {2812  auto oper = getFinalValue() ? resultNum + 1 : resultNum;2813  auto *term = getRegion().front().getTerminator();2814  if (oper < term->getNumOperands())2815    results.push_back(term->getOperand(oper));2816}2817 2818mlir::Value fir::IterWhileOp::blockArgToSourceOp(unsigned blockArgNum) {2819  if (blockArgNum > 0 && blockArgNum <= getInitArgs().size())2820    return getInitArgs()[blockArgNum - 1];2821  return {};2822}2823 2824std::optional<llvm::MutableArrayRef<mlir::OpOperand>>2825fir::IterWhileOp::getYieldedValuesMutable() {2826  auto *term = getRegion().front().getTerminator();2827  return getFinalValue() ? term->getOpOperands().drop_front()2828                         : term->getOpOperands();2829}2830 2831//===----------------------------------------------------------------------===//2832// LenParamIndexOp2833//===----------------------------------------------------------------------===//2834 2835mlir::ParseResult fir::LenParamIndexOp::parse(mlir::OpAsmParser &parser,2836                                              mlir::OperationState &result) {2837  return parseFieldLikeOp<fir::LenType>(parser, result);2838}2839 2840void fir::LenParamIndexOp::print(mlir::OpAsmPrinter &p) {2841  printFieldLikeOp(p, *this);2842}2843 2844void fir::LenParamIndexOp::build(mlir::OpBuilder &builder,2845                                 mlir::OperationState &result,2846                                 llvm::StringRef fieldName, mlir::Type recTy,2847                                 mlir::ValueRange operands) {2848  result.addAttribute(getFieldAttrName(), builder.getStringAttr(fieldName));2849  result.addAttribute(getTypeAttrName(), mlir::TypeAttr::get(recTy));2850  result.addOperands(operands);2851}2852 2853llvm::SmallVector<mlir::Attribute> fir::LenParamIndexOp::getAttributes() {2854  llvm::SmallVector<mlir::Attribute> attrs;2855  attrs.push_back(getFieldIdAttr());2856  attrs.push_back(getOnTypeAttr());2857  return attrs;2858}2859 2860//===----------------------------------------------------------------------===//2861// LoadOp2862//===----------------------------------------------------------------------===//2863 2864void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,2865                        mlir::Value refVal) {2866  if (!refVal) {2867    mlir::emitError(result.location, "LoadOp has null argument");2868    return;2869  }2870  auto eleTy = fir::dyn_cast_ptrEleTy(refVal.getType());2871  if (!eleTy) {2872    mlir::emitError(result.location, "not a memory reference type");2873    return;2874  }2875  build(builder, result, eleTy, refVal);2876}2877 2878void fir::LoadOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,2879                        mlir::Type resTy, mlir::Value refVal) {2880 2881  if (!refVal) {2882    mlir::emitError(result.location, "LoadOp has null argument");2883    return;2884  }2885  result.addOperands(refVal);2886  result.addTypes(resTy);2887}2888 2889mlir::ParseResult fir::LoadOp::getElementOf(mlir::Type &ele, mlir::Type ref) {2890  if ((ele = fir::dyn_cast_ptrEleTy(ref)))2891    return mlir::success();2892  return mlir::failure();2893}2894 2895mlir::ParseResult fir::LoadOp::parse(mlir::OpAsmParser &parser,2896                                     mlir::OperationState &result) {2897  mlir::Type type;2898  mlir::OpAsmParser::UnresolvedOperand oper;2899  if (parser.parseOperand(oper) ||2900      parser.parseOptionalAttrDict(result.attributes) ||2901      parser.parseColonType(type) ||2902      parser.resolveOperand(oper, type, result.operands))2903    return mlir::failure();2904  mlir::Type eleTy;2905  if (fir::LoadOp::getElementOf(eleTy, type) ||2906      parser.addTypeToList(eleTy, result.types))2907    return mlir::failure();2908  return mlir::success();2909}2910 2911void fir::LoadOp::print(mlir::OpAsmPrinter &p) {2912  p << ' ';2913  p.printOperand(getMemref());2914  p.printOptionalAttrDict(getOperation()->getAttrs(), {});2915  p << " : " << getMemref().getType();2916}2917 2918void fir::LoadOp::getEffects(2919    llvm::SmallVectorImpl<2920        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>2921        &effects) {2922  effects.emplace_back(mlir::MemoryEffects::Read::get(), &getMemrefMutable(),2923                       mlir::SideEffects::DefaultResource::get());2924  addVolatileMemoryEffects({getMemref().getType()}, effects);2925}2926 2927//===----------------------------------------------------------------------===//2928// DoLoopOp2929//===----------------------------------------------------------------------===//2930 2931void fir::DoLoopOp::build(mlir::OpBuilder &builder,2932                          mlir::OperationState &result, mlir::Value lb,2933                          mlir::Value ub, mlir::Value step, bool unordered,2934                          bool finalCountValue, mlir::ValueRange iterArgs,2935                          mlir::ValueRange reduceOperands,2936                          llvm::ArrayRef<mlir::Attribute> reduceAttrs,2937                          llvm::ArrayRef<mlir::NamedAttribute> attributes) {2938  result.addOperands({lb, ub, step});2939  result.addOperands(reduceOperands);2940  result.addOperands(iterArgs);2941  result.addAttribute(getOperandSegmentSizeAttr(),2942                      builder.getDenseI32ArrayAttr(2943                          {1, 1, 1, static_cast<int32_t>(reduceOperands.size()),2944                           static_cast<int32_t>(iterArgs.size())}));2945  if (finalCountValue) {2946    result.addTypes(builder.getIndexType());2947    result.addAttribute(getFinalValueAttrName(result.name),2948                        builder.getUnitAttr());2949  }2950  for (auto v : iterArgs)2951    result.addTypes(v.getType());2952  mlir::Region *bodyRegion = result.addRegion();2953  bodyRegion->push_back(new mlir::Block{});2954  if (iterArgs.empty() && !finalCountValue)2955    fir::DoLoopOp::ensureTerminator(*bodyRegion, builder, result.location);2956  bodyRegion->front().addArgument(builder.getIndexType(), result.location);2957  bodyRegion->front().addArguments(2958      iterArgs.getTypes(),2959      llvm::SmallVector<mlir::Location>(iterArgs.size(), result.location));2960  if (unordered)2961    result.addAttribute(getUnorderedAttrName(result.name),2962                        builder.getUnitAttr());2963  if (!reduceAttrs.empty())2964    result.addAttribute(getReduceAttrsAttrName(result.name),2965                        builder.getArrayAttr(reduceAttrs));2966  result.addAttributes(attributes);2967}2968 2969mlir::ParseResult fir::DoLoopOp::parse(mlir::OpAsmParser &parser,2970                                       mlir::OperationState &result) {2971  auto &builder = parser.getBuilder();2972  mlir::OpAsmParser::Argument inductionVariable;2973  mlir::OpAsmParser::UnresolvedOperand lb, ub, step;2974  // Parse the induction variable followed by '='.2975  if (parser.parseArgument(inductionVariable) || parser.parseEqual())2976    return mlir::failure();2977 2978  // Parse loop bounds.2979  auto indexType = builder.getIndexType();2980  if (parser.parseOperand(lb) ||2981      parser.resolveOperand(lb, indexType, result.operands) ||2982      parser.parseKeyword("to") || parser.parseOperand(ub) ||2983      parser.resolveOperand(ub, indexType, result.operands) ||2984      parser.parseKeyword("step") || parser.parseOperand(step) ||2985      parser.resolveOperand(step, indexType, result.operands))2986    return mlir::failure();2987 2988  if (mlir::succeeded(parser.parseOptionalKeyword("unordered")))2989    result.addAttribute("unordered", builder.getUnitAttr());2990 2991  // Parse the reduction arguments.2992  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> reduceOperands;2993  llvm::SmallVector<mlir::Type> reduceArgTypes;2994  if (succeeded(parser.parseOptionalKeyword("reduce"))) {2995    // Parse reduction attributes and variables.2996    llvm::SmallVector<ReduceAttr> attributes;2997    if (failed(parser.parseCommaSeparatedList(2998            mlir::AsmParser::Delimiter::Paren, [&]() {2999              if (parser.parseAttribute(attributes.emplace_back()) ||3000                  parser.parseArrow() ||3001                  parser.parseOperand(reduceOperands.emplace_back()) ||3002                  parser.parseColonType(reduceArgTypes.emplace_back()))3003                return mlir::failure();3004              return mlir::success();3005            })))3006      return mlir::failure();3007    // Resolve input operands.3008    for (auto operand_type : llvm::zip(reduceOperands, reduceArgTypes))3009      if (parser.resolveOperand(std::get<0>(operand_type),3010                                std::get<1>(operand_type), result.operands))3011        return mlir::failure();3012    llvm::SmallVector<mlir::Attribute> arrayAttr(attributes.begin(),3013                                                 attributes.end());3014    result.addAttribute(getReduceAttrsAttrName(result.name),3015                        builder.getArrayAttr(arrayAttr));3016  }3017 3018  // Parse the optional initial iteration arguments.3019  llvm::SmallVector<mlir::OpAsmParser::Argument> regionArgs;3020  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> iterOperands;3021  llvm::SmallVector<mlir::Type> argTypes;3022  bool prependCount = false;3023  regionArgs.push_back(inductionVariable);3024 3025  if (succeeded(parser.parseOptionalKeyword("iter_args"))) {3026    // Parse assignment list and results type list.3027    if (parser.parseAssignmentList(regionArgs, iterOperands) ||3028        parser.parseArrowTypeList(result.types))3029      return mlir::failure();3030    if (result.types.size() == iterOperands.size() + 1)3031      prependCount = true;3032    // Resolve input operands.3033    llvm::ArrayRef<mlir::Type> resTypes = result.types;3034    for (auto operand_type : llvm::zip(3035             iterOperands, prependCount ? resTypes.drop_front() : resTypes))3036      if (parser.resolveOperand(std::get<0>(operand_type),3037                                std::get<1>(operand_type), result.operands))3038        return mlir::failure();3039  } else if (succeeded(parser.parseOptionalArrow())) {3040    if (parser.parseKeyword("index"))3041      return mlir::failure();3042    result.types.push_back(indexType);3043    prependCount = true;3044  }3045 3046  // Set the operandSegmentSizes attribute3047  result.addAttribute(getOperandSegmentSizeAttr(),3048                      builder.getDenseI32ArrayAttr(3049                          {1, 1, 1, static_cast<int32_t>(reduceOperands.size()),3050                           static_cast<int32_t>(iterOperands.size())}));3051 3052  if (parser.parseOptionalAttrDictWithKeyword(result.attributes))3053    return mlir::failure();3054 3055  // Induction variable.3056  if (prependCount)3057    result.addAttribute(DoLoopOp::getFinalValueAttrName(result.name),3058                        builder.getUnitAttr());3059  else3060    argTypes.push_back(indexType);3061  // Loop carried variables3062  argTypes.append(result.types.begin(), result.types.end());3063  // Parse the body region.3064  auto *body = result.addRegion();3065  if (regionArgs.size() != argTypes.size())3066    return parser.emitError(3067        parser.getNameLoc(),3068        "mismatch in number of loop-carried values and defined values");3069  for (size_t i = 0, e = regionArgs.size(); i != e; ++i)3070    regionArgs[i].type = argTypes[i];3071 3072  if (parser.parseRegion(*body, regionArgs))3073    return mlir::failure();3074 3075  DoLoopOp::ensureTerminator(*body, builder, result.location);3076 3077  return mlir::success();3078}3079 3080fir::DoLoopOp fir::getForInductionVarOwner(mlir::Value val) {3081  auto ivArg = mlir::dyn_cast<mlir::BlockArgument>(val);3082  if (!ivArg)3083    return {};3084  assert(ivArg.getOwner() && "unlinked block argument");3085  auto *containingInst = ivArg.getOwner()->getParentOp();3086  return mlir::dyn_cast_or_null<fir::DoLoopOp>(containingInst);3087}3088 3089// Lifted from loop.loop3090llvm::LogicalResult fir::DoLoopOp::verify() {3091  // Check that the body defines as single block argument for the induction3092  // variable.3093  auto *body = getBody();3094  if (!body->getArgument(0).getType().isIndex())3095    return emitOpError(3096        "expected body first argument to be an index argument for "3097        "the induction variable");3098 3099  auto opNumResults = getNumResults();3100  if (opNumResults == 0)3101    return mlir::success();3102 3103  if (getFinalValue()) {3104    if (getUnordered())3105      return emitOpError("unordered loop has no final value");3106    opNumResults--;3107  }3108  if (getNumIterOperands() != opNumResults)3109    return emitOpError(3110        "mismatch in number of loop-carried values and defined values");3111  if (getNumRegionIterArgs() != opNumResults)3112    return emitOpError(3113        "mismatch in number of basic block args and defined values");3114  auto iterOperands = getIterOperands();3115  auto iterArgs = getRegionIterArgs();3116  auto opResults = getFinalValue() ? getResults().drop_front() : getResults();3117  unsigned i = 0u;3118  for (auto e : llvm::zip(iterOperands, iterArgs, opResults)) {3119    if (std::get<0>(e).getType() != std::get<2>(e).getType())3120      return emitOpError() << "types mismatch between " << i3121                           << "th iter operand and defined value";3122    if (std::get<1>(e).getType() != std::get<2>(e).getType())3123      return emitOpError() << "types mismatch between " << i3124                           << "th iter region arg and defined value";3125 3126    i++;3127  }3128  auto reduceAttrs = getReduceAttrsAttr();3129  if (getNumReduceOperands() != (reduceAttrs ? reduceAttrs.size() : 0))3130    return emitOpError(3131        "mismatch in number of reduction variables and reduction attributes");3132  return mlir::success();3133}3134 3135void fir::DoLoopOp::print(mlir::OpAsmPrinter &p) {3136  bool printBlockTerminators = false;3137  p << ' ' << getInductionVar() << " = " << getLowerBound() << " to "3138    << getUpperBound() << " step " << getStep();3139  if (getUnordered())3140    p << " unordered";3141  if (hasReduceOperands()) {3142    p << " reduce(";3143    auto attrs = getReduceAttrsAttr();3144    auto operands = getReduceOperands();3145    llvm::interleaveComma(llvm::zip(attrs, operands), p, [&](auto it) {3146      p << std::get<0>(it) << " -> " << std::get<1>(it) << " : "3147        << std::get<1>(it).getType();3148    });3149    p << ')';3150    printBlockTerminators = true;3151  }3152  if (hasIterOperands()) {3153    p << " iter_args(";3154    auto regionArgs = getRegionIterArgs();3155    auto operands = getIterOperands();3156    llvm::interleaveComma(llvm::zip(regionArgs, operands), p, [&](auto it) {3157      p << std::get<0>(it) << " = " << std::get<1>(it);3158    });3159    p << ") -> (" << getResultTypes() << ')';3160    printBlockTerminators = true;3161  } else if (getFinalValue()) {3162    p << " -> " << getResultTypes();3163    printBlockTerminators = true;3164  }3165  p.printOptionalAttrDictWithKeyword(3166      (*this)->getAttrs(),3167      {"unordered", "finalValue", "reduceAttrs", "operandSegmentSizes"});3168  p << ' ';3169  p.printRegion(getRegion(), /*printEntryBlockArgs=*/false,3170                printBlockTerminators);3171}3172 3173llvm::SmallVector<mlir::Region *> fir::DoLoopOp::getLoopRegions() {3174  return {&getRegion()};3175}3176 3177/// Translate a value passed as an iter_arg to the corresponding block3178/// argument in the body of the loop.3179mlir::BlockArgument fir::DoLoopOp::iterArgToBlockArg(mlir::Value iterArg) {3180  for (auto i : llvm::enumerate(getInitArgs()))3181    if (iterArg == i.value())3182      return getRegion().front().getArgument(i.index() + 1);3183  return {};3184}3185 3186/// Translate the result vector (by index number) to the corresponding value3187/// to the `fir.result` Op.3188void fir::DoLoopOp::resultToSourceOps(3189    llvm::SmallVectorImpl<mlir::Value> &results, unsigned resultNum) {3190  auto oper = getFinalValue() ? resultNum + 1 : resultNum;3191  auto *term = getRegion().front().getTerminator();3192  if (oper < term->getNumOperands())3193    results.push_back(term->getOperand(oper));3194}3195 3196/// Translate the block argument (by index number) to the corresponding value3197/// passed as an iter_arg to the parent DoLoopOp.3198mlir::Value fir::DoLoopOp::blockArgToSourceOp(unsigned blockArgNum) {3199  if (blockArgNum > 0 && blockArgNum <= getInitArgs().size())3200    return getInitArgs()[blockArgNum - 1];3201  return {};3202}3203 3204std::optional<llvm::MutableArrayRef<mlir::OpOperand>>3205fir::DoLoopOp::getYieldedValuesMutable() {3206  auto *term = getRegion().front().getTerminator();3207  return getFinalValue() ? term->getOpOperands().drop_front()3208                         : term->getOpOperands();3209}3210 3211//===----------------------------------------------------------------------===//3212// DTEntryOp3213//===----------------------------------------------------------------------===//3214 3215mlir::ParseResult fir::DTEntryOp::parse(mlir::OpAsmParser &parser,3216                                        mlir::OperationState &result) {3217  llvm::StringRef methodName;3218  // allow `methodName` or `"methodName"`3219  if (failed(parser.parseOptionalKeyword(&methodName))) {3220    mlir::StringAttr methodAttr;3221    if (parser.parseAttribute(methodAttr, getMethodAttrName(result.name),3222                              result.attributes))3223      return mlir::failure();3224  } else {3225    result.addAttribute(getMethodAttrName(result.name),3226                        parser.getBuilder().getStringAttr(methodName));3227  }3228  mlir::SymbolRefAttr calleeAttr;3229  if (parser.parseComma() ||3230      parser.parseAttribute(calleeAttr, fir::DTEntryOp::getProcAttrNameStr(),3231                            result.attributes))3232    return mlir::failure();3233  return mlir::success();3234}3235 3236void fir::DTEntryOp::print(mlir::OpAsmPrinter &p) {3237  p << ' ' << getMethodAttr() << ", " << getProcAttr();3238}3239 3240//===----------------------------------------------------------------------===//3241// ReboxOp3242//===----------------------------------------------------------------------===//3243 3244/// Get the scalar type related to a fir.box type.3245/// Example: return f32 for !fir.box<!fir.heap<!fir.array<?x?xf32>>.3246static mlir::Type getBoxScalarEleTy(mlir::Type boxTy) {3247  auto eleTy = fir::dyn_cast_ptrOrBoxEleTy(boxTy);3248  if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(eleTy))3249    return seqTy.getEleTy();3250  return eleTy;3251}3252 3253/// Test if \p t1 and \p t2 are compatible character types (if they can3254/// represent the same type at runtime).3255static bool areCompatibleCharacterTypes(mlir::Type t1, mlir::Type t2) {3256  auto c1 = mlir::dyn_cast<fir::CharacterType>(t1);3257  auto c2 = mlir::dyn_cast<fir::CharacterType>(t2);3258  if (!c1 || !c2)3259    return false;3260  if (c1.hasDynamicLen() || c2.hasDynamicLen())3261    return true;3262  return c1.getLen() == c2.getLen();3263}3264 3265llvm::LogicalResult fir::ReboxOp::verify() {3266  auto inputBoxTy = getBox().getType();3267  if (fir::isa_unknown_size_box(inputBoxTy))3268    return emitOpError("box operand must not have unknown rank or type");3269  auto outBoxTy = getType();3270  if (fir::isa_unknown_size_box(outBoxTy))3271    return emitOpError("result type must not have unknown rank or type");3272  auto inputRank = fir::getBoxRank(inputBoxTy);3273  auto inputEleTy = getBoxScalarEleTy(inputBoxTy);3274  auto outRank = fir::getBoxRank(outBoxTy);3275  auto outEleTy = getBoxScalarEleTy(outBoxTy);3276 3277  if (auto sliceVal = getSlice()) {3278    // Slicing case3279    if (mlir::cast<fir::SliceType>(sliceVal.getType()).getRank() != inputRank)3280      return emitOpError("slice operand rank must match box operand rank");3281    if (auto shapeVal = getShape()) {3282      if (auto shiftTy = mlir::dyn_cast<fir::ShiftType>(shapeVal.getType())) {3283        if (shiftTy.getRank() != inputRank)3284          return emitOpError("shape operand and input box ranks must match "3285                             "when there is a slice");3286      } else {3287        return emitOpError("shape operand must absent or be a fir.shift "3288                           "when there is a slice");3289      }3290    }3291    if (auto sliceOp = sliceVal.getDefiningOp()) {3292      auto slicedRank = mlir::cast<fir::SliceOp>(sliceOp).getOutRank();3293      if (slicedRank != outRank)3294        return emitOpError("result type rank and rank after applying slice "3295                           "operand must match");3296    }3297  } else {3298    // Reshaping case3299    unsigned shapeRank = inputRank;3300    if (auto shapeVal = getShape()) {3301      auto ty = shapeVal.getType();3302      if (auto shapeTy = mlir::dyn_cast<fir::ShapeType>(ty)) {3303        shapeRank = shapeTy.getRank();3304      } else if (auto shapeShiftTy = mlir::dyn_cast<fir::ShapeShiftType>(ty)) {3305        shapeRank = shapeShiftTy.getRank();3306      } else {3307        auto shiftTy = mlir::cast<fir::ShiftType>(ty);3308        shapeRank = shiftTy.getRank();3309        if (shapeRank != inputRank)3310          return emitOpError("shape operand and input box ranks must match "3311                             "when the shape is a fir.shift");3312      }3313    }3314    if (shapeRank != outRank)3315      return emitOpError("result type and shape operand ranks must match");3316  }3317 3318  if (inputEleTy != outEleTy) {3319    // TODO: check that outBoxTy is a parent type of inputBoxTy for derived3320    // types.3321    // Character input and output types with constant length may be different if3322    // there is a substring in the slice, otherwise, they must match. If any of3323    // the types is a character with dynamic length, the other type can be any3324    // character type.3325    const bool typeCanMismatch =3326        mlir::isa<fir::RecordType>(inputEleTy) ||3327        mlir::isa<mlir::NoneType>(outEleTy) ||3328        (mlir::isa<mlir::NoneType>(inputEleTy) &&3329         mlir::isa<fir::RecordType>(outEleTy)) ||3330        (getSlice() && mlir::isa<fir::CharacterType>(inputEleTy)) ||3331        (getSlice() && fir::isa_complex(inputEleTy) &&3332         mlir::isa<mlir::FloatType>(outEleTy)) ||3333        areCompatibleCharacterTypes(inputEleTy, outEleTy);3334    if (!typeCanMismatch)3335      return emitOpError(3336          "op input and output element types must match for intrinsic types");3337  }3338  return mlir::success();3339}3340 3341std::optional<std::int64_t> fir::ReboxOp::getViewOffset(mlir::OpResult) {3342  // The address offset is zero, unless there is a slice.3343  // TODO: we can handle slices that leave the base address untouched.3344  if (!getSlice())3345    return 0;3346  return std::nullopt;3347}3348 3349//===----------------------------------------------------------------------===//3350// ReboxAssumedRankOp3351//===----------------------------------------------------------------------===//3352 3353static bool areCompatibleAssumedRankElementType(mlir::Type inputEleTy,3354                                                mlir::Type outEleTy) {3355  if (inputEleTy == outEleTy)3356    return true;3357  // Output is unlimited polymorphic -> output dynamic type is the same as input3358  // type.3359  if (mlir::isa<mlir::NoneType>(outEleTy))3360    return true;3361  // Output/Input are derived types. Assuming input extends output type, output3362  // dynamic type is the output static type, unless output is polymorphic.3363  if (mlir::isa<fir::RecordType>(inputEleTy) &&3364      mlir::isa<fir::RecordType>(outEleTy))3365    return true;3366  if (areCompatibleCharacterTypes(inputEleTy, outEleTy))3367    return true;3368  return false;3369}3370 3371llvm::LogicalResult fir::ReboxAssumedRankOp::verify() {3372  mlir::Type inputType = getBox().getType();3373  if (!mlir::isa<fir::BaseBoxType>(inputType) && !fir::isBoxAddress(inputType))3374    return emitOpError("input must be a box or box address");3375  mlir::Type inputEleTy =3376      mlir::cast<fir::BaseBoxType>(fir::unwrapRefType(inputType))3377          .unwrapInnerType();3378  mlir::Type outEleTy =3379      mlir::cast<fir::BaseBoxType>(getType()).unwrapInnerType();3380  if (!areCompatibleAssumedRankElementType(inputEleTy, outEleTy))3381    return emitOpError("input and output element types are incompatible");3382  return mlir::success();3383}3384 3385void fir::ReboxAssumedRankOp::getEffects(3386    llvm::SmallVectorImpl<3387        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>3388        &effects) {3389  mlir::OpOperand &inputBox = getBoxMutable();3390  if (fir::isBoxAddress(inputBox.get().getType()))3391    effects.emplace_back(mlir::MemoryEffects::Read::get(), &inputBox,3392                         mlir::SideEffects::DefaultResource::get());3393}3394 3395//===----------------------------------------------------------------------===//3396// ResultOp3397//===----------------------------------------------------------------------===//3398 3399llvm::LogicalResult fir::ResultOp::verify() {3400  auto *parentOp = (*this)->getParentOp();3401  auto results = parentOp->getResults();3402  auto operands = (*this)->getOperands();3403 3404  if (parentOp->getNumResults() != getNumOperands())3405    return emitOpError() << "parent of result must have same arity";3406  for (auto e : llvm::zip(results, operands))3407    if (std::get<0>(e).getType() != std::get<1>(e).getType())3408      return emitOpError() << "types mismatch between result op and its parent";3409  return mlir::success();3410}3411 3412//===----------------------------------------------------------------------===//3413// SaveResultOp3414//===----------------------------------------------------------------------===//3415 3416llvm::LogicalResult fir::SaveResultOp::verify() {3417  auto resultType = getValue().getType();3418  if (resultType != fir::dyn_cast_ptrEleTy(getMemref().getType()))3419    return emitOpError("value type must match memory reference type");3420  if (fir::isa_unknown_size_box(resultType))3421    return emitOpError("cannot save !fir.box of unknown rank or type");3422 3423  if (mlir::isa<fir::BoxType>(resultType)) {3424    if (getShape() || !getTypeparams().empty())3425      return emitOpError(3426          "must not have shape or length operands if the value is a fir.box");3427    return mlir::success();3428  }3429 3430  // fir.record or fir.array case.3431  unsigned shapeTyRank = 0;3432  if (auto shapeVal = getShape()) {3433    auto shapeTy = shapeVal.getType();3434    if (auto s = mlir::dyn_cast<fir::ShapeType>(shapeTy))3435      shapeTyRank = s.getRank();3436    else3437      shapeTyRank = mlir::cast<fir::ShapeShiftType>(shapeTy).getRank();3438  }3439 3440  auto eleTy = resultType;3441  if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(resultType)) {3442    if (seqTy.getDimension() != shapeTyRank)3443      return emitOpError(3444          "shape operand must be provided and have the value rank "3445          "when the value is a fir.array");3446    eleTy = seqTy.getEleTy();3447  } else {3448    if (shapeTyRank != 0)3449      return emitOpError(3450          "shape operand should only be provided if the value is a fir.array");3451  }3452 3453  if (auto recTy = mlir::dyn_cast<fir::RecordType>(eleTy)) {3454    if (recTy.getNumLenParams() != getTypeparams().size())3455      return emitOpError(3456          "length parameters number must match with the value type "3457          "length parameters");3458  } else if (auto charTy = mlir::dyn_cast<fir::CharacterType>(eleTy)) {3459    if (getTypeparams().size() > 1)3460      return emitOpError(3461          "no more than one length parameter must be provided for "3462          "character value");3463  } else {3464    if (!getTypeparams().empty())3465      return emitOpError(3466          "length parameters must not be provided for this value type");3467  }3468 3469  return mlir::success();3470}3471 3472//===----------------------------------------------------------------------===//3473// IntegralSwitchTerminator3474//===----------------------------------------------------------------------===//3475static constexpr llvm::StringRef getCompareOffsetAttr() {3476  return "compare_operand_offsets";3477}3478 3479static constexpr llvm::StringRef getTargetOffsetAttr() {3480  return "target_operand_offsets";3481}3482 3483template <typename OpT>3484static llvm::LogicalResult verifyIntegralSwitchTerminator(OpT op) {3485  if (!mlir::isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType>(3486          op.getSelector().getType()))3487    return op.emitOpError("must be an integer");3488  auto cases =3489      op->template getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr()).getValue();3490  auto count = op.getNumDest();3491  if (count == 0)3492    return op.emitOpError("must have at least one successor");3493  if (op.getNumConditions() != count)3494    return op.emitOpError("number of cases and targets don't match");3495  if (op.targetOffsetSize() != count)3496    return op.emitOpError("incorrect number of successor operand groups");3497  for (decltype(count) i = 0; i != count; ++i) {3498    if (!mlir::isa<mlir::IntegerAttr, mlir::UnitAttr>(cases[i]))3499      return op.emitOpError("invalid case alternative");3500  }3501  return mlir::success();3502}3503 3504static mlir::ParseResult parseIntegralSwitchTerminator(3505    mlir::OpAsmParser &parser, mlir::OperationState &result,3506    llvm::StringRef casesAttr, llvm::StringRef operandSegmentAttr) {3507  mlir::OpAsmParser::UnresolvedOperand selector;3508  mlir::Type type;3509  if (fir::parseSelector(parser, result, selector, type))3510    return mlir::failure();3511 3512  llvm::SmallVector<mlir::Attribute> ivalues;3513  llvm::SmallVector<mlir::Block *> dests;3514  llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;3515  while (true) {3516    mlir::Attribute ivalue; // Integer or Unit3517    mlir::Block *dest;3518    llvm::SmallVector<mlir::Value> destArg;3519    mlir::NamedAttrList temp;3520    if (parser.parseAttribute(ivalue, "i", temp) || parser.parseComma() ||3521        parser.parseSuccessorAndUseList(dest, destArg))3522      return mlir::failure();3523    ivalues.push_back(ivalue);3524    dests.push_back(dest);3525    destArgs.push_back(destArg);3526    if (!parser.parseOptionalRSquare())3527      break;3528    if (parser.parseComma())3529      return mlir::failure();3530  }3531  auto &bld = parser.getBuilder();3532  result.addAttribute(casesAttr, bld.getArrayAttr(ivalues));3533  llvm::SmallVector<int32_t> argOffs;3534  int32_t sumArgs = 0;3535  const auto count = dests.size();3536  for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {3537    result.addSuccessors(dests[i]);3538    result.addOperands(destArgs[i]);3539    auto argSize = destArgs[i].size();3540    argOffs.push_back(argSize);3541    sumArgs += argSize;3542  }3543  result.addAttribute(operandSegmentAttr,3544                      bld.getDenseI32ArrayAttr({1, 0, sumArgs}));3545  result.addAttribute(getTargetOffsetAttr(), bld.getDenseI32ArrayAttr(argOffs));3546  return mlir::success();3547}3548 3549template <typename OpT>3550static void printIntegralSwitchTerminator(OpT op, mlir::OpAsmPrinter &p) {3551  p << ' ';3552  p.printOperand(op.getSelector());3553  p << " : " << op.getSelector().getType() << " [";3554  auto cases =3555      op->template getAttrOfType<mlir::ArrayAttr>(op.getCasesAttr()).getValue();3556  auto count = op.getNumConditions();3557  for (decltype(count) i = 0; i != count; ++i) {3558    if (i)3559      p << ", ";3560    auto &attr = cases[i];3561    if (auto intAttr = mlir::dyn_cast_or_null<mlir::IntegerAttr>(attr))3562      p << intAttr.getValue();3563    else3564      p.printAttribute(attr);3565    p << ", ";3566    op.printSuccessorAtIndex(p, i);3567  }3568  p << ']';3569  p.printOptionalAttrDict(3570      op->getAttrs(), {op.getCasesAttr(), getCompareOffsetAttr(),3571                       getTargetOffsetAttr(), op.getOperandSegmentSizeAttr()});3572}3573 3574//===----------------------------------------------------------------------===//3575// SelectOp3576//===----------------------------------------------------------------------===//3577 3578llvm::LogicalResult fir::SelectOp::verify() {3579  return verifyIntegralSwitchTerminator(*this);3580}3581 3582mlir::ParseResult fir::SelectOp::parse(mlir::OpAsmParser &parser,3583                                       mlir::OperationState &result) {3584  return parseIntegralSwitchTerminator(parser, result, getCasesAttr(),3585                                       getOperandSegmentSizeAttr());3586}3587 3588void fir::SelectOp::print(mlir::OpAsmPrinter &p) {3589  printIntegralSwitchTerminator(*this, p);3590}3591 3592template <typename A, typename... AdditionalArgs>3593static A getSubOperands(unsigned pos, A allArgs, mlir::DenseI32ArrayAttr ranges,3594                        AdditionalArgs &&...additionalArgs) {3595  unsigned start = 0;3596  for (unsigned i = 0; i < pos; ++i)3597    start += ranges[i];3598  return allArgs.slice(start, ranges[pos],3599                       std::forward<AdditionalArgs>(additionalArgs)...);3600}3601 3602static mlir::MutableOperandRange3603getMutableSuccessorOperands(unsigned pos, mlir::MutableOperandRange operands,3604                            llvm::StringRef offsetAttr) {3605  mlir::Operation *owner = operands.getOwner();3606  mlir::NamedAttribute targetOffsetAttr =3607      *owner->getAttrDictionary().getNamed(offsetAttr);3608  return getSubOperands(3609      pos, operands,3610      mlir::cast<mlir::DenseI32ArrayAttr>(targetOffsetAttr.getValue()),3611      mlir::MutableOperandRange::OperandSegment(pos, targetOffsetAttr));3612}3613 3614std::optional<mlir::OperandRange> fir::SelectOp::getCompareOperands(unsigned) {3615  return {};3616}3617 3618std::optional<llvm::ArrayRef<mlir::Value>>3619fir::SelectOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {3620  return {};3621}3622 3623mlir::SuccessorOperands fir::SelectOp::getSuccessorOperands(unsigned oper) {3624  return mlir::SuccessorOperands(::getMutableSuccessorOperands(3625      oper, getTargetArgsMutable(), getTargetOffsetAttr()));3626}3627 3628std::optional<llvm::ArrayRef<mlir::Value>>3629fir::SelectOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,3630                                    unsigned oper) {3631  auto a =3632      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());3633  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3634      getOperandSegmentSizeAttr());3635  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};3636}3637 3638std::optional<mlir::ValueRange>3639fir::SelectOp::getSuccessorOperands(mlir::ValueRange operands, unsigned oper) {3640  auto a =3641      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());3642  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3643      getOperandSegmentSizeAttr());3644  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};3645}3646 3647unsigned fir::SelectOp::targetOffsetSize() {3648  return (*this)3649      ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())3650      .size();3651}3652 3653//===----------------------------------------------------------------------===//3654// SelectCaseOp3655//===----------------------------------------------------------------------===//3656 3657std::optional<mlir::OperandRange>3658fir::SelectCaseOp::getCompareOperands(unsigned cond) {3659  auto a =3660      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr());3661  return {getSubOperands(cond, getCompareArgs(), a)};3662}3663 3664std::optional<llvm::ArrayRef<mlir::Value>>3665fir::SelectCaseOp::getCompareOperands(llvm::ArrayRef<mlir::Value> operands,3666                                      unsigned cond) {3667  auto a =3668      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr());3669  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3670      getOperandSegmentSizeAttr());3671  return {getSubOperands(cond, getSubOperands(1, operands, segments), a)};3672}3673 3674std::optional<mlir::ValueRange>3675fir::SelectCaseOp::getCompareOperands(mlir::ValueRange operands,3676                                      unsigned cond) {3677  auto a =3678      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr());3679  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3680      getOperandSegmentSizeAttr());3681  return {getSubOperands(cond, getSubOperands(1, operands, segments), a)};3682}3683 3684mlir::SuccessorOperands fir::SelectCaseOp::getSuccessorOperands(unsigned oper) {3685  return mlir::SuccessorOperands(::getMutableSuccessorOperands(3686      oper, getTargetArgsMutable(), getTargetOffsetAttr()));3687}3688 3689std::optional<llvm::ArrayRef<mlir::Value>>3690fir::SelectCaseOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,3691                                        unsigned oper) {3692  auto a =3693      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());3694  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3695      getOperandSegmentSizeAttr());3696  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};3697}3698 3699std::optional<mlir::ValueRange>3700fir::SelectCaseOp::getSuccessorOperands(mlir::ValueRange operands,3701                                        unsigned oper) {3702  auto a =3703      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());3704  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3705      getOperandSegmentSizeAttr());3706  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};3707}3708 3709// parser for fir.select_case Op3710mlir::ParseResult fir::SelectCaseOp::parse(mlir::OpAsmParser &parser,3711                                           mlir::OperationState &result) {3712  mlir::OpAsmParser::UnresolvedOperand selector;3713  mlir::Type type;3714  if (fir::parseSelector(parser, result, selector, type))3715    return mlir::failure();3716 3717  llvm::SmallVector<mlir::Attribute> attrs;3718  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> opers;3719  llvm::SmallVector<mlir::Block *> dests;3720  llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;3721  llvm::SmallVector<std::int32_t> argOffs;3722  std::int32_t offSize = 0;3723  while (true) {3724    mlir::Attribute attr;3725    mlir::Block *dest;3726    llvm::SmallVector<mlir::Value> destArg;3727    mlir::NamedAttrList temp;3728    if (parser.parseAttribute(attr, "a", temp) || isValidCaseAttr(attr) ||3729        parser.parseComma())3730      return mlir::failure();3731    attrs.push_back(attr);3732    if (mlir::dyn_cast_or_null<mlir::UnitAttr>(attr)) {3733      argOffs.push_back(0);3734    } else if (mlir::dyn_cast_or_null<fir::ClosedIntervalAttr>(attr)) {3735      mlir::OpAsmParser::UnresolvedOperand oper1;3736      mlir::OpAsmParser::UnresolvedOperand oper2;3737      if (parser.parseOperand(oper1) || parser.parseComma() ||3738          parser.parseOperand(oper2) || parser.parseComma())3739        return mlir::failure();3740      opers.push_back(oper1);3741      opers.push_back(oper2);3742      argOffs.push_back(2);3743      offSize += 2;3744    } else {3745      mlir::OpAsmParser::UnresolvedOperand oper;3746      if (parser.parseOperand(oper) || parser.parseComma())3747        return mlir::failure();3748      opers.push_back(oper);3749      argOffs.push_back(1);3750      ++offSize;3751    }3752    if (parser.parseSuccessorAndUseList(dest, destArg))3753      return mlir::failure();3754    dests.push_back(dest);3755    destArgs.push_back(destArg);3756    if (mlir::succeeded(parser.parseOptionalRSquare()))3757      break;3758    if (parser.parseComma())3759      return mlir::failure();3760  }3761  result.addAttribute(fir::SelectCaseOp::getCasesAttr(),3762                      parser.getBuilder().getArrayAttr(attrs));3763  if (parser.resolveOperands(opers, type, result.operands))3764    return mlir::failure();3765  llvm::SmallVector<int32_t> targOffs;3766  int32_t toffSize = 0;3767  const auto count = dests.size();3768  for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {3769    result.addSuccessors(dests[i]);3770    result.addOperands(destArgs[i]);3771    auto argSize = destArgs[i].size();3772    targOffs.push_back(argSize);3773    toffSize += argSize;3774  }3775  auto &bld = parser.getBuilder();3776  result.addAttribute(fir::SelectCaseOp::getOperandSegmentSizeAttr(),3777                      bld.getDenseI32ArrayAttr({1, offSize, toffSize}));3778  result.addAttribute(getCompareOffsetAttr(),3779                      bld.getDenseI32ArrayAttr(argOffs));3780  result.addAttribute(getTargetOffsetAttr(),3781                      bld.getDenseI32ArrayAttr(targOffs));3782  return mlir::success();3783}3784 3785void fir::SelectCaseOp::print(mlir::OpAsmPrinter &p) {3786  p << ' ';3787  p.printOperand(getSelector());3788  p << " : " << getSelector().getType() << " [";3789  auto cases =3790      getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();3791  auto count = getNumConditions();3792  for (decltype(count) i = 0; i != count; ++i) {3793    if (i)3794      p << ", ";3795    p << cases[i] << ", ";3796    if (!mlir::isa<mlir::UnitAttr>(cases[i])) {3797      auto caseArgs = *getCompareOperands(i);3798      p.printOperand(*caseArgs.begin());3799      p << ", ";3800      if (mlir::isa<fir::ClosedIntervalAttr>(cases[i])) {3801        p.printOperand(*(++caseArgs.begin()));3802        p << ", ";3803      }3804    }3805    printSuccessorAtIndex(p, i);3806  }3807  p << ']';3808  p.printOptionalAttrDict(getOperation()->getAttrs(),3809                          {getCasesAttr(), getCompareOffsetAttr(),3810                           getTargetOffsetAttr(), getOperandSegmentSizeAttr()});3811}3812 3813unsigned fir::SelectCaseOp::compareOffsetSize() {3814  return (*this)3815      ->getAttrOfType<mlir::DenseI32ArrayAttr>(getCompareOffsetAttr())3816      .size();3817}3818 3819unsigned fir::SelectCaseOp::targetOffsetSize() {3820  return (*this)3821      ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())3822      .size();3823}3824 3825void fir::SelectCaseOp::build(mlir::OpBuilder &builder,3826                              mlir::OperationState &result,3827                              mlir::Value selector,3828                              llvm::ArrayRef<mlir::Attribute> compareAttrs,3829                              llvm::ArrayRef<mlir::ValueRange> cmpOperands,3830                              llvm::ArrayRef<mlir::Block *> destinations,3831                              llvm::ArrayRef<mlir::ValueRange> destOperands,3832                              llvm::ArrayRef<mlir::NamedAttribute> attributes) {3833  result.addOperands(selector);3834  result.addAttribute(getCasesAttr(), builder.getArrayAttr(compareAttrs));3835  llvm::SmallVector<int32_t> operOffs;3836  int32_t operSize = 0;3837  for (auto attr : compareAttrs) {3838    if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {3839      operOffs.push_back(2);3840      operSize += 2;3841    } else if (mlir::isa<mlir::UnitAttr>(attr)) {3842      operOffs.push_back(0);3843    } else {3844      operOffs.push_back(1);3845      ++operSize;3846    }3847  }3848  for (auto ops : cmpOperands)3849    result.addOperands(ops);3850  result.addAttribute(getCompareOffsetAttr(),3851                      builder.getDenseI32ArrayAttr(operOffs));3852  const auto count = destinations.size();3853  for (auto d : destinations)3854    result.addSuccessors(d);3855  const auto opCount = destOperands.size();3856  llvm::SmallVector<std::int32_t> argOffs;3857  std::int32_t sumArgs = 0;3858  for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {3859    if (i < opCount) {3860      result.addOperands(destOperands[i]);3861      const auto argSz = destOperands[i].size();3862      argOffs.push_back(argSz);3863      sumArgs += argSz;3864    } else {3865      argOffs.push_back(0);3866    }3867  }3868  result.addAttribute(getOperandSegmentSizeAttr(),3869                      builder.getDenseI32ArrayAttr({1, operSize, sumArgs}));3870  result.addAttribute(getTargetOffsetAttr(),3871                      builder.getDenseI32ArrayAttr(argOffs));3872  result.addAttributes(attributes);3873}3874 3875/// This builder has a slightly simplified interface in that the list of3876/// operands need not be partitioned by the builder. Instead the operands are3877/// partitioned here, before being passed to the default builder. This3878/// partitioning is unchecked, so can go awry on bad input.3879void fir::SelectCaseOp::build(mlir::OpBuilder &builder,3880                              mlir::OperationState &result,3881                              mlir::Value selector,3882                              llvm::ArrayRef<mlir::Attribute> compareAttrs,3883                              llvm::ArrayRef<mlir::Value> cmpOpList,3884                              llvm::ArrayRef<mlir::Block *> destinations,3885                              llvm::ArrayRef<mlir::ValueRange> destOperands,3886                              llvm::ArrayRef<mlir::NamedAttribute> attributes) {3887  llvm::SmallVector<mlir::ValueRange> cmpOpers;3888  auto iter = cmpOpList.begin();3889  for (auto &attr : compareAttrs) {3890    if (mlir::isa<fir::ClosedIntervalAttr>(attr)) {3891      cmpOpers.push_back(mlir::ValueRange({iter, iter + 2}));3892      iter += 2;3893    } else if (mlir::isa<mlir::UnitAttr>(attr)) {3894      cmpOpers.push_back(mlir::ValueRange{});3895    } else {3896      cmpOpers.push_back(mlir::ValueRange({iter, iter + 1}));3897      ++iter;3898    }3899  }3900  build(builder, result, selector, compareAttrs, cmpOpers, destinations,3901        destOperands, attributes);3902}3903 3904llvm::LogicalResult fir::SelectCaseOp::verify() {3905  if (!mlir::isa<mlir::IntegerType, mlir::IndexType, fir::IntegerType,3906                 fir::LogicalType, fir::CharacterType>(getSelector().getType()))3907    return emitOpError("must be an integer, character, or logical");3908  auto cases =3909      getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();3910  auto count = getNumDest();3911  if (count == 0)3912    return emitOpError("must have at least one successor");3913  if (getNumConditions() != count)3914    return emitOpError("number of conditions and successors don't match");3915  if (compareOffsetSize() != count)3916    return emitOpError("incorrect number of compare operand groups");3917  if (targetOffsetSize() != count)3918    return emitOpError("incorrect number of successor operand groups");3919  for (decltype(count) i = 0; i != count; ++i) {3920    auto &attr = cases[i];3921    if (!(mlir::isa<fir::PointIntervalAttr>(attr) ||3922          mlir::isa<fir::LowerBoundAttr>(attr) ||3923          mlir::isa<fir::UpperBoundAttr>(attr) ||3924          mlir::isa<fir::ClosedIntervalAttr>(attr) ||3925          mlir::isa<mlir::UnitAttr>(attr)))3926      return emitOpError("incorrect select case attribute type");3927  }3928  return mlir::success();3929}3930 3931//===----------------------------------------------------------------------===//3932// SelectRankOp3933//===----------------------------------------------------------------------===//3934 3935llvm::LogicalResult fir::SelectRankOp::verify() {3936  return verifyIntegralSwitchTerminator(*this);3937}3938 3939mlir::ParseResult fir::SelectRankOp::parse(mlir::OpAsmParser &parser,3940                                           mlir::OperationState &result) {3941  return parseIntegralSwitchTerminator(parser, result, getCasesAttr(),3942                                       getOperandSegmentSizeAttr());3943}3944 3945void fir::SelectRankOp::print(mlir::OpAsmPrinter &p) {3946  printIntegralSwitchTerminator(*this, p);3947}3948 3949std::optional<mlir::OperandRange>3950fir::SelectRankOp::getCompareOperands(unsigned) {3951  return {};3952}3953 3954std::optional<llvm::ArrayRef<mlir::Value>>3955fir::SelectRankOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {3956  return {};3957}3958 3959mlir::SuccessorOperands fir::SelectRankOp::getSuccessorOperands(unsigned oper) {3960  return mlir::SuccessorOperands(::getMutableSuccessorOperands(3961      oper, getTargetArgsMutable(), getTargetOffsetAttr()));3962}3963 3964std::optional<llvm::ArrayRef<mlir::Value>>3965fir::SelectRankOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,3966                                        unsigned oper) {3967  auto a =3968      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());3969  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3970      getOperandSegmentSizeAttr());3971  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};3972}3973 3974std::optional<mlir::ValueRange>3975fir::SelectRankOp::getSuccessorOperands(mlir::ValueRange operands,3976                                        unsigned oper) {3977  auto a =3978      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());3979  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(3980      getOperandSegmentSizeAttr());3981  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};3982}3983 3984unsigned fir::SelectRankOp::targetOffsetSize() {3985  return (*this)3986      ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())3987      .size();3988}3989 3990//===----------------------------------------------------------------------===//3991// SelectTypeOp3992//===----------------------------------------------------------------------===//3993 3994std::optional<mlir::OperandRange>3995fir::SelectTypeOp::getCompareOperands(unsigned) {3996  return {};3997}3998 3999std::optional<llvm::ArrayRef<mlir::Value>>4000fir::SelectTypeOp::getCompareOperands(llvm::ArrayRef<mlir::Value>, unsigned) {4001  return {};4002}4003 4004mlir::SuccessorOperands fir::SelectTypeOp::getSuccessorOperands(unsigned oper) {4005  return mlir::SuccessorOperands(::getMutableSuccessorOperands(4006      oper, getTargetArgsMutable(), getTargetOffsetAttr()));4007}4008 4009std::optional<llvm::ArrayRef<mlir::Value>>4010fir::SelectTypeOp::getSuccessorOperands(llvm::ArrayRef<mlir::Value> operands,4011                                        unsigned oper) {4012  auto a =4013      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());4014  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(4015      getOperandSegmentSizeAttr());4016  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};4017}4018 4019std::optional<mlir::ValueRange>4020fir::SelectTypeOp::getSuccessorOperands(mlir::ValueRange operands,4021                                        unsigned oper) {4022  auto a =4023      (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr());4024  auto segments = (*this)->getAttrOfType<mlir::DenseI32ArrayAttr>(4025      getOperandSegmentSizeAttr());4026  return {getSubOperands(oper, getSubOperands(2, operands, segments), a)};4027}4028 4029mlir::ParseResult fir::SelectTypeOp::parse(mlir::OpAsmParser &parser,4030                                           mlir::OperationState &result) {4031  mlir::OpAsmParser::UnresolvedOperand selector;4032  mlir::Type type;4033  if (fir::parseSelector(parser, result, selector, type))4034    return mlir::failure();4035 4036  llvm::SmallVector<mlir::Attribute> attrs;4037  llvm::SmallVector<mlir::Block *> dests;4038  llvm::SmallVector<llvm::SmallVector<mlir::Value>> destArgs;4039  while (true) {4040    mlir::Attribute attr;4041    mlir::Block *dest;4042    llvm::SmallVector<mlir::Value> destArg;4043    mlir::NamedAttrList temp;4044    if (parser.parseAttribute(attr, "a", temp) || parser.parseComma() ||4045        parser.parseSuccessorAndUseList(dest, destArg))4046      return mlir::failure();4047    attrs.push_back(attr);4048    dests.push_back(dest);4049    destArgs.push_back(destArg);4050    if (mlir::succeeded(parser.parseOptionalRSquare()))4051      break;4052    if (parser.parseComma())4053      return mlir::failure();4054  }4055  auto &bld = parser.getBuilder();4056  result.addAttribute(fir::SelectTypeOp::getCasesAttr(),4057                      bld.getArrayAttr(attrs));4058  llvm::SmallVector<int32_t> argOffs;4059  int32_t offSize = 0;4060  const auto count = dests.size();4061  for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {4062    result.addSuccessors(dests[i]);4063    result.addOperands(destArgs[i]);4064    auto argSize = destArgs[i].size();4065    argOffs.push_back(argSize);4066    offSize += argSize;4067  }4068  result.addAttribute(fir::SelectTypeOp::getOperandSegmentSizeAttr(),4069                      bld.getDenseI32ArrayAttr({1, 0, offSize}));4070  result.addAttribute(getTargetOffsetAttr(), bld.getDenseI32ArrayAttr(argOffs));4071  return mlir::success();4072}4073 4074unsigned fir::SelectTypeOp::targetOffsetSize() {4075  return (*this)4076      ->getAttrOfType<mlir::DenseI32ArrayAttr>(getTargetOffsetAttr())4077      .size();4078}4079 4080void fir::SelectTypeOp::print(mlir::OpAsmPrinter &p) {4081  p << ' ';4082  p.printOperand(getSelector());4083  p << " : " << getSelector().getType() << " [";4084  auto cases =4085      getOperation()->getAttrOfType<mlir::ArrayAttr>(getCasesAttr()).getValue();4086  auto count = getNumConditions();4087  for (decltype(count) i = 0; i != count; ++i) {4088    if (i)4089      p << ", ";4090    p << cases[i] << ", ";4091    printSuccessorAtIndex(p, i);4092  }4093  p << ']';4094  p.printOptionalAttrDict(getOperation()->getAttrs(),4095                          {getCasesAttr(), getCompareOffsetAttr(),4096                           getTargetOffsetAttr(),4097                           fir::SelectTypeOp::getOperandSegmentSizeAttr()});4098}4099 4100llvm::LogicalResult fir::SelectTypeOp::verify() {4101  if (!mlir::isa<fir::BaseBoxType>(getSelector().getType()))4102    return emitOpError("must be a fir.class or fir.box type");4103  if (auto boxType = mlir::dyn_cast<fir::BoxType>(getSelector().getType()))4104    if (!mlir::isa<mlir::NoneType>(boxType.getEleTy()))4105      return emitOpError("selector must be polymorphic");4106  auto typeGuardAttr = getCases();4107  for (unsigned idx = 0; idx < typeGuardAttr.size(); ++idx)4108    if (mlir::isa<mlir::UnitAttr>(typeGuardAttr[idx]) &&4109        idx != typeGuardAttr.size() - 1)4110      return emitOpError("default must be the last attribute");4111  auto count = getNumDest();4112  if (count == 0)4113    return emitOpError("must have at least one successor");4114  if (getNumConditions() != count)4115    return emitOpError("number of conditions and successors don't match");4116  if (targetOffsetSize() != count)4117    return emitOpError("incorrect number of successor operand groups");4118  for (unsigned i = 0; i != count; ++i) {4119    if (!mlir::isa<fir::ExactTypeAttr, fir::SubclassAttr, mlir::UnitAttr>(4120            typeGuardAttr[i]))4121      return emitOpError("invalid type-case alternative");4122  }4123  return mlir::success();4124}4125 4126void fir::SelectTypeOp::build(mlir::OpBuilder &builder,4127                              mlir::OperationState &result,4128                              mlir::Value selector,4129                              llvm::ArrayRef<mlir::Attribute> typeOperands,4130                              llvm::ArrayRef<mlir::Block *> destinations,4131                              llvm::ArrayRef<mlir::ValueRange> destOperands,4132                              llvm::ArrayRef<mlir::NamedAttribute> attributes) {4133  result.addOperands(selector);4134  result.addAttribute(getCasesAttr(), builder.getArrayAttr(typeOperands));4135  const auto count = destinations.size();4136  for (mlir::Block *dest : destinations)4137    result.addSuccessors(dest);4138  const auto opCount = destOperands.size();4139  llvm::SmallVector<int32_t> argOffs;4140  int32_t sumArgs = 0;4141  for (std::remove_const_t<decltype(count)> i = 0; i != count; ++i) {4142    if (i < opCount) {4143      result.addOperands(destOperands[i]);4144      const auto argSz = destOperands[i].size();4145      argOffs.push_back(argSz);4146      sumArgs += argSz;4147    } else {4148      argOffs.push_back(0);4149    }4150  }4151  result.addAttribute(getOperandSegmentSizeAttr(),4152                      builder.getDenseI32ArrayAttr({1, 0, sumArgs}));4153  result.addAttribute(getTargetOffsetAttr(),4154                      builder.getDenseI32ArrayAttr(argOffs));4155  result.addAttributes(attributes);4156}4157 4158//===----------------------------------------------------------------------===//4159// ShapeOp4160//===----------------------------------------------------------------------===//4161 4162llvm::LogicalResult fir::ShapeOp::verify() {4163  auto size = getExtents().size();4164  auto shapeTy = mlir::dyn_cast<fir::ShapeType>(getType());4165  assert(shapeTy && "must be a shape type");4166  if (shapeTy.getRank() != size)4167    return emitOpError("shape type rank mismatch");4168  return mlir::success();4169}4170 4171void fir::ShapeOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,4172                         mlir::ValueRange extents) {4173  auto type = fir::ShapeType::get(builder.getContext(), extents.size());4174  build(builder, result, type, extents);4175}4176 4177//===----------------------------------------------------------------------===//4178// ShapeShiftOp4179//===----------------------------------------------------------------------===//4180 4181llvm::LogicalResult fir::ShapeShiftOp::verify() {4182  auto size = getPairs().size();4183  if (size < 2 || size > 16 * 2)4184    return emitOpError("incorrect number of args");4185  if (size % 2 != 0)4186    return emitOpError("requires a multiple of 2 args");4187  auto shapeTy = mlir::dyn_cast<fir::ShapeShiftType>(getType());4188  assert(shapeTy && "must be a shape shift type");4189  if (shapeTy.getRank() * 2 != size)4190    return emitOpError("shape type rank mismatch");4191  return mlir::success();4192}4193 4194//===----------------------------------------------------------------------===//4195// ShiftOp4196//===----------------------------------------------------------------------===//4197 4198llvm::LogicalResult fir::ShiftOp::verify() {4199  auto size = getOrigins().size();4200  auto shiftTy = mlir::dyn_cast<fir::ShiftType>(getType());4201  assert(shiftTy && "must be a shift type");4202  if (shiftTy.getRank() != size)4203    return emitOpError("shift type rank mismatch");4204  return mlir::success();4205}4206 4207//===----------------------------------------------------------------------===//4208// SliceOp4209//===----------------------------------------------------------------------===//4210 4211void fir::SliceOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,4212                         mlir::ValueRange trips, mlir::ValueRange path,4213                         mlir::ValueRange substr) {4214  const auto rank = trips.size() / 3;4215  auto sliceTy = fir::SliceType::get(builder.getContext(), rank);4216  build(builder, result, sliceTy, trips, path, substr);4217}4218 4219/// Return the output rank of a slice op. The output rank must be between 1 and4220/// the rank of the array being sliced (inclusive).4221unsigned fir::SliceOp::getOutputRank(mlir::ValueRange triples) {4222  unsigned rank = 0;4223  if (!triples.empty()) {4224    for (unsigned i = 1, end = triples.size(); i < end; i += 3) {4225      auto *op = triples[i].getDefiningOp();4226      if (!mlir::isa_and_nonnull<fir::UndefOp>(op))4227        ++rank;4228    }4229    assert(rank > 0);4230  }4231  return rank;4232}4233 4234llvm::LogicalResult fir::SliceOp::verify() {4235  auto size = getTriples().size();4236  if (size < 3 || size > 16 * 3)4237    return emitOpError("incorrect number of args for triple");4238  if (size % 3 != 0)4239    return emitOpError("requires a multiple of 3 args");4240  auto sliceTy = mlir::dyn_cast<fir::SliceType>(getType());4241  assert(sliceTy && "must be a slice type");4242  if (sliceTy.getRank() * 3 != size)4243    return emitOpError("slice type rank mismatch");4244  return mlir::success();4245}4246 4247//===----------------------------------------------------------------------===//4248// StoreOp4249//===----------------------------------------------------------------------===//4250 4251mlir::Type fir::StoreOp::elementType(mlir::Type refType) {4252  return fir::dyn_cast_ptrEleTy(refType);4253}4254 4255mlir::ParseResult fir::StoreOp::parse(mlir::OpAsmParser &parser,4256                                      mlir::OperationState &result) {4257  mlir::Type type;4258  mlir::OpAsmParser::UnresolvedOperand oper;4259  mlir::OpAsmParser::UnresolvedOperand store;4260  if (parser.parseOperand(oper) || parser.parseKeyword("to") ||4261      parser.parseOperand(store) ||4262      parser.parseOptionalAttrDict(result.attributes) ||4263      parser.parseColonType(type) ||4264      parser.resolveOperand(oper, fir::StoreOp::elementType(type),4265                            result.operands) ||4266      parser.resolveOperand(store, type, result.operands))4267    return mlir::failure();4268  return mlir::success();4269}4270 4271void fir::StoreOp::print(mlir::OpAsmPrinter &p) {4272  p << ' ';4273  p.printOperand(getValue());4274  p << " to ";4275  p.printOperand(getMemref());4276  p.printOptionalAttrDict(getOperation()->getAttrs(), {});4277  p << " : " << getMemref().getType();4278}4279 4280llvm::LogicalResult fir::StoreOp::verify() {4281  if (getValue().getType() != fir::dyn_cast_ptrEleTy(getMemref().getType()))4282    return emitOpError("store value type must match memory reference type");4283  return mlir::success();4284}4285 4286void fir::StoreOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,4287                         mlir::Value value, mlir::Value memref) {4288  build(builder, result, value, memref, {}, {}, {});4289}4290 4291void fir::StoreOp::getEffects(4292    llvm::SmallVectorImpl<4293        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>4294        &effects) {4295  effects.emplace_back(mlir::MemoryEffects::Write::get(), &getMemrefMutable(),4296                       mlir::SideEffects::DefaultResource::get());4297  addVolatileMemoryEffects({getMemref().getType()}, effects);4298}4299 4300//===----------------------------------------------------------------------===//4301// CopyOp4302//===----------------------------------------------------------------------===//4303 4304void fir::CopyOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,4305                        mlir::Value source, mlir::Value destination,4306                        bool noOverlap) {4307  mlir::UnitAttr noOverlapAttr =4308      noOverlap ? builder.getUnitAttr() : mlir::UnitAttr{};4309  build(builder, result, source, destination, noOverlapAttr);4310}4311 4312llvm::LogicalResult fir::CopyOp::verify() {4313  mlir::Type sourceType = fir::unwrapRefType(getSource().getType());4314  mlir::Type destinationType = fir::unwrapRefType(getDestination().getType());4315  if (sourceType != destinationType)4316    return emitOpError("source and destination must have the same value type");4317  return mlir::success();4318}4319 4320void fir::CopyOp::getEffects(4321    llvm::SmallVectorImpl<4322        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>4323        &effects) {4324  effects.emplace_back(mlir::MemoryEffects::Read::get(), &getSourceMutable(),4325                       mlir::SideEffects::DefaultResource::get());4326  effects.emplace_back(mlir::MemoryEffects::Write::get(),4327                       &getDestinationMutable(),4328                       mlir::SideEffects::DefaultResource::get());4329  addVolatileMemoryEffects({getDestination().getType(), getSource().getType()},4330                           effects);4331}4332 4333//===----------------------------------------------------------------------===//4334// StringLitOp4335//===----------------------------------------------------------------------===//4336 4337inline fir::CharacterType::KindTy stringLitOpGetKind(fir::StringLitOp op) {4338  auto eleTy = mlir::cast<fir::SequenceType>(op.getType()).getElementType();4339  return mlir::cast<fir::CharacterType>(eleTy).getFKind();4340}4341 4342bool fir::StringLitOp::isWideValue() { return stringLitOpGetKind(*this) != 1; }4343 4344static mlir::NamedAttribute4345mkNamedIntegerAttr(mlir::OpBuilder &builder, llvm::StringRef name, int64_t v) {4346  assert(v > 0);4347  return builder.getNamedAttr(4348      name, builder.getIntegerAttr(builder.getIntegerType(64), v));4349}4350 4351void fir::StringLitOp::build(mlir::OpBuilder &builder,4352                             mlir::OperationState &result,4353                             fir::CharacterType inType, llvm::StringRef val,4354                             std::optional<int64_t> len) {4355  auto valAttr = builder.getNamedAttr(value(), builder.getStringAttr(val));4356  int64_t length = len ? *len : inType.getLen();4357  auto lenAttr = mkNamedIntegerAttr(builder, size(), length);4358  result.addAttributes({valAttr, lenAttr});4359  result.addTypes(inType);4360}4361 4362template <typename C>4363static mlir::ArrayAttr convertToArrayAttr(mlir::OpBuilder &builder,4364                                          llvm::ArrayRef<C> xlist) {4365  llvm::SmallVector<mlir::Attribute> attrs;4366  auto ty = builder.getIntegerType(8 * sizeof(C));4367  for (auto ch : xlist)4368    attrs.push_back(builder.getIntegerAttr(ty, ch));4369  return builder.getArrayAttr(attrs);4370}4371 4372void fir::StringLitOp::build(mlir::OpBuilder &builder,4373                             mlir::OperationState &result,4374                             fir::CharacterType inType,4375                             llvm::ArrayRef<char> vlist,4376                             std::optional<std::int64_t> len) {4377  auto valAttr =4378      builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));4379  std::int64_t length = len ? *len : inType.getLen();4380  auto lenAttr = mkNamedIntegerAttr(builder, size(), length);4381  result.addAttributes({valAttr, lenAttr});4382  result.addTypes(inType);4383}4384 4385void fir::StringLitOp::build(mlir::OpBuilder &builder,4386                             mlir::OperationState &result,4387                             fir::CharacterType inType,4388                             llvm::ArrayRef<char16_t> vlist,4389                             std::optional<std::int64_t> len) {4390  auto valAttr =4391      builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));4392  std::int64_t length = len ? *len : inType.getLen();4393  auto lenAttr = mkNamedIntegerAttr(builder, size(), length);4394  result.addAttributes({valAttr, lenAttr});4395  result.addTypes(inType);4396}4397 4398void fir::StringLitOp::build(mlir::OpBuilder &builder,4399                             mlir::OperationState &result,4400                             fir::CharacterType inType,4401                             llvm::ArrayRef<char32_t> vlist,4402                             std::optional<std::int64_t> len) {4403  auto valAttr =4404      builder.getNamedAttr(xlist(), convertToArrayAttr(builder, vlist));4405  std::int64_t length = len ? *len : inType.getLen();4406  auto lenAttr = mkNamedIntegerAttr(builder, size(), length);4407  result.addAttributes({valAttr, lenAttr});4408  result.addTypes(inType);4409}4410 4411mlir::ParseResult fir::StringLitOp::parse(mlir::OpAsmParser &parser,4412                                          mlir::OperationState &result) {4413  auto &builder = parser.getBuilder();4414  mlir::Attribute val;4415  mlir::NamedAttrList attrs;4416  llvm::SMLoc trailingTypeLoc;4417  if (parser.parseAttribute(val, "fake", attrs))4418    return mlir::failure();4419  if (auto v = mlir::dyn_cast<mlir::StringAttr>(val))4420    result.attributes.push_back(4421        builder.getNamedAttr(fir::StringLitOp::value(), v));4422  else if (auto v = mlir::dyn_cast<mlir::DenseElementsAttr>(val))4423    result.attributes.push_back(4424        builder.getNamedAttr(fir::StringLitOp::xlist(), v));4425  else if (auto v = mlir::dyn_cast<mlir::ArrayAttr>(val))4426    result.attributes.push_back(4427        builder.getNamedAttr(fir::StringLitOp::xlist(), v));4428  else4429    return parser.emitError(parser.getCurrentLocation(),4430                            "found an invalid constant");4431  mlir::IntegerAttr sz;4432  mlir::Type type;4433  if (parser.parseLParen() ||4434      parser.parseAttribute(sz, fir::StringLitOp::size(), result.attributes) ||4435      parser.parseRParen() || parser.getCurrentLocation(&trailingTypeLoc) ||4436      parser.parseColonType(type))4437    return mlir::failure();4438  auto charTy = mlir::dyn_cast<fir::CharacterType>(type);4439  if (!charTy)4440    return parser.emitError(trailingTypeLoc, "must have character type");4441  type = fir::CharacterType::get(builder.getContext(), charTy.getFKind(),4442                                 sz.getInt());4443  if (!type || parser.addTypesToList(type, result.types))4444    return mlir::failure();4445  return mlir::success();4446}4447 4448void fir::StringLitOp::print(mlir::OpAsmPrinter &p) {4449  p << ' ' << getValue() << '(';4450  p << mlir::cast<mlir::IntegerAttr>(getSize()).getValue() << ") : ";4451  p.printType(getType());4452}4453 4454llvm::LogicalResult fir::StringLitOp::verify() {4455  if (mlir::cast<mlir::IntegerAttr>(getSize()).getValue().isNegative())4456    return emitOpError("size must be non-negative");4457  if (auto xl = getOperation()->getAttr(fir::StringLitOp::xlist())) {4458    if (auto xList = mlir::dyn_cast<mlir::ArrayAttr>(xl)) {4459      for (auto a : xList)4460        if (!mlir::isa<mlir::IntegerAttr>(a))4461          return emitOpError("values in initializer must be integers");4462    } else if (mlir::isa<mlir::DenseElementsAttr>(xl)) {4463      // do nothing4464    } else {4465      return emitOpError("has unexpected attribute");4466    }4467  }4468  return mlir::success();4469}4470 4471//===----------------------------------------------------------------------===//4472// UnboxProcOp4473//===----------------------------------------------------------------------===//4474 4475llvm::LogicalResult fir::UnboxProcOp::verify() {4476  if (auto eleTy = fir::dyn_cast_ptrEleTy(getRefTuple().getType()))4477    if (mlir::isa<mlir::TupleType>(eleTy))4478      return mlir::success();4479  return emitOpError("second output argument has bad type");4480}4481 4482//===----------------------------------------------------------------------===//4483// IfOp4484//===----------------------------------------------------------------------===//4485 4486void fir::IfOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,4487                      mlir::Value cond, bool withElseRegion) {4488  build(builder, result, {}, cond, withElseRegion);4489}4490 4491void fir::IfOp::build(mlir::OpBuilder &builder, mlir::OperationState &result,4492                      mlir::TypeRange resultTypes, mlir::Value cond,4493                      bool withElseRegion) {4494  result.addOperands(cond);4495  result.addTypes(resultTypes);4496 4497  mlir::Region *thenRegion = result.addRegion();4498  thenRegion->push_back(new mlir::Block());4499  if (resultTypes.empty())4500    IfOp::ensureTerminator(*thenRegion, builder, result.location);4501 4502  mlir::Region *elseRegion = result.addRegion();4503  if (withElseRegion) {4504    elseRegion->push_back(new mlir::Block());4505    if (resultTypes.empty())4506      IfOp::ensureTerminator(*elseRegion, builder, result.location);4507  }4508}4509 4510// These 3 functions copied from scf.if implementation.4511 4512/// Given the region at `index`, or the parent operation if `index` is None,4513/// return the successor regions. These are the regions that may be selected4514/// during the flow of control.4515void fir::IfOp::getSuccessorRegions(4516    mlir::RegionBranchPoint point,4517    llvm::SmallVectorImpl<mlir::RegionSuccessor> &regions) {4518  // The `then` and the `else` region branch back to the parent operation.4519  if (!point.isParent()) {4520    regions.push_back(mlir::RegionSuccessor(getOperation(), getResults()));4521    return;4522  }4523 4524  // Don't consider the else region if it is empty.4525  regions.push_back(mlir::RegionSuccessor(&getThenRegion()));4526 4527  // Don't consider the else region if it is empty.4528  mlir::Region *elseRegion = &this->getElseRegion();4529  if (elseRegion->empty())4530    regions.push_back(4531        mlir::RegionSuccessor(getOperation(), getOperation()->getResults()));4532  else4533    regions.push_back(mlir::RegionSuccessor(elseRegion));4534}4535 4536void fir::IfOp::getEntrySuccessorRegions(4537    llvm::ArrayRef<mlir::Attribute> operands,4538    llvm::SmallVectorImpl<mlir::RegionSuccessor> &regions) {4539  FoldAdaptor adaptor(operands);4540  auto boolAttr =4541      mlir::dyn_cast_or_null<mlir::BoolAttr>(adaptor.getCondition());4542  if (!boolAttr || boolAttr.getValue())4543    regions.emplace_back(&getThenRegion());4544 4545  // If the else region is empty, execution continues after the parent op.4546  if (!boolAttr || !boolAttr.getValue()) {4547    if (!getElseRegion().empty())4548      regions.emplace_back(&getElseRegion());4549    else4550      regions.emplace_back(getOperation(), getOperation()->getResults());4551  }4552}4553 4554void fir::IfOp::getRegionInvocationBounds(4555    llvm::ArrayRef<mlir::Attribute> operands,4556    llvm::SmallVectorImpl<mlir::InvocationBounds> &invocationBounds) {4557  if (auto cond = mlir::dyn_cast_or_null<mlir::BoolAttr>(operands[0])) {4558    // If the condition is known, then one region is known to be executed once4559    // and the other zero times.4560    invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);4561    invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);4562  } else {4563    // Non-constant condition. Each region may be executed 0 or 1 times.4564    invocationBounds.assign(2, {0, 1});4565  }4566}4567 4568mlir::ParseResult fir::IfOp::parse(mlir::OpAsmParser &parser,4569                                   mlir::OperationState &result) {4570  result.regions.reserve(2);4571  mlir::Region *thenRegion = result.addRegion();4572  mlir::Region *elseRegion = result.addRegion();4573 4574  auto &builder = parser.getBuilder();4575  mlir::OpAsmParser::UnresolvedOperand cond;4576  mlir::Type i1Type = builder.getIntegerType(1);4577  if (parser.parseOperand(cond) ||4578      parser.resolveOperand(cond, i1Type, result.operands))4579    return mlir::failure();4580 4581  if (mlir::succeeded(4582          parser.parseOptionalKeyword(getWeightsAttrAssemblyName()))) {4583    if (parser.parseLParen())4584      return mlir::failure();4585    mlir::DenseI32ArrayAttr weights;4586    if (parser.parseCustomAttributeWithFallback(weights, mlir::Type{}))4587      return mlir::failure();4588    if (weights)4589      result.addAttribute(getRegionWeightsAttrName(result.name), weights);4590    if (parser.parseRParen())4591      return mlir::failure();4592  }4593 4594  if (parser.parseOptionalArrowTypeList(result.types))4595    return mlir::failure();4596 4597  if (parser.parseRegion(*thenRegion, {}, {}))4598    return mlir::failure();4599  fir::IfOp::ensureTerminator(*thenRegion, parser.getBuilder(),4600                              result.location);4601 4602  if (mlir::succeeded(parser.parseOptionalKeyword("else"))) {4603    if (parser.parseRegion(*elseRegion, {}, {}))4604      return mlir::failure();4605    fir::IfOp::ensureTerminator(*elseRegion, parser.getBuilder(),4606                                result.location);4607  }4608 4609  // Parse the optional attribute list.4610  if (parser.parseOptionalAttrDict(result.attributes))4611    return mlir::failure();4612  return mlir::success();4613}4614 4615llvm::LogicalResult fir::IfOp::verify() {4616  if (getNumResults() != 0 && getElseRegion().empty())4617    return emitOpError("must have an else block if defining values");4618 4619  return mlir::success();4620}4621 4622void fir::IfOp::print(mlir::OpAsmPrinter &p) {4623  bool printBlockTerminators = false;4624  p << ' ' << getCondition();4625  if (auto weights = getRegionWeightsAttr()) {4626    p << ' ' << getWeightsAttrAssemblyName() << '(';4627    p.printStrippedAttrOrType(weights);4628    p << ')';4629  }4630  if (!getResults().empty()) {4631    p << " -> (" << getResultTypes() << ')';4632    printBlockTerminators = true;4633  }4634  p << ' ';4635  p.printRegion(getThenRegion(), /*printEntryBlockArgs=*/false,4636                printBlockTerminators);4637 4638  // Print the 'else' regions if it exists and has a block.4639  auto &otherReg = getElseRegion();4640  if (!otherReg.empty()) {4641    p << " else ";4642    p.printRegion(otherReg, /*printEntryBlockArgs=*/false,4643                  printBlockTerminators);4644  }4645  p.printOptionalAttrDict((*this)->getAttrs(),4646                          /*elideAttrs=*/{getRegionWeightsAttrName()});4647}4648 4649void fir::IfOp::resultToSourceOps(llvm::SmallVectorImpl<mlir::Value> &results,4650                                  unsigned resultNum) {4651  auto *term = getThenRegion().front().getTerminator();4652  if (resultNum < term->getNumOperands())4653    results.push_back(term->getOperand(resultNum));4654  term = getElseRegion().front().getTerminator();4655  if (resultNum < term->getNumOperands())4656    results.push_back(term->getOperand(resultNum));4657}4658 4659//===----------------------------------------------------------------------===//4660// BoxOffsetOp4661//===----------------------------------------------------------------------===//4662 4663llvm::LogicalResult fir::BoxOffsetOp::verify() {4664  auto boxType = mlir::dyn_cast_or_null<fir::BaseBoxType>(4665      fir::dyn_cast_ptrEleTy(getBoxRef().getType()));4666  mlir::Type boxCharType;4667  if (!boxType) {4668    boxCharType = mlir::dyn_cast_or_null<fir::BoxCharType>(4669        fir::dyn_cast_ptrEleTy(getBoxRef().getType()));4670    if (!boxCharType)4671      return emitOpError("box_ref operand must have !fir.ref<!fir.box<T>> or "4672                         "!fir.ref<!fir.boxchar<k>> type");4673    if (getField() == fir::BoxFieldAttr::derived_type)4674      return emitOpError("cannot address derived_type field of a fir.boxchar");4675  }4676  if (getField() != fir::BoxFieldAttr::base_addr &&4677      getField() != fir::BoxFieldAttr::derived_type)4678    return emitOpError("cannot address provided field");4679  if (getField() == fir::BoxFieldAttr::derived_type) {4680    if (!fir::boxHasAddendum(boxType))4681      return emitOpError("can only address derived_type field of derived type "4682                         "or unlimited polymorphic fir.box");4683  }4684  return mlir::success();4685}4686 4687void fir::BoxOffsetOp::build(mlir::OpBuilder &builder,4688                             mlir::OperationState &result, mlir::Value boxRef,4689                             fir::BoxFieldAttr field) {4690  mlir::Type valueType =4691      fir::unwrapPassByRefType(fir::unwrapRefType(boxRef.getType()));4692  mlir::Type resultType = valueType;4693  if (field == fir::BoxFieldAttr::base_addr)4694    resultType = fir::LLVMPointerType::get(fir::ReferenceType::get(valueType));4695  else if (field == fir::BoxFieldAttr::derived_type)4696    resultType = fir::LLVMPointerType::get(4697        fir::TypeDescType::get(fir::unwrapSequenceType(valueType)));4698  build(builder, result, {resultType}, boxRef, field);4699}4700 4701//===----------------------------------------------------------------------===//4702 4703mlir::ParseResult fir::isValidCaseAttr(mlir::Attribute attr) {4704  if (mlir::isa<mlir::UnitAttr, fir::ClosedIntervalAttr, fir::PointIntervalAttr,4705                fir::LowerBoundAttr, fir::UpperBoundAttr>(attr))4706    return mlir::success();4707  return mlir::failure();4708}4709 4710unsigned fir::getCaseArgumentOffset(llvm::ArrayRef<mlir::Attribute> cases,4711                                    unsigned dest) {4712  unsigned o = 0;4713  for (unsigned i = 0; i < dest; ++i) {4714    auto &attr = cases[i];4715    if (!mlir::dyn_cast_or_null<mlir::UnitAttr>(attr)) {4716      ++o;4717      if (mlir::dyn_cast_or_null<fir::ClosedIntervalAttr>(attr))4718        ++o;4719    }4720  }4721  return o;4722}4723 4724mlir::ParseResult4725fir::parseSelector(mlir::OpAsmParser &parser, mlir::OperationState &result,4726                   mlir::OpAsmParser::UnresolvedOperand &selector,4727                   mlir::Type &type) {4728  if (parser.parseOperand(selector) || parser.parseColonType(type) ||4729      parser.resolveOperand(selector, type, result.operands) ||4730      parser.parseLSquare())4731    return mlir::failure();4732  return mlir::success();4733}4734 4735mlir::func::FuncOp fir::createFuncOp(mlir::Location loc, mlir::ModuleOp module,4736                                     llvm::StringRef name,4737                                     mlir::FunctionType type,4738                                     llvm::ArrayRef<mlir::NamedAttribute> attrs,4739                                     const mlir::SymbolTable *symbolTable) {4740  if (symbolTable)4741    if (auto f = symbolTable->lookup<mlir::func::FuncOp>(name)) {4742#ifdef EXPENSIVE_CHECKS4743      assert(f == module.lookupSymbol<mlir::func::FuncOp>(name) &&4744             "symbolTable and module out of sync");4745#endif4746      return f;4747    }4748  if (auto f = module.lookupSymbol<mlir::func::FuncOp>(name))4749    return f;4750  mlir::OpBuilder modBuilder(module.getBodyRegion());4751  modBuilder.setInsertionPointToEnd(module.getBody());4752  auto result = mlir::func::FuncOp::create(modBuilder, loc, name, type, attrs);4753  result.setVisibility(mlir::SymbolTable::Visibility::Private);4754  return result;4755}4756 4757fir::GlobalOp fir::createGlobalOp(mlir::Location loc, mlir::ModuleOp module,4758                                  llvm::StringRef name, mlir::Type type,4759                                  llvm::ArrayRef<mlir::NamedAttribute> attrs,4760                                  const mlir::SymbolTable *symbolTable) {4761  if (symbolTable)4762    if (auto g = symbolTable->lookup<fir::GlobalOp>(name)) {4763#ifdef EXPENSIVE_CHECKS4764      assert(g == module.lookupSymbol<fir::GlobalOp>(name) &&4765             "symbolTable and module out of sync");4766#endif4767      return g;4768    }4769  if (auto g = module.lookupSymbol<fir::GlobalOp>(name))4770    return g;4771  mlir::OpBuilder modBuilder(module.getBodyRegion());4772  auto result = fir::GlobalOp::create(modBuilder, loc, name, type, attrs);4773  result.setVisibility(mlir::SymbolTable::Visibility::Private);4774  return result;4775}4776 4777bool fir::hasHostAssociationArgument(mlir::func::FuncOp func) {4778  if (auto allArgAttrs = func.getAllArgAttrs())4779    for (auto attr : allArgAttrs)4780      if (auto dict = mlir::dyn_cast_or_null<mlir::DictionaryAttr>(attr))4781        if (dict.get(fir::getHostAssocAttrName()))4782          return true;4783  return false;4784}4785 4786// Test if value's definition has the specified set of4787// attributeNames. The value's definition is one of the operations4788// that are able to carry the Fortran variable attributes, e.g.4789// fir.alloca or fir.allocmem. Function arguments may also represent4790// value definitions and carry relevant attributes.4791//4792// If it is not possible to reach the limited set of definition4793// entities from the given value, then the function will return4794// std::nullopt. Otherwise, the definition is known and the return4795// value is computed as:4796//   * if checkAny is true, then the function will return true4797//     iff any of the attributeNames attributes is set on the definition.4798//   * if checkAny is false, then the function will return true4799//     iff all of the attributeNames attributes are set on the definition.4800static std::optional<bool>4801valueCheckFirAttributes(mlir::Value value,4802                        llvm::ArrayRef<llvm::StringRef> attributeNames,4803                        bool checkAny) {4804  auto testAttributeSets = [&](llvm::ArrayRef<mlir::NamedAttribute> setAttrs,4805                               llvm::ArrayRef<llvm::StringRef> checkAttrs) {4806    if (checkAny) {4807      // Return true iff any of checkAttrs attributes is present4808      // in setAttrs set.4809      for (llvm::StringRef checkAttrName : checkAttrs)4810        if (llvm::any_of(setAttrs, [&](mlir::NamedAttribute setAttr) {4811              return setAttr.getName() == checkAttrName;4812            }))4813          return true;4814 4815      return false;4816    }4817 4818    // Return true iff all attributes from checkAttrs are present4819    // in setAttrs set.4820    for (mlir::StringRef checkAttrName : checkAttrs)4821      if (llvm::none_of(setAttrs, [&](mlir::NamedAttribute setAttr) {4822            return setAttr.getName() == checkAttrName;4823          }))4824        return false;4825 4826    return true;4827  };4828  // If this is a fir.box that was loaded, the fir attributes will be on the4829  // related fir.ref<fir.box> creation.4830  if (mlir::isa<fir::BoxType>(value.getType()))4831    if (auto definingOp = value.getDefiningOp())4832      if (auto loadOp = mlir::dyn_cast<fir::LoadOp>(definingOp))4833        value = loadOp.getMemref();4834  // If this is a function argument, look in the argument attributes.4835  if (auto blockArg = mlir::dyn_cast<mlir::BlockArgument>(value)) {4836    if (blockArg.getOwner() && blockArg.getOwner()->isEntryBlock())4837      if (auto funcOp = mlir::dyn_cast<mlir::func::FuncOp>(4838              blockArg.getOwner()->getParentOp()))4839        return testAttributeSets(4840            mlir::cast<mlir::FunctionOpInterface>(*funcOp).getArgAttrs(4841                blockArg.getArgNumber()),4842            attributeNames);4843 4844    // If it is not a function argument, the attributes are unknown.4845    return std::nullopt;4846  }4847 4848  if (auto definingOp = value.getDefiningOp()) {4849    // If this is an allocated value, look at the allocation attributes.4850    if (mlir::isa<fir::AllocMemOp>(definingOp) ||4851        mlir::isa<fir::AllocaOp>(definingOp))4852      return testAttributeSets(definingOp->getAttrs(), attributeNames);4853    // If this is an imported global, look at AddrOfOp and GlobalOp attributes.4854    // Both operations are looked at because use/host associated variable (the4855    // AddrOfOp) can have ASYNCHRONOUS/VOLATILE attributes even if the ultimate4856    // entity (the globalOp) does not have them.4857    if (auto addressOfOp = mlir::dyn_cast<fir::AddrOfOp>(definingOp)) {4858      if (testAttributeSets(addressOfOp->getAttrs(), attributeNames))4859        return true;4860      if (auto module = definingOp->getParentOfType<mlir::ModuleOp>())4861        if (auto globalOp =4862                module.lookupSymbol<fir::GlobalOp>(addressOfOp.getSymbol()))4863          return testAttributeSets(globalOp->getAttrs(), attributeNames);4864    }4865  }4866  // TODO: Construct associated entities attributes. Decide where the fir4867  // attributes must be placed/looked for in this case.4868  return std::nullopt;4869}4870 4871bool fir::valueMayHaveFirAttributes(4872    mlir::Value value, llvm::ArrayRef<llvm::StringRef> attributeNames) {4873  std::optional<bool> mayHaveAttr =4874      valueCheckFirAttributes(value, attributeNames, /*checkAny=*/true);4875  return mayHaveAttr.value_or(true);4876}4877 4878bool fir::valueHasFirAttribute(mlir::Value value,4879                               llvm::StringRef attributeName) {4880  std::optional<bool> mayHaveAttr =4881      valueCheckFirAttributes(value, {attributeName}, /*checkAny=*/false);4882  return mayHaveAttr.value_or(false);4883}4884 4885bool fir::anyFuncArgsHaveAttr(mlir::func::FuncOp func, llvm::StringRef attr) {4886  for (unsigned i = 0, end = func.getNumArguments(); i < end; ++i)4887    if (func.getArgAttr(i, attr))4888      return true;4889  return false;4890}4891 4892std::optional<std::int64_t> fir::getIntIfConstant(mlir::Value value) {4893  if (auto *definingOp = value.getDefiningOp()) {4894    if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))4895      if (auto intAttr = mlir::dyn_cast<mlir::IntegerAttr>(cst.getValue()))4896        return intAttr.getInt();4897    if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(definingOp))4898      if (auto attr = mlir::dyn_cast<mlir::IntegerAttr>(llConstOp.getValue()))4899        return attr.getValue().getSExtValue();4900  }4901  return {};4902}4903 4904bool fir::isDummyArgument(mlir::Value v) {4905  auto blockArg{mlir::dyn_cast<mlir::BlockArgument>(v)};4906  if (!blockArg) {4907    auto defOp = v.getDefiningOp();4908    if (defOp) {4909      if (auto declareOp = mlir::dyn_cast<fir::DeclareOp>(defOp))4910        if (declareOp.getDummyScope())4911          return true;4912    }4913    return false;4914  }4915 4916  auto *owner{blockArg.getOwner()};4917  return owner->isEntryBlock() &&4918         mlir::isa<mlir::FunctionOpInterface>(owner->getParentOp());4919}4920 4921mlir::Type fir::applyPathToType(mlir::Type eleTy, mlir::ValueRange path) {4922  for (auto i = path.begin(), end = path.end(); eleTy && i < end;) {4923    eleTy = llvm::TypeSwitch<mlir::Type, mlir::Type>(eleTy)4924                .Case<fir::RecordType>([&](fir::RecordType ty) {4925                  if (auto *op = (*i++).getDefiningOp()) {4926                    if (auto off = mlir::dyn_cast<fir::FieldIndexOp>(op))4927                      return ty.getType(off.getFieldName());4928                    if (auto off = mlir::dyn_cast<mlir::arith::ConstantOp>(op))4929                      return ty.getType(fir::toInt(off));4930                  }4931                  return mlir::Type{};4932                })4933                .Case<fir::SequenceType>([&](fir::SequenceType ty) {4934                  bool valid = true;4935                  const auto rank = ty.getDimension();4936                  for (std::remove_const_t<decltype(rank)> ii = 0;4937                       valid && ii < rank; ++ii)4938                    valid = i < end && fir::isa_integer((*i++).getType());4939                  return valid ? ty.getEleTy() : mlir::Type{};4940                })4941                .Case<mlir::TupleType>([&](mlir::TupleType ty) {4942                  if (auto *op = (*i++).getDefiningOp())4943                    if (auto off = mlir::dyn_cast<mlir::arith::ConstantOp>(op))4944                      return ty.getType(fir::toInt(off));4945                  return mlir::Type{};4946                })4947                .Case<mlir::ComplexType>([&](mlir::ComplexType ty) {4948                  if (fir::isa_integer((*i++).getType()))4949                    return ty.getElementType();4950                  return mlir::Type{};4951                })4952                .Default([&](const auto &) { return mlir::Type{}; });4953  }4954  return eleTy;4955}4956 4957bool fir::reboxPreservesContinuity(fir::ReboxOp rebox,4958                                   bool mayHaveNonDefaultLowerBounds,4959                                   bool checkWhole) {4960  // If slicing is not involved, then the rebox does not affect4961  // the continuity of the array.4962  auto sliceArg = rebox.getSlice();4963  if (!sliceArg)4964    return true;4965 4966  if (auto sliceOp =4967          mlir::dyn_cast_or_null<fir::SliceOp>(sliceArg.getDefiningOp()))4968    return isContiguousArraySlice(sliceOp, checkWhole, rebox.getBox(),4969                                  mayHaveNonDefaultLowerBounds);4970 4971  return false;4972}4973 4974std::optional<int64_t> fir::getAllocaByteSize(fir::AllocaOp alloca,4975                                              const mlir::DataLayout &dl,4976                                              const fir::KindMapping &kindMap) {4977  mlir::Type type = alloca.getInType();4978  // TODO: should use the constant operands when all info is not available in4979  // the type.4980  if (!alloca.isDynamic())4981    if (auto sizeAndAlignment =4982            getTypeSizeAndAlignment(alloca.getLoc(), type, dl, kindMap))4983      return sizeAndAlignment->first;4984  return std::nullopt;4985}4986 4987//===----------------------------------------------------------------------===//4988// DeclareOp4989//===----------------------------------------------------------------------===//4990 4991llvm::LogicalResult fir::DeclareOp::verify() {4992  auto fortranVar =4993      mlir::cast<fir::FortranVariableOpInterface>(this->getOperation());4994  return fortranVar.verifyDeclareLikeOpImpl(getMemref());4995}4996 4997//===----------------------------------------------------------------------===//4998// PackArrayOp4999//===----------------------------------------------------------------------===//5000 5001llvm::LogicalResult fir::PackArrayOp::verify() {5002  mlir::Type arrayType = getArray().getType();5003  if (!validTypeParams(arrayType, getTypeparams(), /*allowParamsForBox=*/true))5004    return emitOpError("invalid type parameters");5005 5006  if (getInnermost() && fir::getBoxRank(arrayType) == 1)5007    return emitOpError(5008        "'innermost' is invalid for 1D arrays, use 'whole' instead");5009  return mlir::success();5010}5011 5012void fir::PackArrayOp::getEffects(5013    llvm::SmallVectorImpl<5014        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>5015        &effects) {5016  if (getStack())5017    effects.emplace_back(5018        mlir::MemoryEffects::Allocate::get(),5019        mlir::SideEffects::AutomaticAllocationScopeResource::get());5020  else5021    effects.emplace_back(mlir::MemoryEffects::Allocate::get(),5022                         mlir::SideEffects::DefaultResource::get());5023 5024  if (!getNoCopy())5025    effects.emplace_back(mlir::MemoryEffects::Read::get(),5026                         mlir::SideEffects::DefaultResource::get());5027}5028 5029static mlir::ParseResult5030parsePackArrayConstraints(mlir::OpAsmParser &parser, mlir::IntegerAttr &maxSize,5031                          mlir::IntegerAttr &maxElementSize,5032                          mlir::IntegerAttr &minStride) {5033  mlir::OperationName opName = mlir::OperationName(5034      fir::PackArrayOp::getOperationName(), parser.getContext());5035  struct {5036    llvm::StringRef name;5037    mlir::IntegerAttr &ref;5038  } attributes[] = {5039      {fir::PackArrayOp::getMaxSizeAttrName(opName), maxSize},5040      {fir::PackArrayOp::getMaxElementSizeAttrName(opName), maxElementSize},5041      {fir::PackArrayOp::getMinStrideAttrName(opName), minStride}};5042 5043  mlir::NamedAttrList parsedAttrs;5044  if (succeeded(parser.parseOptionalAttrDict(parsedAttrs))) {5045    for (auto parsedAttr : parsedAttrs) {5046      for (auto opAttr : attributes) {5047        if (parsedAttr.getName() == opAttr.name)5048          opAttr.ref = mlir::cast<mlir::IntegerAttr>(parsedAttr.getValue());5049      }5050    }5051    return mlir::success();5052  }5053  return mlir::failure();5054}5055 5056static void printPackArrayConstraints(mlir::OpAsmPrinter &p,5057                                      fir::PackArrayOp &op,5058                                      const mlir::IntegerAttr &maxSize,5059                                      const mlir::IntegerAttr &maxElementSize,5060                                      const mlir::IntegerAttr &minStride) {5061  llvm::SmallVector<mlir::NamedAttribute> attributes;5062  if (maxSize)5063    attributes.emplace_back(op.getMaxSizeAttrName(), maxSize);5064  if (maxElementSize)5065    attributes.emplace_back(op.getMaxElementSizeAttrName(), maxElementSize);5066  if (minStride)5067    attributes.emplace_back(op.getMinStrideAttrName(), minStride);5068 5069  p.printOptionalAttrDict(attributes);5070}5071 5072//===----------------------------------------------------------------------===//5073// UnpackArrayOp5074//===----------------------------------------------------------------------===//5075 5076llvm::LogicalResult fir::UnpackArrayOp::verify() {5077  if (auto packOp = getTemp().getDefiningOp<fir::PackArrayOp>())5078    if (getStack() != packOp.getStack())5079      return emitOpError() << "the pack operation uses different memory for "5080                              "the temporary (stack vs heap): "5081                           << *packOp.getOperation() << "\n";5082  return mlir::success();5083}5084 5085void fir::UnpackArrayOp::getEffects(5086    llvm::SmallVectorImpl<5087        mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>5088        &effects) {5089  if (getStack())5090    effects.emplace_back(5091        mlir::MemoryEffects::Free::get(),5092        mlir::SideEffects::AutomaticAllocationScopeResource::get());5093  else5094    effects.emplace_back(mlir::MemoryEffects::Free::get(),5095                         mlir::SideEffects::DefaultResource::get());5096 5097  if (!getNoCopy())5098    effects.emplace_back(mlir::MemoryEffects::Write::get(),5099                         mlir::SideEffects::DefaultResource::get());5100}5101 5102//===----------------------------------------------------------------------===//5103// IsContiguousBoxOp5104//===----------------------------------------------------------------------===//5105 5106namespace {5107struct SimplifyIsContiguousBoxOp5108    : public mlir::OpRewritePattern<fir::IsContiguousBoxOp> {5109  using mlir::OpRewritePattern<fir::IsContiguousBoxOp>::OpRewritePattern;5110  mlir::LogicalResult5111  matchAndRewrite(fir::IsContiguousBoxOp op,5112                  mlir::PatternRewriter &rewriter) const override;5113};5114} // namespace5115 5116mlir::LogicalResult SimplifyIsContiguousBoxOp::matchAndRewrite(5117    fir::IsContiguousBoxOp op, mlir::PatternRewriter &rewriter) const {5118  auto boxType = mlir::cast<fir::BaseBoxType>(op.getBox().getType());5119  // Nothing to do for assumed-rank arrays and !fir.box<none>.5120  if (boxType.isAssumedRank() || fir::isBoxNone(boxType))5121    return mlir::failure();5122 5123  if (fir::getBoxRank(boxType) == 0) {5124    // Scalars are always contiguous.5125    mlir::Type i1Type = rewriter.getI1Type();5126    rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(5127        op, i1Type, rewriter.getIntegerAttr(i1Type, 1));5128    return mlir::success();5129  }5130 5131  // TODO: support more patterns, e.g. a result of fir.embox without5132  // the slice is contiguous. We can add fir::isSimplyContiguous(box)5133  // that walks def-use to figure it out.5134  return mlir::failure();5135}5136 5137void fir::IsContiguousBoxOp::getCanonicalizationPatterns(5138    mlir::RewritePatternSet &patterns, mlir::MLIRContext *context) {5139  patterns.add<SimplifyIsContiguousBoxOp>(context);5140}5141 5142//===----------------------------------------------------------------------===//5143// BoxTotalElementsOp5144//===----------------------------------------------------------------------===//5145 5146namespace {5147struct SimplifyBoxTotalElementsOp5148    : public mlir::OpRewritePattern<fir::BoxTotalElementsOp> {5149  using mlir::OpRewritePattern<fir::BoxTotalElementsOp>::OpRewritePattern;5150  mlir::LogicalResult5151  matchAndRewrite(fir::BoxTotalElementsOp op,5152                  mlir::PatternRewriter &rewriter) const override;5153};5154} // namespace5155 5156mlir::LogicalResult SimplifyBoxTotalElementsOp::matchAndRewrite(5157    fir::BoxTotalElementsOp op, mlir::PatternRewriter &rewriter) const {5158  auto boxType = mlir::cast<fir::BaseBoxType>(op.getBox().getType());5159  // Nothing to do for assumed-rank arrays and !fir.box<none>.5160  if (boxType.isAssumedRank() || fir::isBoxNone(boxType))5161    return mlir::failure();5162 5163  if (fir::getBoxRank(boxType) == 0) {5164    // Scalar: 1 element.5165    rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(5166        op, op.getType(), rewriter.getIntegerAttr(op.getType(), 1));5167    return mlir::success();5168  }5169 5170  // TODO: support more cases, e.g. !fir.box<!fir.array<10xi32>>.5171  return mlir::failure();5172}5173 5174void fir::BoxTotalElementsOp::getCanonicalizationPatterns(5175    mlir::RewritePatternSet &patterns, mlir::MLIRContext *context) {5176  patterns.add<SimplifyBoxTotalElementsOp>(context);5177}5178 5179//===----------------------------------------------------------------------===//5180// IsAssumedSizeExtentOp and AssumedSizeExtentOp5181//===----------------------------------------------------------------------===//5182 5183namespace {5184struct FoldIsAssumedSizeExtentOnCtor5185    : public mlir::OpRewritePattern<fir::IsAssumedSizeExtentOp> {5186  using mlir::OpRewritePattern<fir::IsAssumedSizeExtentOp>::OpRewritePattern;5187  mlir::LogicalResult5188  matchAndRewrite(fir::IsAssumedSizeExtentOp op,5189                  mlir::PatternRewriter &rewriter) const override {5190    if (llvm::isa_and_nonnull<fir::AssumedSizeExtentOp>(5191            op.getVal().getDefiningOp())) {5192      mlir::Type i1 = rewriter.getI1Type();5193      rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(5194          op, i1, rewriter.getIntegerAttr(i1, 1));5195      return mlir::success();5196    }5197    return mlir::failure();5198  }5199};5200} // namespace5201 5202void fir::IsAssumedSizeExtentOp::getCanonicalizationPatterns(5203    mlir::RewritePatternSet &patterns, mlir::MLIRContext *context) {5204  patterns.add<FoldIsAssumedSizeExtentOnCtor>(context);5205}5206 5207//===----------------------------------------------------------------------===//5208// LocalitySpecifierOp5209//===----------------------------------------------------------------------===//5210 5211// TODO This is a copy of omp::PrivateClauseOp::verifiyRegions(). Once we find a5212// solution to merge both ops into one this duplication will not be needed. See:5213// https://discourse.llvm.org/t/dialect-for-data-locality-sharing-specifiers-clauses-in-openmp-openacc-and-do-concurrent/86108.5214llvm::LogicalResult fir::LocalitySpecifierOp::verifyRegions() {5215  mlir::Type argType = getArgType();5216  auto verifyTerminator = [&](mlir::Operation *terminator,5217                              bool yieldsValue) -> llvm::LogicalResult {5218    if (!terminator->getBlock()->getSuccessors().empty())5219      return llvm::success();5220 5221    if (!llvm::isa<fir::YieldOp>(terminator))5222      return mlir::emitError(terminator->getLoc())5223             << "expected exit block terminator to be an `fir.yield` op.";5224 5225    YieldOp yieldOp = llvm::cast<YieldOp>(terminator);5226    mlir::TypeRange yieldedTypes = yieldOp.getResults().getTypes();5227 5228    if (!yieldsValue) {5229      if (yieldedTypes.empty())5230        return llvm::success();5231 5232      return mlir::emitError(terminator->getLoc())5233             << "Did not expect any values to be yielded.";5234    }5235 5236    if (yieldedTypes.size() == 1 && yieldedTypes.front() == argType)5237      return llvm::success();5238 5239    auto error = mlir::emitError(yieldOp.getLoc())5240                 << "Invalid yielded value. Expected type: " << argType5241                 << ", got: ";5242 5243    if (yieldedTypes.empty())5244      error << "None";5245    else5246      error << yieldedTypes;5247 5248    return error;5249  };5250 5251  auto verifyRegion = [&](mlir::Region &region, unsigned expectedNumArgs,5252                          llvm::StringRef regionName,5253                          bool yieldsValue) -> llvm::LogicalResult {5254    assert(!region.empty());5255 5256    if (region.getNumArguments() != expectedNumArgs)5257      return mlir::emitError(region.getLoc())5258             << "`" << regionName << "`: "5259             << "expected " << expectedNumArgs5260             << " region arguments, got: " << region.getNumArguments();5261 5262    for (mlir::Block &block : region) {5263      // MLIR will verify the absence of the terminator for us.5264      if (!block.mightHaveTerminator())5265        continue;5266 5267      if (failed(verifyTerminator(block.getTerminator(), yieldsValue)))5268        return llvm::failure();5269    }5270 5271    return llvm::success();5272  };5273 5274  // Ensure all of the region arguments have the same type5275  for (mlir::Region *region : getRegions())5276    for (mlir::Type ty : region->getArgumentTypes())5277      if (ty != argType)5278        return emitError() << "Region argument type mismatch: got " << ty5279                           << " expected " << argType << ".";5280 5281  mlir::Region &initRegion = getInitRegion();5282  if (!initRegion.empty() &&5283      failed(verifyRegion(getInitRegion(), /*expectedNumArgs=*/2, "init",5284                          /*yieldsValue=*/true)))5285    return llvm::failure();5286 5287  LocalitySpecifierType dsType = getLocalitySpecifierType();5288 5289  if (dsType == LocalitySpecifierType::Local && !getCopyRegion().empty())5290    return emitError("`local` specifiers do not require a `copy` region.");5291 5292  if (dsType == LocalitySpecifierType::LocalInit && getCopyRegion().empty())5293    return emitError(5294        "`local_init` specifiers require at least a `copy` region.");5295 5296  if (dsType == LocalitySpecifierType::LocalInit &&5297      failed(verifyRegion(getCopyRegion(), /*expectedNumArgs=*/2, "copy",5298                          /*yieldsValue=*/true)))5299    return llvm::failure();5300 5301  if (!getDeallocRegion().empty() &&5302      failed(verifyRegion(getDeallocRegion(), /*expectedNumArgs=*/1, "dealloc",5303                          /*yieldsValue=*/false)))5304    return llvm::failure();5305 5306  return llvm::success();5307}5308 5309// TODO This is a copy of omp::DeclareReductionOp::verifiyRegions(). Once we5310// find a solution to merge both ops into one this duplication will not be5311// needed.5312mlir::LogicalResult fir::DeclareReductionOp::verifyRegions() {5313  if (!getAllocRegion().empty()) {5314    for (YieldOp yieldOp : getAllocRegion().getOps<YieldOp>()) {5315      if (yieldOp.getResults().size() != 1 ||5316          yieldOp.getResults().getTypes()[0] != getType())5317        return emitOpError() << "expects alloc region to yield a value "5318                                "of the reduction type";5319    }5320  }5321 5322  if (getInitializerRegion().empty())5323    return emitOpError() << "expects non-empty initializer region";5324  mlir::Block &initializerEntryBlock = getInitializerRegion().front();5325 5326  if (initializerEntryBlock.getNumArguments() == 1) {5327    if (!getAllocRegion().empty())5328      return emitOpError() << "expects two arguments to the initializer region "5329                              "when an allocation region is used";5330  } else if (initializerEntryBlock.getNumArguments() == 2) {5331    if (getAllocRegion().empty())5332      return emitOpError() << "expects one argument to the initializer region "5333                              "when no allocation region is used";5334  } else {5335    return emitOpError()5336           << "expects one or two arguments to the initializer region";5337  }5338 5339  for (mlir::Value arg : initializerEntryBlock.getArguments())5340    if (arg.getType() != getType())5341      return emitOpError() << "expects initializer region argument to match "5342                              "the reduction type";5343 5344  for (YieldOp yieldOp : getInitializerRegion().getOps<YieldOp>()) {5345    if (yieldOp.getResults().size() != 1 ||5346        yieldOp.getResults().getTypes()[0] != getType())5347      return emitOpError() << "expects initializer region to yield a value "5348                              "of the reduction type";5349  }5350 5351  if (getReductionRegion().empty())5352    return emitOpError() << "expects non-empty reduction region";5353  mlir::Block &reductionEntryBlock = getReductionRegion().front();5354  if (reductionEntryBlock.getNumArguments() != 2 ||5355      reductionEntryBlock.getArgumentTypes()[0] !=5356          reductionEntryBlock.getArgumentTypes()[1] ||5357      reductionEntryBlock.getArgumentTypes()[0] != getType())5358    return emitOpError() << "expects reduction region with two arguments of "5359                            "the reduction type";5360  for (YieldOp yieldOp : getReductionRegion().getOps<YieldOp>()) {5361    if (yieldOp.getResults().size() != 1 ||5362        yieldOp.getResults().getTypes()[0] != getType())5363      return emitOpError() << "expects reduction region to yield a value "5364                              "of the reduction type";5365  }5366 5367  if (!getAtomicReductionRegion().empty()) {5368    mlir::Block &atomicReductionEntryBlock = getAtomicReductionRegion().front();5369    if (atomicReductionEntryBlock.getNumArguments() != 2 ||5370        atomicReductionEntryBlock.getArgumentTypes()[0] !=5371            atomicReductionEntryBlock.getArgumentTypes()[1])5372      return emitOpError() << "expects atomic reduction region with two "5373                              "arguments of the same type";5374  }5375 5376  if (getCleanupRegion().empty())5377    return mlir::success();5378  mlir::Block &cleanupEntryBlock = getCleanupRegion().front();5379  if (cleanupEntryBlock.getNumArguments() != 1 ||5380      cleanupEntryBlock.getArgument(0).getType() != getType())5381    return emitOpError() << "expects cleanup region with one argument "5382                            "of the reduction type";5383 5384  return mlir::success();5385}5386 5387//===----------------------------------------------------------------------===//5388// DoConcurrentOp5389//===----------------------------------------------------------------------===//5390 5391llvm::LogicalResult fir::DoConcurrentOp::verify() {5392  mlir::Block *body = getBody();5393 5394  if (body->empty())5395    return emitOpError("body cannot be empty");5396 5397  if (!body->mightHaveTerminator() ||5398      !mlir::isa<fir::DoConcurrentLoopOp>(body->getTerminator()))5399    return emitOpError("must be terminated by 'fir.do_concurrent.loop'");5400 5401  return mlir::success();5402}5403 5404//===----------------------------------------------------------------------===//5405// DoConcurrentLoopOp5406//===----------------------------------------------------------------------===//5407 5408static mlir::ParseResult parseSpecifierList(5409    mlir::OpAsmParser &parser, mlir::OperationState &result,5410    llvm::StringRef specifierKeyword, llvm::StringRef symsAttrName,5411    llvm::SmallVectorImpl<mlir::OpAsmParser::Argument> &regionArgs,5412    llvm::SmallVectorImpl<mlir::Type> &regionArgTypes,5413    int32_t &numSpecifierOperands, bool isReduce = false) {5414  auto &builder = parser.getBuilder();5415  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand> specifierOperands;5416 5417  if (failed(parser.parseOptionalKeyword(specifierKeyword)))5418    return mlir::success();5419 5420  std::size_t oldArgTypesSize = regionArgTypes.size();5421  if (failed(parser.parseLParen()))5422    return mlir::failure();5423 5424  llvm::SmallVector<bool> isByRefVec;5425  llvm::SmallVector<mlir::SymbolRefAttr> spceifierSymbolVec;5426  llvm::SmallVector<fir::ReduceAttr> attributes;5427 5428  if (failed(parser.parseCommaSeparatedList([&]() {5429        if (isReduce)5430          isByRefVec.push_back(5431              parser.parseOptionalKeyword("byref").succeeded());5432 5433        if (failed(parser.parseAttribute(spceifierSymbolVec.emplace_back())))5434          return mlir::failure();5435 5436        if (isReduce &&5437            failed(parser.parseAttribute(attributes.emplace_back())))5438          return mlir::failure();5439 5440        if (parser.parseOperand(specifierOperands.emplace_back()) ||5441            parser.parseArrow() ||5442            parser.parseArgument(regionArgs.emplace_back()))5443          return mlir::failure();5444 5445        return mlir::success();5446      })))5447    return mlir::failure();5448 5449  if (failed(parser.parseColon()))5450    return mlir::failure();5451 5452  if (failed(parser.parseCommaSeparatedList([&]() {5453        if (failed(parser.parseType(regionArgTypes.emplace_back())))5454          return mlir::failure();5455 5456        return mlir::success();5457      })))5458    return mlir::failure();5459 5460  if (regionArgs.size() != regionArgTypes.size())5461    return parser.emitError(parser.getNameLoc(), "mismatch in number of " +5462                                                     specifierKeyword.str() +5463                                                     " arg and types");5464 5465  if (failed(parser.parseRParen()))5466    return mlir::failure();5467 5468  for (auto operandType :5469       llvm::zip_equal(specifierOperands,5470                       llvm::drop_begin(regionArgTypes, oldArgTypesSize)))5471    if (parser.resolveOperand(std::get<0>(operandType),5472                              std::get<1>(operandType), result.operands))5473      return mlir::failure();5474 5475  if (isReduce)5476    result.addAttribute(5477        fir::DoConcurrentLoopOp::getReduceByrefAttrName(result.name),5478        isByRefVec.empty()5479            ? nullptr5480            : mlir::DenseBoolArrayAttr::get(builder.getContext(), isByRefVec));5481 5482  llvm::SmallVector<mlir::Attribute> symbolAttrs(spceifierSymbolVec.begin(),5483                                                 spceifierSymbolVec.end());5484  result.addAttribute(symsAttrName, builder.getArrayAttr(symbolAttrs));5485 5486  if (isReduce) {5487    llvm::SmallVector<mlir::Attribute> arrayAttr(attributes.begin(),5488                                                 attributes.end());5489    result.addAttribute(5490        fir::DoConcurrentLoopOp::getReduceAttrsAttrName(result.name),5491        builder.getArrayAttr(arrayAttr));5492  }5493 5494  numSpecifierOperands = specifierOperands.size();5495 5496  return mlir::success();5497}5498 5499mlir::ParseResult fir::DoConcurrentLoopOp::parse(mlir::OpAsmParser &parser,5500                                                 mlir::OperationState &result) {5501  auto &builder = parser.getBuilder();5502  // Parse an opening `(` followed by induction variables followed by `)`5503  llvm::SmallVector<mlir::OpAsmParser::Argument, 4> regionArgs;5504 5505  if (parser.parseArgumentList(regionArgs, mlir::OpAsmParser::Delimiter::Paren))5506    return mlir::failure();5507 5508  llvm::SmallVector<mlir::Type> argTypes(regionArgs.size(),5509                                         builder.getIndexType());5510 5511  // Parse loop bounds.5512  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> lower;5513  if (parser.parseEqual() ||5514      parser.parseOperandList(lower, regionArgs.size(),5515                              mlir::OpAsmParser::Delimiter::Paren) ||5516      parser.resolveOperands(lower, builder.getIndexType(), result.operands))5517    return mlir::failure();5518 5519  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> upper;5520  if (parser.parseKeyword("to") ||5521      parser.parseOperandList(upper, regionArgs.size(),5522                              mlir::OpAsmParser::Delimiter::Paren) ||5523      parser.resolveOperands(upper, builder.getIndexType(), result.operands))5524    return mlir::failure();5525 5526  // Parse step values.5527  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> steps;5528  if (parser.parseKeyword("step") ||5529      parser.parseOperandList(steps, regionArgs.size(),5530                              mlir::OpAsmParser::Delimiter::Paren) ||5531      parser.resolveOperands(steps, builder.getIndexType(), result.operands))5532    return mlir::failure();5533 5534  int32_t numLocalOperands = 0;5535  if (failed(parseSpecifierList(parser, result, "local",5536                                getLocalSymsAttrName(result.name), regionArgs,5537                                argTypes, numLocalOperands)))5538    return mlir::failure();5539 5540  int32_t numReduceOperands = 0;5541  if (failed(parseSpecifierList(5542          parser, result, "reduce", getReduceSymsAttrName(result.name),5543          regionArgs, argTypes, numReduceOperands, /*isReduce=*/true)))5544    return mlir::failure();5545 5546  // Set `operandSegmentSizes` attribute.5547  result.addAttribute(5548      DoConcurrentLoopOp::getOperandSegmentSizeAttr(),5549      builder.getDenseI32ArrayAttr({static_cast<int32_t>(lower.size()),5550                                    static_cast<int32_t>(upper.size()),5551                                    static_cast<int32_t>(steps.size()),5552                                    static_cast<int32_t>(numLocalOperands),5553                                    static_cast<int32_t>(numReduceOperands)}));5554 5555  // Now parse the body.5556  for (auto [arg, type] : llvm::zip_equal(regionArgs, argTypes))5557    arg.type = type;5558 5559  mlir::Region *body = result.addRegion();5560  if (parser.parseRegion(*body, regionArgs))5561    return mlir::failure();5562 5563  // Parse attributes.5564  if (parser.parseOptionalAttrDict(result.attributes))5565    return mlir::failure();5566 5567  return mlir::success();5568}5569 5570void fir::DoConcurrentLoopOp::print(mlir::OpAsmPrinter &p) {5571  p << " (" << getBody()->getArguments().slice(0, getNumInductionVars())5572    << ") = (" << getLowerBound() << ") to (" << getUpperBound() << ") step ("5573    << getStep() << ")";5574 5575  if (!getLocalVars().empty()) {5576    p << " local(";5577    llvm::interleaveComma(llvm::zip_equal(getLocalSymsAttr(), getLocalVars(),5578                                          getRegionLocalArgs()),5579                          p, [&](auto it) {5580                            p << std::get<0>(it) << " " << std::get<1>(it)5581                              << " -> " << std::get<2>(it);5582                          });5583    p << " : ";5584    llvm::interleaveComma(getLocalVars(), p,5585                          [&](auto it) { p << it.getType(); });5586    p << ")";5587  }5588 5589  if (!getReduceVars().empty()) {5590    p << " reduce(";5591    llvm::interleaveComma(5592        llvm::zip_equal(getReduceByrefAttr().asArrayRef(), getReduceSymsAttr(),5593                        getReduceAttrsAttr(), getReduceVars(),5594                        getRegionReduceArgs()),5595        p, [&](auto it) {5596          if (std::get<0>(it))5597            p << "byref ";5598 5599          p << std::get<1>(it) << " " << std::get<2>(it) << " "5600            << std::get<3>(it) << " -> " << std::get<4>(it);5601        });5602    p << " : ";5603    llvm::interleaveComma(getReduceVars(), p,5604                          [&](auto it) { p << it.getType(); });5605    p << ")";5606  }5607 5608  p << ' ';5609  p.printRegion(getRegion(), /*printEntryBlockArgs=*/false);5610  p.printOptionalAttrDict(5611      (*this)->getAttrs(),5612      /*elidedAttrs=*/{DoConcurrentLoopOp::getOperandSegmentSizeAttr(),5613                       DoConcurrentLoopOp::getLocalSymsAttrName(),5614                       DoConcurrentLoopOp::getReduceSymsAttrName(),5615                       DoConcurrentLoopOp::getReduceAttrsAttrName(),5616                       DoConcurrentLoopOp::getReduceByrefAttrName()});5617}5618 5619llvm::SmallVector<mlir::Region *> fir::DoConcurrentLoopOp::getLoopRegions() {5620  return {&getRegion()};5621}5622 5623llvm::LogicalResult fir::DoConcurrentLoopOp::verify() {5624  mlir::Operation::operand_range lbValues = getLowerBound();5625  mlir::Operation::operand_range ubValues = getUpperBound();5626  mlir::Operation::operand_range stepValues = getStep();5627  mlir::Operation::operand_range localVars = getLocalVars();5628  mlir::Operation::operand_range reduceVars = getReduceVars();5629 5630  if (lbValues.empty())5631    return emitOpError(5632        "needs at least one tuple element for lowerBound, upperBound and step");5633 5634  if (lbValues.size() != ubValues.size() ||5635      ubValues.size() != stepValues.size())5636    return emitOpError("different number of tuple elements for lowerBound, "5637                       "upperBound or step");5638 5639  // Check that the body defines the same number of block arguments as the5640  // number of tuple elements in step.5641  mlir::Block *body = getBody();5642  unsigned numIndVarArgs =5643      body->getNumArguments() - localVars.size() - reduceVars.size();5644 5645  if (numIndVarArgs != stepValues.size())5646    return emitOpError() << "expects the same number of induction variables: "5647                         << body->getNumArguments()5648                         << " as bound and step values: " << stepValues.size();5649  for (auto arg : body->getArguments().slice(0, numIndVarArgs))5650    if (!arg.getType().isIndex())5651      return emitOpError(5652          "expects arguments for the induction variable to be of index type");5653 5654  auto reduceAttrs = getReduceAttrsAttr();5655  if (getNumReduceOperands() != (reduceAttrs ? reduceAttrs.size() : 0))5656    return emitOpError(5657        "mismatch in number of reduction variables and reduction attributes");5658 5659  return mlir::success();5660}5661 5662std::optional<llvm::SmallVector<mlir::Value>>5663fir::DoConcurrentLoopOp::getLoopInductionVars() {5664  return llvm::SmallVector<mlir::Value>{5665      getBody()->getArguments().slice(0, getLowerBound().size())};5666}5667 5668//===----------------------------------------------------------------------===//5669// FIROpsDialect5670//===----------------------------------------------------------------------===//5671 5672void fir::FIROpsDialect::registerOpExternalInterfaces() {5673  // Attach default declare target interfaces to operations which can be marked5674  // as declare target.5675  fir::GlobalOp::attachInterface<5676      mlir::omp::DeclareTargetDefaultModel<fir::GlobalOp>>(*getContext());5677}5678 5679// Tablegen operators5680 5681#define GET_OP_CLASSES5682#include "flang/Optimizer/Dialect/FIROps.cpp.inc"5683