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> ®ions) {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> ®ions) {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 ®ion, 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> ®ionArgs,5412 llvm::SmallVectorImpl<mlir::Type> ®ionArgTypes,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